
1. 从一个真实翻车现场说起去年冬天我帮一个做智能客服的朋友排查线上问题。他们的系统接了一个大模型驱动的对话 Agent上线头两周效果惊艳第三周开始用户投诉量暴涨——同一个用户反复问同一个问题Agent 每次回答都不一样有时候甚至自相矛盾。更离谱的是一个用户聊到第 40 轮的时候Agent 突然把前面 30 轮里用户提到的订单号、收货地址、投诉诉求全忘了开始重新问“请问您遇到了什么问题”。朋友的第一反应是“模型不行”想换一个更大的模型。我让他先把每轮请求的 token 数打出来看看。结果一看就明白了他们的做法是把整个对话历史原封不动地拼进 prompt每轮都全量塞进去。到第 40 轮的时候单次请求的输入 token 已经逼近模型上下文窗口的上限系统为了不报错在代码里做了一层“截断保护”——从最早的对话开始丢。于是用户最早说的那些关键信息恰好就是被丢掉的那部分。这个案例几乎每天都在不同的团队里重演。Agent 的记忆管理是当前所有做智能体应用的团队绕不开的一道坎。很多人下意识觉得“上下文窗口越大越好那就全塞进去呗”但真正跑过生产环境的人都知道这条路走不通。这篇文章就把这件事掰开揉碎讲清楚为什么不能全塞、全塞会出什么问题、业内在用什么思路解决、以及你可以怎么落地。不管你是刚接触 Agent 开发的新手还是已经踩过几次坑的老手下面这些内容应该都能帮你少走一段弯路。我会尽量用生活化的类比把原理讲透同时给出可以直接参考的方案和参数。2. 为什么“全塞进上下文”是个陷阱2.1 上下文窗口不是免费的仓库先纠正一个特别常见的认知偏差。很多人把上下文窗口想象成一个“仓库”觉得只要没装满就能一直往里放。但上下文窗口更像是一张工作台而不是仓库。工作台的特点是你放的东西越多找东西越慢而且台面本身是有物理边界的。从技术层面看上下文窗口有三个硬约束。第一是长度上限这个最直观不同模型的窗口大小不一样从几万到几十万 token 不等但再大也有天花板。第二是注意力衰减这是很多人忽略的。Transformer 架构在处理长序列时对中间位置信息的关注度会明显下降业内常说的“lost in the middle”现象就是指这个——你把关键信息放在一长串内容的中间模型很可能视而不见。第三是成本输入 token 是要计费的全量拼接意味着每一轮都要为之前所有轮次的内容重复付费对话越长单轮成本越高而且是线性甚至超线性增长。我做过一个粗略的测算。假设一个 Agent 平均每轮对话产生 200 token 的内容用户和 Agent 各占一半。到第 50 轮时如果全量拼接单次请求的输入大约是 50 × 200 10000 token。看起来还好但如果你的系统提示词本身就有 2000 token再加上工具调用的返回结果、检索到的文档片段很容易就冲到 15000 以上。按主流模型的输入价格算单次请求成本可能是首轮的十几倍。一个日活几千的客服系统光这一项每月多出来的开销就相当可观。提示判断你的 Agent 是否已经掉进“全塞陷阱”最简单的信号是——单次请求的输入 token 数随着对话轮次线性增长且没有上限控制。2.2 全量拼接会引发四类典型故障我把实际项目中遇到过的故障归了归类基本逃不出下面四种。第一类是信息淹没。关键信息被大量无关内容稀释。比如用户在第 3 轮说了“我对花生过敏”后面 40 轮都在聊别的等到第 45 轮用户问“这个菜能吃吗”模型很可能因为中间隔了太多内容而忽略掉那条过敏信息。这不是模型笨是注意力机制的特性决定的。第二类是自相矛盾。长对话里用户的需求会演变早期说的和后期说的可能冲突。全量拼接时模型面对的是两套甚至多套互相矛盾的信息它不知道该以哪个为准输出就会飘忽不定。前面提到的客服案例就是典型。第三类是成本失控。这个不用多解释token 账单会教你做人。第四类是延迟恶化。输入越长推理耗时越长。用户等 2 秒能接受等 8 秒就开始骂人了。而且长输入的延迟增长不是线性的到后面会越来越慢。2.3 一个容易被忽视的隐性成本调试难度这一点很少有人提但我觉得特别重要。当你的 prompt 里塞了几十轮对话一旦输出有问题你根本无从下手排查。是系统提示词的问题是某轮用户输入的问题是工具返回结果的问题还是信息之间的相互干扰全量拼接把所有变量搅在一起调试就像在一锅乱炖里找一根特定的面条。我自己的习惯是任何 Agent 的 prompt 里同时存在的“信息块”不超过 5 个。超过这个数我就会考虑做记忆分层或者摘要压缩。这个数字不是拍脑袋来的是踩了很多次坑之后总结的经验值——5 个块以内我还能在脑子里追踪每个块的作用超过 5 个排查问题的时间会指数级上升。3. 记忆分层的核心思路3.1 把记忆当成一个分级存储系统解决思路其实不复杂核心就一句话不是所有记忆都值得放进上下文不同重要性的记忆应该放在不同的层级。这个思路借鉴的是计算机体系结构里的存储层次。CPU 有寄存器、L1/L2/L3 缓存、内存、硬盘越靠近 CPU 的越快越小越贵越远的越慢越大越便宜。Agent 的记忆管理完全可以照搬这套逻辑。我通常把 Agent 记忆分成四层。工作记忆是当前这一轮必须用到的信息直接进上下文比如用户当前的问题、最近一两轮的对话。短期记忆是本次会话内的重要信息比如用户在这次对话里表明的偏好、提到的关键实体需要的时候调进上下文。长期记忆是跨会话的持久信息比如用户的历史偏好、过往问题的解决记录存在外部存储里按需检索。归档记忆是几乎不用的冷数据只做合规留存平时不参与推理。这样分层之后上下文里永远只放“当前最相关”的那一小部分长度可控成本可控调试也清晰。3.2 什么信息该进哪一层一个判断框架分层说起来容易具体到某条信息该放哪层很多人会卡住。我总结了一个简单的判断框架问自己三个问题。第一个问题这条信息在当前这一轮对话里用得到吗用得到进工作记忆。用不到但本次会话可能还会用到进短期记忆。本次会话大概率用不到进长期记忆。第二个问题这条信息的时效性有多强比如“用户当前正在咨询的订单号”时效性极强用完就该从工作记忆里清掉。“用户偏好的沟通语气”时效性弱可以进长期记忆。第三个问题这条信息出错的代价有多大代价高的比如医疗过敏史、金融账户信息宁可多占一点上下文也要保证它在场甚至可以强制常驻。代价低的比如闲聊内容可以大胆压缩或丢弃。这三个问题问下来大部分信息的归属就清楚了。我建议你把这个框架做成一个简单的决策表贴在团队文档里新同学上手会快很多。3.3 分层带来的额外好处可观测性分层之后还有一个意外收获——可观测性大幅提升。因为每一层的信息来源和更新时机都是明确的你可以在每一层加日志、加监控。工作记忆的长度、短期记忆的命中率、长期记忆的检索准确率这些指标都能单独观测。我之前带的一个项目就是靠监控“长期记忆检索命中率”发现了一个隐蔽的 bug检索模块的向量模型和写入模块的向量模型版本不一致导致检索出来的内容总是差那么一点。这个问题在全量拼接的方案里几乎不可能被发现因为所有信息都在检索模块根本没被用上。4. 落地实操从摘要压缩到向量检索4.1 摘要压缩最容易被低估的基础手段如果只能选一种记忆管理手段我会选摘要压缩。它的性价比最高实现简单效果立竿见影。具体做法是当对话轮次超过某个阈值我一般设 10 轮就把最早的若干轮对话交给模型做一次摘要用摘要替换原始对话。摘要要保留什么我的经验是保留四类信息用户的核心诉求、已经确认的事实、达成的结论、未解决的问题。其他的寒暄、重复确认、中间过程都可以丢。摘要的 prompt 我一般这么写请将以下对话压缩成一段不超过 200 字的摘要必须保留 1. 用户提出的所有明确诉求 2. 对话中已经确认的客观事实如订单号、时间、金额 3. 已经给出的结论或方案 4. 尚未解决的问题 不要保留寒暄、重复确认和中间推理过程。这里有个细节要注意摘要本身也会累积误差。如果你对摘要再做摘要几轮之后信息会严重失真。我的做法是摘要只做一层原始对话保留在外部存储里摘要里如果提到某个关键事实同时存一个指向原始对话的引用 ID需要的时候可以回溯。注意摘要压缩的阈值不要设得太小。我见过有人设成 3 轮就压缩结果摘要比原文还长纯属浪费。10 到 15 轮是比较舒服的区间具体看你的单轮信息密度。4.2 向量检索让长期记忆真正可用短期记忆靠摘要长期记忆就得靠向量检索了。这块的坑最多我重点讲。基本流程是把历史信息切块、向量化、存入向量库需要的时候用当前问题去检索最相关的若干块拼进上下文。听起来简单但每一步都有讲究。切块策略是第一个关键点。切太大检索出来的内容冗余切太小语义不完整。我的经验值是 200 到 500 字一块块与块之间留 10% 到 20% 的重叠避免关键信息被切断。对于对话记录我倾向于按“话题”切而不是按“轮次”切同一个话题的几轮对话合成一块。检索数量是第二个关键点。检索太多上下文又被塞满了检索太少可能漏掉关键信息。我一般检索 top 5 到 top 8然后做一次重排序最终只把 top 3 放进上下文。重排序这一步很多人省掉但我觉得不能省向量相似度高不代表真的相关加一个交叉编码器做精排准确率能提升不少。检索时机是第三个关键点。不是每一轮都要检索。我的做法是先用一个轻量判断——当前问题是否涉及历史信息如果只是“好的”“谢谢”这种根本不用检索。这个判断可以用规则做也可以用一个小模型做成本很低。下面是一个检索模块的伪代码展示整体流程def retrieve_memory(query, user_id, top_k8, final_k3): # 1. 向量粗排 candidates vector_store.search( query_embeddingembed(query), filter{user_id: user_id}, top_ktop_k ) # 2. 交叉编码器精排 reranked rerank_model.sort(query, candidates) # 3. 取最终结果并做长度控制 selected reranked[:final_k] return truncate_by_token(selected, max_tokens1500)4.3 参数怎么定一份可参考的配置表参数不能拍脑袋我整理了一份自己常用的配置你可以作为起点再根据实际效果微调。参数建议值说明摘要触发轮次10-15 轮低于 10 轮压缩收益低高于 15 轮上下文压力大摘要长度上限200-300 字太长失去压缩意义太短信息丢失严重向量块大小200-500 字按话题切分块间重叠 10%-20%粗排数量5-8 条给精排留足候选精排后入上下文2-3 条控制上下文长度检索结果 token 上限1000-1500超过这个数就该考虑压缩工作记忆保留轮次最近 3-5 轮保证当前对话连贯性这张表里的数字不是金科玉律但都是我实际跑过、验证过能用的。你如果发现效果不好优先调“摘要触发轮次”和“检索结果 token 上限”这两个它们对整体表现影响最大。4.4 一个完整的记忆流转示例光讲模块可能还是抽象我串一个完整流程。用户第 1 次来咨询问了一个产品问题。系统把这次对话存入短期记忆。用户第 2 次来问的是另一个问题。系统检索长期记忆发现这个用户上次问过相关问题把上次的结论调出来拼进上下文。用户第 3 次来聊到第 12 轮触发摘要压缩前 10 轮压成一段摘要最近 2 轮保留原文。同时这次对话里用户表明的偏好比如“我喜欢简洁的回答”被写入长期记忆。整个过程中上下文里始终只有系统提示词 当前问题 最近几轮原文 相关摘要 检索到的长期记忆。长度稳定在一个可控范围内不会随对话轮次无限增长。5. 常见问题与排查技巧实录5.1 摘要丢信息怎么办这是最高频的问题。摘要压缩之后模型突然“忘了”之前确认过的事实。排查思路分三步。先看摘要 prompt 有没有明确要求保留事实类信息。很多人写的 prompt 太笼统只说“总结一下”模型自然会把事实当细节丢掉。然后看摘要长度是不是压得太狠200 字塞不下关键事实那就放宽到 300 字。最后看是不是摘要做了多层多层摘要必然失真改成单层加引用回溯。我自己的兜底方案是关键事实不进摘要单独存一个结构化字段。比如订单号、金额、时间这些用 JSON 存需要的时候直接拼进上下文不依赖摘要。摘要只负责承载那些不好结构化的语义信息。5.2 检索总是召回不相关内容向量检索召回不准八成是切块或 embedding 的问题。先检查切块是不是把语义切碎了一个完整的诉求被切成两半检索出来自然不相关。再检查 embedding 模型是不是适合你的领域通用模型在垂直领域往往表现一般有条件的话用领域数据微调一下。还有一个容易被忽略的点查询改写。用户当前的问题可能很短比如“那这个呢”直接拿去做向量检索召回质量肯定差。我的做法是先用模型把当前问题结合最近几轮对话改写成一句完整的查询再去检索。这一步能显著提升召回准确率。5.3 上下文长度还是压不下来如果做了摘要和检索上下文还是长那要检查是不是有“隐形大户”。常见的隐形大户有三个系统提示词太长、工具返回结果没做裁剪、检索结果没做 token 控制。系统提示词我一般控制在 1000 token 以内超过就拆分把不常用的指令做成按需加载。工具返回结果一定要裁剪比如搜索工具返回 10 条结果只保留前 3 条的关键字段。检索结果的 token 控制前面提过用truncate_by_token这类函数硬性截断。5.4 一份速查表现象可能原因排查方向模型忘记早期确认的事实摘要丢信息 / 检索没召回检查摘要 prompt、关键事实结构化回答自相矛盾新旧信息同时在场检查是否有冲突信息未清理检索结果不相关切块碎 / embedding 不匹配调整切块、查询改写、换模型上下文压不下来隐形大户 / 参数没调检查系统提示词、工具返回、检索上限响应越来越慢输入 token 增长监控单轮输入长度加硬性上限提示这张表建议直接贴到你的监控看板上出问题时按行排查比从头分析快得多。5.5 几个我踩过的坑第一个坑摘要和原文同时在场。早期我做过一个“保险”设计摘要进上下文的同时原文也保留一份想着万一摘要漏了还能兜底。结果上下文直接翻倍而且模型面对摘要和原文两套表述反而更容易混乱。后来改成摘要进上下文、原文只存外部需要时按引用 ID 回溯问题就没了。第二个坑检索没有做用户隔离。多用户场景下如果检索时不加 user_id 过滤A 用户的记忆可能被检索到 B 用户的对话里。这个 bug 很隐蔽因为大部分时候检索结果看起来“也说得通”但偶尔会冒出莫名其妙的信息。加上过滤条件就好了。第三个坑长期记忆只写不清理。用户三个月前的一个临时偏好一直留在长期记忆里导致 Agent 的行为越来越“固执”。长期记忆一定要有 TTL过期时间或者定期清理机制我一般设 90 天重要的偏好可以手动标记为永久。6. 我个人的一些实践体会做 Agent 记忆管理这几年最大的体会是不要追求“记住一切”要追求“在对的时候想起对的事”。人类的大脑也不是把所有经历都存着而是记住关键的、遗忘次要的需要的时候通过线索回忆起来。Agent 的记忆系统应该模仿这个机制而不是模仿硬盘。另一个体会是记忆管理没有银弹只有权衡。摘要压缩会丢信息向量检索会召回不准分层会增加复杂度。你要做的是根据自己业务的特点选择能接受的权衡。客服场景对准确性要求高那就多留一点上下文闲聊场景对成本敏感那就压得狠一点。最后一个建议从最简单的方案开始。不要一上来就搞四层记忆加向量库加重排序先用摘要压缩跑起来观察效果再逐步加复杂度。我见过太多团队记忆系统设计得无比精巧结果因为调试困难、维护成本高最后又退回全量拼接。简单能跑通的方案永远比复杂但跑不起来的方案有价值。如果你现在正在为 Agent 的记忆问题头疼不妨先做一件事把单轮请求的输入 token 数打出来看看它是不是在随对话轮次增长。如果是那你就已经找到了优化的起点。