
做 Agent 应用早晚会遇到那个灵魂拷问模型怎么什么都记不住你上午让它查完资料下午再问一句“上午那个结论是什么”它一脸茫然。更别提让它长期跟踪一个项目、记住你的偏好、跨多轮对话保持一致。这不是模型笨而是你压根没给它装“记忆”。“记忆工程”这四个字就是专门解决这个问题的。它不是某一个函数、某一个数据库而是围绕“Agent 怎么把信息存下来、怎么在需要时想起来、怎么忘记过时的东西”设计的一整套机制。我的理解是记忆工程之于 Agent相当于操作系统之于电脑——没有它程序也能跑但跑不长远也跑不聪明。这篇文章我不打算讲抽象概念直接把我在实际项目里怎么设计记忆层、踩过哪些坑、最后沉淀下来的一套可行方案拆给你看。适合正在做 Agent 应用、或者准备上多轮对话和长期任务场景的开发者参考新手也能跟着落地。1. 记忆工程到底是什么Agent 的“第二大脑”1.1 从一次对话翻车说起我之前做过一个模拟项目 X核心功能是让 Agent 担任项目助理帮用户跟踪一个跨三周的任务。头两天表现还行到了第三天问题就来了。用户问“上周二和某供应商确认的交期是几号”Agent 的回答完全基于当前这一轮对话的上下文它根本不知道“上周二”发生了什么。因为它没有记忆。这事给我提了个醒绝大多数大模型 API 是无状态的。你每次调用它它面对的都是一张白纸。所谓多轮对话不过是你把历史记录一股脑塞回给它而已。所以“记忆”这件事本质上不是模型的缺陷而是工程上有没有把信息管理起来。1.2 记忆的分层模型工作记忆、情景记忆、语义记忆人类记忆分很多种Agent 也一样。我参考认知科学的思路把记忆工程里的数据划分为三个层级第一层是工作记忆就是当前这轮对话的上下文窗口。模型能直接看到的内容都在这里相当于它手上的便签纸。便签纸越大能同时处理的信息越多但成本也越高而且翻页就忘。第二层是情景记忆记录那些“发生过的事”某次对话、某个操作记录、某次用户纠偏。它和当前上下文解耦存在外部存储里但可以通过检索在需要时调回来。前面那个“上周二”的问题就是情景记忆缺失导致的。第三层是语义记忆是从大量互动中提炼出来的稳定事实和偏好比如“用户偏好简洁回复”“项目截止日期是下周五”“客户 A 不接受分批交付”。这类信息不会频繁变化适合长期存储、高频复用。这三个层级的核心差异其实是信息的时效性与抽象度。工作记忆最敏感但最短暂语义记忆最稳定但最需要提炼。一份好的记忆工程设计第一件事就是把这三类信息分清楚用不同的机制去处理而不是一股脑塞进一个表里。1.3 为什么记忆工程不是“加个数据库”这么简单有些人会觉得记忆嘛把历史对话存进数据库下次检索出来拼到提示词里不就行了。理论上没错但实际落地会发现一堆问题存什么、怎么存、怎么找、怎么防止找回一堆没用的垃圾、怎么让它该忘的时候果断忘……每一个环节都有讲究。举个例子。你在应用里内置一个“最近 30 天对话记录表”用户问“我之前说过不喜欢邮件通知”你用关键词“邮件通知”去检索能查到那天对话的原文。但如果用户换一种说法——“别老往我邮箱里发东西”关键词匹配就废了。这时候你需要语义检索而语义检索又牵扯出 embedding 模型选择、相似度阈值怎么设、结果怎么重排这些细节。记忆工程更像是一个信息生命周期管理系统。它要处理的不只是“存”和“取”还包括“提炼”和“遗忘”。单纯加一个数据库只是给 Agent 装了个硬盘但一套完整的记忆工程才让这个硬盘变成会思考的第二大脑。2. 记忆工程的三个核心环节写入、检索、遗忘2.1 写入策略什么时候该记什么时候不该记我见过不少项目把 Agent 说的每一句话都存下来结果记忆库变成一个巨大的垃圾场。检索时召回一堆无关内容不仅浪费 token还把模型思路带偏。所以记忆工程第一课是学会克制地写入。我的实践是设置三类写入触发条件。第一类是显式写入用户明确表达“请记住”“以后都按这个来”。用户的明确指示优先级最高必须落库而且要让用户感知到“它记住了”。第二类是隐式写入基于规则的自动识别。比如用户在对话中透露了偏好、约束、时间节点、实体关系系统通过预设的槽位或模型抽取判断信息是否值得入库。判断标准很简单这条信息在未来还有没有可能被用到会不会影响后续决策如果两者都否就不写。第三类是状态变更写入当某个任务状态、进度、结论发生变化时及时更新对应的记忆记录。比如“和供应商确认的交付日期从 5 月 10 日改到 5 月 18 日”这就不是新增记录而是更新原记录否则过几天检索时会同时出现两个相互矛盾的日期模型直接精神分裂。写入时还有一个容易被忽略的点原始记录 vs 提炼记录。原始记录信息最全但噪声大、冗余高提炼记录干净但提炼过程可能丢失细节。成熟方案通常两层都存原始记录做底档提炼记录做索引前端优先用提炼记录需要细节时再回溯原文。2.2 检索策略向量检索与重排的取舍写入做了分类管理之后检索就是记忆工程的门面。用户感知到“有没有记忆”全靠检索的命中质量。最基础的方案是向量检索。把记忆内容用 embedding 模型转成向量用户提问时也转成向量算相似度取 TopK。这条路能解决“换说法”的问题但也不完美。它的问题是相似度高的内容不一定是对用户当前问题最有帮助的而且向量检索对时间、数字、否定语义这类信息很不敏感。比如“不要把报告发给客户”如果把这段语义编码进向量检索“请把报告发给客户”时相似度可能还很高——语义相反向量却相近。所以我在实践中会做混合检索向量相似度做召回再加一道规则与重排。规则层过滤掉时间过期、状态已废弃、来源不可靠的记忆重排层用轻量级评分函数或大模型二次判断给候选记忆打分排序。具体打分我会同时参考三样东西语义相关分用户当前问题与记忆内容的相似程度占比最高。时间衰减分记忆距今越久分数越低。但某些类型如用户偏好、项目红线例外它们不受时间衰减影响。命中频次分同一条记忆近期被反复调用的权重适当上调说明它一直在“发挥作用”。这套评分不需要多复杂关键是权重调参。我最初全部依赖向量相似度想省事结果用户问“我上次说过什么来着”召回的全是无关的寒暄记录。后来加了时间衰减和重排效果立刻不一样了。2.3 遗忘策略被所有人忽略的环节记忆工程里最反直觉的其实是“遗忘”。很多人一股脑想把所有东西记下来却忘了信息是有时效性的。举几个常见场景。用户昨天说“这周五之前需要完成初稿”到了周六这条记忆就失去价值了继续留着只会干扰后续判断。一个临时任务状态“正在等待某方确认”项目结束后再检索到模型可能误以为它还是当前任务答错方向。这种记忆不清理时间一长整个记忆库的信噪比就会急剧恶化。我设计的遗忘机制分两个层次。一是硬性淘汰给记忆记录加 TTL 和过期时间。对临时任务状态、一次性告知类信息到期自动归档到冷存储甚至直接删除不再参与检索。二是软性降权对保留价值但时效性下降的信息不删除但降低检索权重。比如用户半年前提到“我比较喜欢电话沟通”最近一个月都在用邮件开会这种旧偏好不能直接删可能只是这段时间变了但要降权让更近期的行为模式占据主导。遗忘是记忆工程里最容易被偷懒跳过的一环但恰恰是它决定了一个长时间运行的 Agent 是越用越聪明还是越用越混乱。我宁愿每周末跑一次清理任务也不愿意让垃圾记忆在库里发酵。3. 实操落地我在模拟项目里搭建的一套记忆层3.1 技术选型为什么这么选这部分写给动手实现的人。先说 embedding 与向量存储。我的判断是不要一上来就上重型方案。如果 Agent 应用的日活不高、记忆量在十万条以内用轻量级本地方案完全可以撑住——内存索引配合文件持久化或者直接用一个开源向量库。等数据量真的大了再迁移不迟迁移成本没有想象中高因为记忆层和应用逻辑本来就是解耦的。我那个模拟项目 X 的选型是记忆存储用了一个支持向量检索的嵌入式数据库单文件即可运行不需要单独部署服务结构化信息如用户档案、任务状态表单独存了一张关系表方便按条件精确查询和更新核心数据通过外置 API 向量化同时做了一个本地缓存避免每次查询都调用向量化服务节约成本。选型的核心思路只有一个记忆层要和业务逻辑完全分离保证后续替换存储方案时不需要改上层代码。我在设计时把记忆读写封装成了统一的存取接口内部具体用向量库还是关系表调用方完全不用关心。3.2 记忆的存取流程设计整个存取流程我把它分成写入和读取两条链路互不干扰。写入链路长这样用户每条消息进来先跑一遍“记忆判定器”——一组规则加一次轻量模型调用判断消息里是否存在值得入库的信息。如果命中显式指令直接按指令落库如果命中隐式规则抽取出的信息先进入“待确认缓存”由后续对话验证。分类写入属于用户档案的进档案表属于任务状态的进任务表属于知识经验的进语义库无法归类的暂存为原始会话日志。对新入库信息打标签来源时间、信息类型、置信度、过期时间。读取链路相对简单用户提问后除了获取当前上下文同时生成一个语义查询。查询检索三个层级当前对话上下文工作记忆、最近的相关情景记忆、该用户的稳定语义记忆。召回结果进入重排打分取前几条拼接成“记忆增强片段”注入到提示词中的专门区域。提示词里明确告诉模型以下是该用户的历史记忆若与当前对话无关请忽略。这一步很重要防止模型被无关记忆带偏。3.3 记忆检索的评分融合代码示例下面这段是我在一版原型里写的简化版评分逻辑做了一个轻量级的“相关分 时效分 频次分”融合。你可以看作一个可扩展的框架实际权重根据你的场景调。import time def memory_score(memory, query_embedding, similarity, nowNone): now now or time.time() # 1. 语义相关分范围 0-1来自向量检索 semantic_score similarity # 2. 时效分衰减系数按天计算越近的越高 age_days max(0, (now - memory.timestamp) / 86400) time_score memory.stable_flag if memory.stable_flag else (1 / (1 0.1 * age_days)) # stable_flag: 对于用户偏好、项目红线这类稳定记忆时效分恒定为1 # 3. 频次分近期被检索命中的次数越多说明越有价值 freq_score min(1.0, memory.hit_count / 5) # 4. 加权求和权重需要结合实际场景调整 total 0.6 * semantic_score 0.3 * time_score 0.1 * freq_score # 5. 硬性过滤规则优先级最高 if memory.status expired: return 0.0 if memory.info_type temporary and memory.expire_time now: return 0.0 return total代码很简单但我想强调权重设计的两点讲究。一是稳定记忆的时效分为什么恒为 1。因为“用户偏好”“项目红线”这类信息本质上是长期事实它不会因为时间流逝而变得不重要。如果也按衰减公式来半年后一条关键约束就排在很后面模型很可能忽略它导致严重决策错误。二是过期状态优先级最高。很多检索逻辑只算分数没有状态过滤结果一条已经被标记过期的临时记忆还出现在候选里直接污染结果。实际排查问题时“命中的全是过期内容”这一类 bug 大多是这里逻辑缺失。3.4 记忆压缩与摘要策略记忆库只增不减任何一个长期运行的 Agent 都会遇到上下文长度天花板。我的做法是分层摘要。每一轮重要对话结束时系统会生成一个“本轮摘要”包含核心信息、当前结论、未决事项和原始记录一起存。每天晚上跑一次定时任务把当天多个摘要合并成“日摘要”再和之前的日摘要合并成“周摘要”。检索时默认用高层摘要只有高层摘要信息不足时才去翻底层的原始记录。这样做的好处是双重的。第一token 消耗显著下降一个月的对话记录如果全部塞进上下文几百条甚至上千条都不止但压缩成日摘要后可能只有几十条。第二信噪比提升——摘要这个动作本身就是一个提炼过程去掉了客套话、重复表达、碎片信息只保留关键事实。但也要注意摘要可能丢失细节。我踩过的坑是摘要里只记“和客户确认了交付时间”但忘了写具体日期导致后续 Agent 只能含含糊糊回答。后来我在摘要模板里强制要求列出可执行的参数项时间、人员、状态、限制条件没填全的摘要不允许入库。4. 常见问题与排查技巧实录4.1 记忆污染找回一堆没用的旧记忆症状是用户没问过去的事但 Agent 回答里莫名带出了几个月前的旧历史甚至把已经作废的信息当现在的依据。我排查这种问题先看检索环节的重排结果前几个候选是不是匹配错了再看卡阈值看哪些低质量候选被放进来。这类问题的根源一般有两个一是检索的相似度阈值设置过低二是没有对记忆记录做“使用价值”分级。阈值太低垃圾全进来没有分级一次闲聊记录和一条决策依据被同等对待各凭向量相似度竞争自然容易翻车。我的对策是双管齐下把阈值往上调同时给记忆记录增加“价值等级”。高价值记录项目约束、用户明确偏好提高权重低价值记录日常闲聊降低权重。结果立竿见影。4.2 记忆漂移AI 记错上下文记忆漂移这个词是我自己总结的指 Agent 在长期的记忆读写过程中对同一个实体的理解逐渐偏离真实情况。举个例子用户最初说“客户 A 比较在意价格”一周后说“客户 A 最近开始重视质量了”推理能力强的模型能理解这是情况变化更新记录。但如果记忆系统设计得糙旧记录没被覆盖新记录又进来了检索时同时召回两条矛盾记录模型就不知道该信哪条。还有更隐蔽的用户说“整体色调偏冷淡”系统抽取时夸大成“用户讨厌所有彩色”这种过度泛化就是漂移。这个问题的解决思路是更新优先于新增 存储后校准。凡是对同一实体的同一属性存在已有记录一律做更新而不是插入新记录信息入库前用一次轻量模型校验抽取结果发现过度泛化就退回原文修正。我后来在记忆库里加了一层简单的实体归一化处理所有提到客户、时间、数字的地方统一转成规范化格式再存避免同一含义的内容生成多个变体记录。4.3 性能瓶颈记忆越来越多响应越来越慢记忆库从几千条涨到几十万条后检索延迟肉眼可见地上升。尤其向量检索暴力搜索的复杂度是线性的数据量大到一定程度就顶不住了。我实测下来的处理顺序是先做冷热分离。用户最近 30 天产生的高频记忆放热存储索引全开更早的记忆归档到冷存储只在特定场景用户主动翻历史时检索。这一步通常能把检索延迟降掉一半以上。如果还不够再考虑加索引或换支持 ANN 的存储方案但我还是那个建议不到规模瓶颈不要轻易上重型方案运维成本会拖垮你。另一个隐藏性能问题是写入链路的重复计算。每条消息都重复做记忆判定、信息抽取、向量化费时费钱。我加了简单缓存同一用户相近时间的相似消息直接沿用上次的判定结果不再重复计算。4.4 记忆安全与隐私防护最后是很多人不会立刻意识到、但真正上线时卡你脖子的问题记忆里往往包含大量的用户私人信息。偏好、联系方式、日程安排、健康状况这些一旦被不相关的对话场景检索出来就会带来隐私风险。我处理的原则有三条。一是最小化存储能存摘要就不存原文能明确用途才采集和功能无关的信息直接不吸收。二是权限隔离不同用户之间的记忆必须完全隔绝同一用户的不同项目空间之间也不允许相互检索。这条在代码里要直接写在数据访问层不能只靠上层逻辑约束。三是可清除权用户有权一键删除自己的全部记忆这个接口我强烈建议所有做记忆工程的人都要预留必要时能救命。5. 记忆工程的进阶方向让 Agent 学会自己管理记忆5.1 反思与固化把经历变成经验在基础架构稳定之后我想分享一个让 Agent 记忆质量产生质变的设计反思与固化机制。具体做法是每隔一段时间比如每 5 轮对话、或每个任务节点结束用一次独立的模型调用把当前记忆库里相关的碎片信息做一个反思这次交互里哪些是真正影响到结果的关键信息用户隐含的偏好是什么有没有数据之间相互矛盾的地方反思生成的内容不是简单摘要而是带有结论性质的“经验笔记”。这些笔记再作为高权威记忆入库。打个比方。普通记忆相当于记账——一条一条记录事实反思机制相当于做财务分析——从账目里发现规律提炼出“以后这类客户要预留更多沟通时间”这样的判断。这一步做完Agent 才真正从“记住你说过的话”进化为“理解你的习惯”。5.2 结构化记忆与知识图谱向量相似度适合“模糊回忆”但有些查询需要精确的关联关系。比如“客户 A 的项目和哪个供应商有关”这不是相似度问题而是关系查询。针对这类场景我尝试过在记忆库里增加一个轻量级的关系层把高频出现的实体客户、项目、人员、时间节点建实体表把它们之间的关系存成关系边。查询时先通过关系层定位候选再做向量检索增强细节。这个方案的取舍在于关系维护成本高不能全量做只针对重要记忆。和摘要机制配合之后效果很明显但架构复杂度和维护成本也同步上升。适合你的应用已经有明确实体边界时再考虑不要在起步阶段就上。5.3 让 Agent 自主决定何时记忆与遗忘最后一个方向也是我自己还在探索的把“记忆决策权”部分交给 Agent 自己。传统方案靠规则和流程控制明确什么时候存、什么时候取、什么时候删。但规则总有边界用户的表达千变万化总有些信息模块难以通过预设规则识别。我的新思路是给 Agent 提供“记忆工具”让它在对话过程中自主判断是否需要调用记忆读取、是否需要保存当前信息。所谓“给 Agent 装上记忆管理的 API”需要写入和读取的都是用户显式指令时机器自主判断的边界就变得尤为重要。这里必须加一道保险丝所有自主决策都记录审计日志关键操作删除记忆、覆盖旧记录必须有用户确认。我不建议一上来就全放开最好从“只允许自动写入不允许自动删除”的半自主模式起步观察一段时间再逐步增加权限。我在实际项目里感受最深的一点是记忆工程不是一个一次性搭建的功能而是一个需要随应用运行不断调优的系统。它没有标准答案只有持续迭代——就像任何靠谱的软件系统一样。希望这篇文章能帮你少走一些我走过的弯路。