一、Agent 的记忆,其实是三块不同的东西

给 Agent 加"记忆",很多人以为就是存对话历史。实际要分三块:工作记忆、情景记忆、语义记忆。

不清这三块,就会出现"记了很多但都没用"的情况。

做 Agent 做得久了会发现,效果差往往不是模型差,是记忆乱。

把三块东西混在一个向量库里,检索出来的结果永远似是而非。

分开存、分开检,效果立刻不一样。这是我改架构之后最明显的一次提升。

二、工作记忆:当前这一步需要什么

工作记忆就是上下文窗口里的内容,只服务当前任务。

它的问题不是容量,是噪音。把整段历史都塞进去,模型会被无关内容干扰,反而更容易跑偏。

做法是每一步只保留:目标、当前状态、上一步结果、约束条件。四样就够。

工作记忆的容量是有限的,这一点要认清。

它不是越大越好。塞太多,关键信息会被稀释;塞太少,模型会反复问你同样的问题。

我的经验是控制在一次任务所需的量,具体一点:当前步骤、相关的三条事实、以及一个约束。

三、情景记忆:做过什么,结果如何

情景记忆是"我上次遇到类似的事,怎么处理,结果怎样"。

它最适合存成结构化记录,而不是原文对话。

一条记录写四个字段:任务类型、采取的动作、结果、失败原因。后面检索靠这四个字段,不靠向量相似度硬怼。

情景记忆最容易写坏,因为它需要「结果」这一列。

很多人只记「做过什么」,不记「结果如何」。这样的记忆只能复述,不能学习。

我后来加了两列:成功与否、失败原因。检索的时候先按相似任务,再按成功过滤。

这一步让重复犯错的概率降了一大截。代价是要多写一个字段,值。

还有一点:情景记忆要带时间戳。没有时间的记忆,会被当成永久事实。

四、语义记忆:稳定的事实和偏好

语义记忆是长期有效的知识,比如用户偏好、系统规则、常用参数。

这块最需要"写入审慎"。Agent 自作主张把推断当事实写进去,后面每一步都会被污染。

一条实用规则:只有用户明确说过的,才写语义记忆;模型推断的,只进情景记忆。

语义记忆最容易腐烂,因为它记的是「事实」,而事实会变。

所以语义记忆要带置信度和来源。没有来源的事实,三个月后你不敢用。

我的做法是每条事实配一句「据 X 于 Y 时所述」,更新时整条替换,不做合并。

五、检索比存储更关键

存了一堆记忆,检索不出来等于没有。

三个调法:

一、先按类型筛,再算相似度。类型错了,相似度再高也没用。

二、给记忆加时间戳,同一条事实冲突时取新的。

三、限制每次注入条数。三条以内通常够用,多了就是噪音。

检索比存储更关键,这句话我想多说两句。

存储是空间问题,检索是精度问题。空间可以花钱买,精度只能靠设计。

三个设计点:一是分块大小,太大检索粗,太小丢上下文;二是混合检索,关键词加向量;三是重排,先粗排再精选。

三个都做了,效果通常能上一个台阶。只做向量,往往在专有名词上翻车。

专有名词翻车这件事,几乎每个垂直领域都会遇到。补关键词检索,是最省事的解法。

六、成本上的现实

记忆不是免费的。每次注入都要占 token,长会话里这块开销会很明显。

我的做法是分层:工作记忆每步都带,情景记忆按需检索,语义记忆只在开头注入一次。

成本这块说点实话:记忆是最容易失控的部分。

每轮都写、从不清理,三个月后一条任务要检二十万条记录。

我的做法是三层清理:会话级过期即删,任务级保留三十天,事实级长期保留但要人工确认。

三层之外还有一个兜底:定期抽样重检,看召回是否变差。变差就说明该重排了。

这套东西不复杂,但要坚持。不做清理的 Agent,最后都会变慢、变贵、变糊涂。

补一句:记忆不要做成黑箱。

你要能看见它检索了什么、为什么选这条。看不见,出了问题只能猜。

我现在都会留一个日志,记下每次注入的内容。这个日志救过我很多次。

成本上的现实:记忆检索的延迟,往往比生成还高。

一次检索要跑向量搜索加重排,几十毫秒到几百毫秒。任务步骤一多,这部分就成了瓶颈。

所以缓存很重要。同一任务内,检索结果可以复用,不必每步都查。

延伸参考

概念对照可以去前端 Wiki 翻词条,解释都不绕。

前端 Wiki

留一句:Agent 的记忆做得好不好,看它会不会忘掉该忘的。