Agent memory 是过去一两年最热门的研究方向之一。每隔几周就有新方案出现,每一个都声称解决了 agent 的记忆问题——跨 session 记住用户偏好、学习使用习惯、随着交互变得越来越懂你、永续记忆。产品越来越多,论文越来越多,但现实是这些系统都有已知的、根本性的失败方式,这个问题还远没有解决。
反复摘要会让记忆偏离原始事实,像复印件的复印件,你不知道什么时候开始不准确了。语义检索会把语义相似但语用相反的记忆拿回来,注入错误的上下文。早期频繁提及的信息会压过最近发生的事,让 agent 活在过去。旧的记忆和新的事实产生矛盾,没有机制发现。这些都不是边缘情况,是任何有一定规模的 memory 系统都会撞上的问题。
更麻烦的是,我们连怎么评估一个 memory 系统都还没搞清楚。要评估 memory 系统好不好,你需要 ground truth——完整的对话历史。但完整历史比任何 context window 都大,没有人能合理地手动标注。你用来评估 memory 的 judge,和被评估的系统面临完全相同的限制。LongMemEval 这类 benchmark 能测"大海捞针式"的检索,但检索不是记忆。记忆是事实随时间变化、旧 context 被新信息覆盖、某段对话的意义在几周后才变得清晰。这些没有 benchmark 能捕捉。
Agent Memory 不是存储问题
把 agent memory 当数据库是最常见的误解。
agent memory 的每一步都在调用 model。写入时,LLM 决定这条信息值不值得存、该怎么概括。读取时,LLM 判断哪些历史记忆和当前对话相关。发现出错时,LLM 来识别哪条是错的、该怎么修正。
这意味着 memory 系统继承了 model 的所有不可靠性:幻觉、过度概括、前后矛盾、对语境的误判。写进去的不一定是你以为你写进去的,读出来的不一定是你需要的。
这带来了一个没有出路的矛盾。保存信息只有两种方式,一种是原样存,一种是提炼后存。
原样存(raw)是把原始对话完整保留。无损,但惰性——一堆 transcript 堆在那里,信息都在,但没有连接、优先级、解释,就是埋在源材料里的数据。
提炼后存(derived)是用 LLM 把对话压缩成摘要、事实、结构化信息。紧凑可用,但每次提炼都有损失。更危险的是,错误会随着反复摘要而积累——像复印件的复印件,你不知道什么时候开始不准确了。
两个极端都不工作。所有 memory 系统都是在这个谱系上选一个位置,然后接受那个位置的代价。
那 context window 越来越大,最终是不是可以直接塞进全部历史?不行,原因有两个。第一是成本:两年的对话历史,每次对话全量处理,成本线性增长,没有消费产品能撑住这个结构。第二是质量:context window 填满时模型性能下降,中间部分的信息被忽略,推理和指令执行都变差。Infinite context 只是 raw 路径的极端版本,而 raw 路径已经证明不够用。
设计空间有多复杂
理解了 raw vs derived 的矛盾,只是理解了问题的起点。一个完整的 agent memory 系统还需要回答很多问题:存什么、什么时候提炼、什么触发写入、存在哪、怎么检索、检索后怎么处理、什么时候检索、谁来做判断、遗忘策略。每一个都是独立的取舍,牵一发动全身。
几个重要的单独说。
谁来做判断
memory 系统里,每个决策点都需要有人在做判断:这条信息值不值得存?这个摘要准确吗?这条记忆该不该遗忘?
主模型来做,质量最高,但每轮推理都要付全价。便宜的小模型来做,省钱但判断更粗糙。用户自己来做,最准确但加了摩擦。规则和算法来做,零成本但只能处理可预测的情况。没有哪个选择是免费的,成本、质量、可问责性,三个里面只能选两个。
遗忘策略
遗忘不是删除,这是最常被低估的工程复杂度。
如果你同时存了原始对话和从它提炼出来的摘要,删掉原始对话不会删掉摘要。如果你把事实提取进了知识图谱,删掉源对话会让那些事实变成孤儿——它们还在,但失去了来源。真正的遗忘要么追踪每条数据的来源做级联删除,要么定期从更小的 raw corpus 重新 derive 一切,后者代价极高。
而且,遗忘策略无论你有没有主动设计,它都存在。不设计等于选择了"什么都不忘",结果是积累越来越多过时的、错误的、相互矛盾的信息,越来越难纠正。
检索时机
"怎么检索"之外,"什么时候检索"同样重要。
Always-inject 把所有记忆永远塞进 context,不需要检索,但不相关的信息和相关的一起污染了 context 窗口。Hook-driven 在特定时机触发检索,被动覆盖还不错,但可能让 model 表演"拥有记忆"而不是真的有。Tool-driven 让 model 自己决定什么时候去检索,但 model 不知道自己不知道什么——该检索的时候往往不去检索。
三种模式各有各的失败方式,没有一个是干净的解法。
跨 session 检索的两难
不做跨 session 检索,agent 每次对话都从零开始,没有长期记忆可言。做了,又带来另一个问题:同一个词在不同 session 里指代的东西完全不同。"这个项目"在上周的对话里是 A,在今天的对话里是 B,但检索系统不知道这个区别,把旧 session 的记忆拉进来,不只是没用,而是主动引入了歧义。上下文污染不一定来自错误的信息,也可能来自正确但属于另一个语境的信息。
做多少跨 session 检索,是每个 memory 系统都要面对的 tradeoff,没有普遍正确的答案——取决于任务类型、用户习惯、session 之间的间隔时间。
Agent Memory 需要自己的 Harness
Harness engineering 现在是 AI 开发里最关键的概念之一,指的是 model 之外用来让 agent 可靠运转的工程基础设施。它和 prompt engineering、context engineering 有一个本质区别:后两者假设失败空间是可以预见的,在设计阶段把对策想清楚;harness engineering 承认失败空间是无界的,系统必须有能力从遇到的新失败里生长。
类比是免疫系统。先天免疫针对已知威胁,提前设计好——传统软件工程里的 circuit breaker、RAID、重传机制都是这个思维。后天免疫在遭遇未知威胁后习得,识别它,产生对策,永久记住它。没有人在设计 Devin 时能预测到 context anxiety,agent 感知到 context window 快满时会开始提前收尾,表现得像工作做完了,实际上只是在逃避。发现这个问题之后,修法是纯 harness 手段:把实际使用限制在 200K tokens,让 model 以为自己还有充足空间,anxiety 消失了,没改任何模型。这种失败模式只能在生产里撞上才能发现,没有办法提前设计出来。
LangChain 的 Harrison 提出,AI Agent = Model + Harness + Memory。但是 Memory 不是这个系统中一个独立的组件, 它本身就是一个需要被 harness 的子系统。
写入出错了,谁来检测?检索拿回来一条语义相似但语用完全相反的记忆,谁来拦截?记忆随时间漂移,和三个月前写入时的事实产生矛盾,谁来发现?这些都需要独立的机制——而每一个机制本身又要调用 model 来做判断。用不可靠的系统来管理不可靠的系统,这个递归没有干净的出口。
所以 Agent Memory 系统并不是一句简单的 “完整的记录所有信息并让 LLM 来决定” 可以解决的,大多数 memory 系统没有认真对待这一层。"让 LLM 来决定"被当成了终点,而不是起点。少数系统开始引入信任评分机制——对 memory 输出的有用性做反馈追踪,不对称地惩罚错误记忆(错误的代价大于收益)——但这只是解决了一个子问题。
Memory 的失败也是这个性质,而且比 context anxiety 更难处理。
Context anxiety 有明确的症状——agent 开始提前收尾,行为模式发生变化,你能观察到。Memory 的失败通常是无声的。Agent 拿着三个月前写入的一条过时记忆继续运行,假设用户还在用某个已经废弃的工具,给出的建议全部基于这个错误前提。没有报错,没有异常,输出看起来完全正常,只是不对。
更麻烻的是,memory 的失败空间不是固定的。网络丢包的方式是有限的,节点崩溃的方式是有限的,所以可以设计对应的恢复机制。但 memory 的错误随用户行为、时间、上下文动态变化——用户换了工作,换了技术栈,换了习惯,之前积累的大量记忆从"正确"变成了"误导",而这个转变没有任何触发信号。你不可能在设计阶段把所有这些情况都枚举出来。
所以 memory 需要的 harness 必须是后天免疫的——遭遇一种新的失败,识别它,把对策编码进系统,下次能早点发现。矛盾检测、信任评分、跨记忆合成、写入前的安全扫描,这些机制已经有人在做,但各自在解决不同的子问题,没有人把它们整合成一个统一的框架。更根本的问题是,大多数 memory 系统根本没有把"memory 本身会出错"当作一个需要认真对待的前提——它们在解决怎么存、怎么取,但不在解决存错了怎么办、取错了怎么发现。
离成功还差得远,但是有一些曙光
这么多方案并存,没有统一答案。Infinite context 不解决问题,更好的向量检索不解决问题,让 LLM 来决定存什么也不够——尽管它比硬编码规则更好。真正需要的是两件事同时发生。
第一,把 harness engineering 的思维用在 memory 这个子系统本身。不是把 memory 当作一个需要优化的功能,而是把它当作一个会以未知方式出错的组件来设计——建立检测、纠错、学习的机制,让系统从每次 memory 失败里变得更强。这不是一次性的工程工作,而是一个持续生长的过程。
第二,扩展对 memory 本身的定义。目前几乎所有 memory 系统处理的都是同一类问题——存储和检索事实、偏好、对话历史,认知科学里叫 declarative memory,知道"什么"。但人类记忆还有另一半:procedural memory,知道"怎么做"。骑自行车、做手术——这些能力不存在某个可以检索的事实里,它们直接体现在行为里。Skill 文件是目前最接近 procedural memory 的实现,但几乎没有人把它放进 memory 的框架里思考。已经有 agent 开始往这个方向走——在完成复杂任务后自动生成 skill 文件,把"这次是怎么做到的"沉淀成下次可以直接调用的能力。这不是在存事实,是在存行为模式。
Declarative memory 还没解决。Procedural memory 几乎还没开始。但至少问题的轮廓已经清楚了——这比两年前只知道"agent 需要记忆"要进步不少。
夜雨聆风