上下文工程与记忆工程:Agent认知升级的工程实践指南 做Agent开发的朋友应该都有过这种体会同一个模型单轮问答表现惊艳一旦放到真实业务的多轮流程里就变得“失去记忆”指令执行到一半开始跑偏甚至把前面说过的话忘得一干二净。很多人第一反应是“prompt写得不够好”于是反复改提示词效果依然不稳定。直到你开始认真对待上下文工程和记忆工程这两个概念才会意识到问题不在提示词本身而在Agent的认知结构。这篇内容是我把一段时间里做大模型Agent开发踩过的坑、总结出来的方法重新梳理成的一份“认知升级指南”。它不是什么高深理论更偏“工程实践”适合正在做Agent开发、或准备把大模型接入真实业务的人。核心就一句话别再把上下文当垃圾桶而是把它当成一个需要设计、存储、检索、更新的记忆系统来对待。1. 从“上下文”到“记忆工程”先搞懂认知链路1.1 上下文窗口不是用来“装”的是用来“算”的很多初学者对“上下文窗口”有误解觉得它是给模型“装聊天记录”的容器只要不超token上限塞进去就行。这在单轮问答里勉强能用一旦涉及Agent问题立刻暴露模型不仅要“看”上下文还要在每一步决策时对整段上下文做注意力计算。你塞进去的东西越多模型真正关注关键信息的难度就越大。我习惯用一个比喻上下文窗口是一块白板模型每次下笔前都要快速扫一眼白板上所有内容。如果白板上写满了历史对话、无关日志、重复说明那它找到重点的速度会越来越慢最终写出来的东西也会越来越“散”。这不是模型能力不够而是你的信息编排方式让它不堪重负。所以上下文管理的本质不是“控制长度”而是“控制信息密度”。你要主动决定每一轮对话、每一个工具调用往白板上写什么、擦掉什么。一个健康的上下文应该始终只包含当前决策“必需”的信息而不是“所有发生过”的信息。1.2 记忆工程的核心层次短期工作记忆、长期存储、检索与遗忘一旦你接受了“上下文是白板”这个前提自然就会思考那些被擦掉的信息去哪了人类大脑会把重要的事情转存到长期记忆需要时再调取。Agent也一样这就是记忆工程要做的事。我习惯把Agent的记忆分为三个层次第一层是工作记忆直接存在于当前上下文中对应最近几轮对话和当前任务状态。它的特点是快、准、容易获取但容量有限而且对话一结束就消失。第二层是长期存储放在外部数据库或缓存里比如向量数据库、键值存储、文件系统。它负责保存跨会话的用户偏好、任务历史、事实性知识。问题是从“存储”到“工作记忆”需要一次“检索”检索质量决定了记忆能不能被用上。第三层是遗忘机制。遗忘不是bug是特性。长期存储里如果塞满了过期、冲突、低价值的记忆检索时就会把噪声捞上来反而污染上下文。所以记忆工程必须包含主动的过滤、更新、过期清理。这三个层次缺一不可。很多人做记忆只做“存储”和“检索”不做“遗忘”结果就是记忆库越来越脏效果越来越差。真正的Agent认知升级是把这三层连城一条完整的链路写入、存储、检索、更新、遗忘。1.3 Agent“认知升级”到底升什么如果只说“认知升级”这个抽象概念很容易变成鸡汤。落在地上我认为它体现在四个可观测的变化上第一连续性Agent能在多轮、跨会话的任务中保持一致的行为和目标不会因为中间换了一轮对话就丢失主线。第二个性化同样的请求对不同用户返回不同结果因为Agent能记住用户偏好和习惯。第三决策质量Agent在工具调用、信息筛选时能基于历史经验而不是单轮直觉做判断。第四可解释性当Agent做出一个奇怪决定时你能查看到底是哪条历史记忆影响了它而不是黑盒乱猜。我见过一个典型的“认知未升级”的例子某客服Agent用户上周刚投诉过物流问题这周再来询问订单状态Agent完全不记得用户情绪敏感回复依然机械官方用户二次引爆。这不是模型情商不够而是Agent根本没有记忆工程它把每次对话都当成陌生人。认知升级之后Agent会先检索用户最近的交互记录识别出“敏感用户”标签再调整回复策略整个体验完全不同。2. 上下文工程的实操细节把token花在刀刃上2.1 上下文压缩与结构化组织让每一轮都轻装上阵上下文工程不是简单地删聊天记录而是“有损压缩”加“结构化保存”。我实际用的做法是每一轮Agent执行完一个子步骤后不把完整的中间产出塞回上下文而是生成一条精简的“状态摘要”。具体操作分三步。第一步设定上下文预算比如总token的三分之一留给历史摘要三分之二留给当前任务的系统指令、工具结果和最新用户输入。第二步对历史对话做分层摘要最近3轮保留原文3轮之前采用“要点抽取”把用户意图、已确认的事实、已完成的动作转化为结构化字段。第三步把摘要写回上下文时用清晰的Markdown块或JSON结构组织让模型能够快速定位。举个例子一个项目回顾Agent处理“帮我总结本周开发进度”时上下文里只需要放用户身份标签、本周提交的关键commit列表、之前的项目偏好比如喜欢简洁报告、包含风险提示而不是整个月的聊天记录。这样做的收益很明显模型在长会话中的指令跟随能力、工具调用准确率都会有大幅回升。我实测过同样一个任务把上下文从塞满8000 token压缩到3000 token后最终输出质量和稳定性反而明显提升。2.2 基于工具调用保持上下文精简很多人做Agent时喜欢把所有需要用到的数据一次性预置到上下文里比如把用户的所有订单记录、商品详情、日志文本全塞进去让模型自己“看着办”。这样做不仅浪费token还会让模型在不需要这些信息的时候也受到干扰。更好的做法是把信息获取交给工具让模型按需调用。模型上下文里只需要保留“工具描述”和“工具返回的关键结果”。举个例子Agent要查询用户订单状态不要让模型在记忆里翻找所有订单而是给它一个query_order(user_id, date_range)工具。模型只需要在需要时调用这个工具然后只把返回结果中的状态、物流单号等关键字段放进上下文。这个思路的关键是上下文里放的是“获取信息的方法”不是“信息本身”。你自己可以做一个简单的估算假设一份数据全量是5000 token但前端只需要其中3个字段那通过工具调用你就省了4900 token的上下文空间模型注意力也能集中在真正需要判断的东西上。当模型需要连续多个数据时工具也可以返回“紧凑格式”比如只返回字段名和值不要返回无关说明。你甚至可以设计专门的summarize_tool_result()函数把工具输出做截断、提炼后再进上下文。2.3 上下文管理的常见坑满窗截断、信息稀释、重复注入上下文工程里最常见的坑有三个我每个都踩过。第一个坑是满窗截断。很多人简单粗暴地实现“如果超过context window就丢弃最早的对话”。这会破坏任务连贯性。比如用户在第3轮说“记住用极简风格”第10轮超过窗口后被截断了后面模型就开始自由发挥。正确做法是在截断前把早期对话做摘要压缩确保重要指令、确认过的事实被保留。第二个坑是信息稀释。上下文里塞了很多不相关的日志、报错堆栈、临时变量模型抓不住重点。表现是用户明明问了A模型却在回答B。排查方法很简单把上下文中每个信息块问一句“当前决策真的需要它吗”不需要的就去掉。第三个坑是重复注入。同一个偏好或事实在系统提示词、历史摘要、用户原话里反复出现模型会认为它很重要但同时也占用了大量注意力。解决办法是去重把稳定的偏好放进系统提示词把动态状态放进历史摘要不要两边重复。可以定期用脚本检查重复片段做一个去重流程。3. 记忆工程的系统设计与落地3.1 记忆分层会话级、用户级、任务级记忆工程的第一原则是“分层存储按需取用”。不分层的记忆库很容易变成一锅粥。我常用的分层方式如下记忆类型生命周期典型内容存储方式使用时机会话级记忆单次会话存活当前意图、最近N轮对话、临时决策内存缓存每轮对话直接放在上下文中用户级记忆跨会话长期保存用户偏好、历史偏好、身份信息、常用说法键值库或向量库会话开始时加载按需检索任务级记忆与某个任务绑定任务结束可清理项目上下文、目标状态、已完成步骤、关键产出数据库表或文档索引任务执行过程中检索、更新分层的好处是你能为不同层设置独立的写入、检索、过期策略。用户级记忆要稳重宁缺毋滥会话级记忆要灵敏快速读写任务级记忆要有清晰的生命周期边界任务结束就归档或删除。实际落地时可以用一个MemoryManager统一管理这三个层级。收到用户输入后先检查用户级记忆里有没有相关偏好会话过程中把关键事实写入会话缓存任务到达里程碑时把任务状态固化到任务库。这样各部分职责清晰排查问题时也容易定位。3.2 记忆存储与检索向量化、关键词、混合召回提到记忆检索很多人的第一反应是“用向量数据库做语义搜索”。向量检索确实重要但只靠向量会漏掉很多精确信息。比如用户偏好里的“不要打电话用短信通知”如果对话中说的是“上次打电话烦死了以后发消息就行”向量检索可能判断不够精准。更好的方案是混合检索把关键词、正则、规则匹配和向量语义检索结合起来。具体做法第一把每条记忆打上类型标签比如preference,fact,task_state,emotion_tag检索时先按标签过滤。第二对短文本或专有名词用关键词索引例如用倒排索引存储用户提到过的产品名、地名、人名。第三对描述性内容用向量嵌入做语义召回。第四把两个召回结果合并做一次重排去掉与当前用户意图关联度低的记忆。我自己的经验是一个轻量级的记忆检索系统可以先用SQLite存结构化字段再用一个本地向量库存嵌入最后用几行代码合并结果。不需要一开始就上分布式系统。关键是让每条记忆带一个“新鲜度”分数比如最近7天命中过就加分否则降权这样检索结果会自然偏向近期互动。3.3 记忆写入与更新策略什么时候写、什么时候改、什么时候忘记忆工程最难的不是存储和检索而是写入策略。什么时候把一段对话“升级”为长期记忆如果每条消息都写入记忆库会迅速充满噪声如果都不写那Agent又变回失忆状态。我的经验是采用“事件驱动 事后抽取”结合。事件驱动指在某些关键节点主动触发写入比如用户明确表达偏好、任务完成、用户情绪出现明显变化。事后抽取指在会话结束时让模型生成一段结构化记忆候选然后用规则或另一层校验决定是否入库。举一个入库存活的例子。用户说“以后周报用表格形式发我”。这是一个明确的偏好陈述应该在当轮对话结束后抽取成{type: preference, key: report_format, value: table, source_timestamp: ...}写入用户级记忆。而用户随口说的一句“今天天气真热”没有长期价值就应该只留在会话级缓存中随会话结束清空。更新策略上也容易踩坑。当新记忆与旧记忆冲突时不能简单覆盖。比如用户先说“我喜欢详细报告”后说“这周开始只要摘要”——这是临时变化还是永久变化我一般做法是如果是“这周/这次/暂时”等时间限定词就写入任务级或会话级记忆如果没有时间限定则更新用户级记忆并保留旧值的历史版本方便追溯。遗忘机制同样重要。定期批量扫描记忆库对超过保质期的记忆降权或删除。比如用户三个月没提到的临时偏好、已完成项目的过程记录都应进入归档而非持续参与检索。遗忘策略可以简单用“最近访问时间 标签类型”判断没必要一开始就做复杂模型。4. Agent开发中的认知架构从RAG到记忆编排4.1 工作流示例多阶段Agent如何串联记忆与其说理论不如看一个具体的编排案例。假设要做一个“项目周报助手”Agent它需要在一次会话里完成收集本周完成事项、对比上周计划、生成周报草稿、按用户偏好调整格式。如果每个步骤都从零开始那Agent就不可能知道用户偏好和上周上下文。我设计的执行流程如下第一阶段会话初始化。Agent从用户级记忆加载该用户的两个偏好字段报告风格偏好表格要点、周报中包含风险提示。同时从任务级记忆找到“上周计划”的状态作为对比基线。第二阶段任务执行。调用工具获取本周commit记录、任务清单把工具返回结果做压缩后放入工作记忆。此时上下文包含用户偏好、上周计划摘要、本周变更列表。模型开始生成草稿。第三阶段记忆更新。生成结束后模型不直接把草稿放回记忆而是抽取一条任务状态记忆“已完成本周周报初稿用户尚未审阅”并记录生成的报告ID。同时把用户此次的修改意见如果有提取为新的偏好候选。这样整个流程里上下文每一阶段都是精简的长期记忆始终可靠。关键路径是从长期存储拉数据 - 加入工作记忆 - 执行 - 写回长期存储 - 清理工作记忆。4.2 记忆工程与RAG的关系与边界很多朋友会把记忆工程直接等同于RAG这是现在最普遍的误区。RAG检索增强生成解决的是“让模型获取外部知识”比如从文档库、知识库里查资料。记忆工程解决的是“让模型记住用户和任务的历史状态”。两者有重叠但目标不同。我习惯用一个边界判断如果一段信息不依赖具体用户和具体任务属于可公开查询的知识那就进RAG如果一段信息只对某个用户、某个任务有意义比如用户偏好、项目进度、历史决策原因那就进记忆系统。举个例子一个法律咨询Agent法律条文、司法解释是RAG的数据源某个用户之前的咨询历史、他的偏好选择、上个未完成的事项则是记忆系统的事。如果把这些都塞进同一个向量库检索时知识性内容和个性化内容会互相干扰效果会很糟糕。正确做法是让RAG和记忆系统并行存在Agent先判断当前需求是“查知识”还是“查历史”然后分别检索最后在工作记忆中合并。这样每个系统的数据都足够纯净检索准确率也会更高。4.3 扩展场景多轮对话、个性化、工具使用记忆工程对三个场景的影响最大值得展开说说。先说多轮对话。没有记忆的多轮对话只是“消息列表连续”有了记忆系统之后模型可以真正跨轮引用前置事实。比如用户在第1轮告诉Agent“我预算上限是5000”中间经过几轮讨论物料和方案第8轮Agent报价6000时应该能主动识别超标并询问调整。这需要工作记忆里持续保存“预算上限”这个约束即使不在最近的原始消息里。再说个性化。个性化不是简单地在prompt里写“你是一个贴心的助手”而是要有实际记忆数据支撑。比如用户习惯用缩写、喜欢简洁回复、讨厌表情包这些都可以作为记忆条目在会话初始化时注入。效果是可测量的用户满意度、任务完成率都会有变化。最后说工具使用。Agent在执行工具调用时常常需要知道“此前已经调用过哪些工具、结果如何”。比如一个API调用型Agent第一轮调用了天气查询工具第二轮用户问“和昨天的天气比怎么样”Agent需要从工作记忆中提取第一轮的工具返回结果而不是让用户再重复一遍。这种情况下工具调用历史的摘要几乎必须进上下文。5. 踩坑实录与排查速查表5.1 我踩过的三个坑第一个坑把全部历史对话一股脑塞进上下文然后发现越到后面回答质量越差。后来我用token开销统计看了一眼发现近80%的token都被历史对话占据当前指令只占很小比例。改用摘要压缩后问题立刻缓解。第二个坑记忆写入太积极。早期我给每个会话都自动抽取记忆并写入长期库结果一周后检索出来的记忆很多是“用户今天说想吃火锅”这种一次性的信息严重污染了用户偏好。后来我加入了写入校验只有带有时效性短词或明确偏好关键词的内容才允许写入长期记忆临时信息只留在会话缓存。第三个坑忽略记忆时效性。曾经有一个Agent记住了用户“偏好邮件沟通”这条旧记忆但用户在后续对话里已经明确改成了“微信通知”旧记忆没有失效导致Agent反复用邮件模板回复。后来我在记忆表里加了valid_until字段每次更新时把旧值标记为过期检索时默认过滤过期项。5.2 常见问题排查速查表这里整理了一份我经常用来排查的速查表不一定覆盖所有场景但能解决大多数常见问题症状可能原因解决思路Agent在长对话后段“失忆”上下文被截断没有保留早期关键信息对早期对话做摘要压缩提取用户约束和已完成动作检索出来的记忆总是不相关向量化单一召回忽略了关键词和标签过滤改成混合检索增加类型标签过滤和重排记忆库越来越大但效果变差写入策略太宽松垃圾记忆过多收紧写入校验增加遗忘机制Agent反复询问用户已给过的信息信息只存在某轮对话中未写入长期记忆关键信息在对话结束时抽取并写入对应层级记忆用户改变偏好后Agent仍用旧偏好更新策略缺失旧记忆未失效更新记忆时保留历史版本把旧版本标记过期或降权工具调用频繁失败或返回重复数据上下文里没有保存上一次工具调用的摘要在上下文保留工具调用历史的关键结果摘要使用这个表时建议先检查日志里模型实际拿到的上下文和检索结果再对照表格定位原因不要一上来就调模型或换向量库。5.3 更进一步的实验方向走到这里你已经有了一个能用的记忆系统。如果再往深走有四个方向值得尝试。第一个方向是记忆抽象。不要把原始对话直接存进长期库而是引导模型生成更高层的“用户画像”“任务规律”。比如从十次对话中抽象出“用户偏好结构化报告”“用户在预算紧张时会优先选性价比方案”。抽象记忆的泛化能力更强但也要注意过度抽象导致的失真。第二个方向是记忆压缩与合并。长期运行之后同类记忆会越来越多比如用户多次表达“希望尽快交付”。与其存十条相似的记忆不如做一次聚类合并变成一条带权重的偏好纪录。这个过程可以定期离线执行不需要在线实时做。第三个方向是记忆评估。记忆工程好不好不能只看“能不能搜到”还要看对最终任务结果的贡献。可以设计一组指标记忆命中率、记忆引入后的任务成功率、上下文平均长度变化、用户反馈分数。有评估体系你才能优化迭代而不是拍脑袋调参。第四个方向是多Agent共享记忆。如果你的系统里有多个Agent协同可以考虑让它们共享部分公共记忆同时保留各自的私有记忆。例如所有Agent共享企业的知识库RAG但每个Agent维护自己负责客户的用户记忆。这个架构能避免重复造轮子也能让记忆更清晰。最后分享一个我自己的小经验做记忆工程不要一开始就追求高大上的架构。先用一个最简单的脚本把关键信息从对话中抽取出来存成JSON文件再写几十行代码做关键词检索把结果拼到上下文里。跑通这条链路之后再逐步替换成向量库、混合检索、分层存储。很多项目恰恰是因为一开始就把系统设计得太复杂结果连基础链路都没跑通就匆忙推进最后返工。我个人在实际操作中还有一个习惯每次Agent执行完一个完整任务我都会让它额外输出一条“本次会话的记忆摘要”然后我会自己看一遍确认哪些值得写进长期库哪些应该丢弃。这个简单的“人工审核”步骤能在初期阶段大幅提高记忆库的质量。等数据量和置信度上来了再慢慢把审核自动化最终形成“写入-检索-更新-遗忘”的完整闭环。