跳到主要内容

Agent 记忆是一个没有失效策略的缓存

· 阅读需 10 分钟
Tian Pan
Software Engineer

现在每个智能体 (agent) 框架都将“长期记忆”作为核心功能发布,每个团队都将其视为百利而无一害的好事。智能体记住了用户的偏好、之前的决策、项目上下文以及上周收到的修正,因此每次会话的起始状态都比上一次更“热”。演示效果令人难以抗拒:用户说一句“按照我的喜好设置项目”,智能体就照办了。没有人问那个显而易见的问题,因为这一功能的叙事框架在刻意回避它。

问题是:这一切何时会变得不再准确?

记忆存储本质上是一个缓存。它保存着关于一个并非静止不变的世界的事实。智能体在 8 个月前记录了“用户偏好 Postgres”,但团队此后已迁移到了另一个数据库。智能体记得“用户在增长团队”,而用户在 3 月份已经调岗了。智能体存储了一个简洁的对话总结,但该对话的前提在两条消息后就被修正了。记忆层在提取这些信息时,其自信程度和新鲜感与今早刚写下的事实完全一致。我们花了 50 年的时间才意识到,没有失效策略的缓存就是一个正确性漏洞 (correctness bug)。然后我们构建了智能体记忆,并在没有这种策略的情况下将其发布了。

功能包装掩盖了缓存的本质

Phil Karlton 的那句名言——“计算机科学中只有两件难事:缓存失效和命名”——之所以是个笑话,是因为它确实如此。缓存失效之所以难,是因为它不是一个你构建出来的功能,而是一套你需要维持的准则。你必须知道每个缓存条目依赖于什么,检测依赖项何时发生变化,并在有人读取陈旧值之前传播该变化。这三者中任何一个出错,缓存就会默默地撒谎。

智能体记忆同时具备这三个问题,却没有继承任何准则,因为它从未被当作“缓存”来介绍。它被冠以“记忆”之名——这个词带有拟人化的、令人共情的、显而易见的好感。你绝不会发布一个没有 TTL(生存时间)、没有剔除机制且没有依赖跟踪的缓存层,并称其为生产就绪。但是,带有同样这三个漏洞的“长期记忆”每天都在发布,因为这个名字让缓存“偷渡”过了评审阶段。

2026 年关于智能体记忆框架的调查直言不讳地指出了这种做法的后果。在广泛采用的系统(Mem0、Zep、Letta、LangMem、MemOS)中,检索质量和写入提取能力提升很快,但陈旧性处理正如 Mem0 所言,在大多数框架中仍然是“未解决”的。存储量单调增长。没有任何东西会被剔除,因为“记忆”的说法让删除感觉像是数据丢失,而不是缓存清理。

“陈旧”不等于“过期”

一旦你接受了缓存的比喻,直觉就是去寻找 TTL。让一切衰减:除非有东西重新确认,否则记忆的置信度会按计划下降。这会有所帮助,你也应该这样做——但它解决的是问题中次要的那一半。

TTL 可以优雅地处理“低相关性”条目。关于临时项目的语法问题的随手笔记会在 7 天或 30 天后过期,没有人会想念它。危险的记忆恰恰相反:那些被不断且正确检索的“高相关性”事实,直到它们失效的那一刻。

“用户的雇主是 Acme”是存储库中被检索次数最多的事实。它在连续的一千轮对话中都是正确的。然后用户换了工作,在第 1001 轮时,它并没有变得陈旧或低置信度,而是变得“自信且具体地错误”——而且它在存储库中仍然拥有最高的检索评分,因为它一直如此。

这正是最近一项关于记忆有效性的基准测试所揭示的令人不安的失败模式。当研究人员测试前沿模型和专用记忆框架是否能识别其存储的记忆已不再有效时,表现最好的系统得分约为 55%——仅仅比掷硬币好一点点。模型通常会接受用户问题中包含的过时假设,并且无法传播变更:当用户更新一个事实时,智能体不会使依赖该事实的相关事实失效。告诉智能体你搬了家,它也不会重新考虑它热心记住的“最喜欢的本地咖啡店”。

纯粹的衰减模型无法捕捉到这一点,因为陈旧的事实看起来从来都不像低置信度的。失效不是计时器。它是一个依赖图。

记忆存储真正需要的四项准则

如果你把记忆层看作它原本的缓存本质,那么操作要求并不奇特。它们就是任何缓存都需要的同样四件事,只不过翻译成了智能体的语言。

出处 (Provenance),以便使记忆失效。 每个存储的记忆都应该链接回产生它的源事件——消息、文档或工具结果。如果没有这个链接,你永远无法回答“这是否仍然真实?”,因为你不知道“这”是从哪里推导出来的。有了它,当源头被删除、修正或取代时,记忆就可以被机械地置为无效。那些认真对待这一点的框架——Mem0 的作用域出处、Zep 的片段级出处、MemOS 的版本化出处元数据——并不是在增加繁琐的手续。它们是在添加让失效成为可能的依赖边。没有出处的记忆就像没有键的缓存条目:你可以读取它,但永远无法安全地使其过期。

区分持久事实与情境事实的写入策略。 “用户名叫 Sam”和“用户今天很沮丧”不应该以相同的生命周期进入同一个存储库。大多数提取流水线将两者都扁平化为“一条记忆”,并让它们一起腐烂。一个有用的写入策略会在进入时进行分类——身份事实、稳定的偏好、项目状态、瞬时情绪——并为每个类别分配不同的默认生命周期和不同的置信度衰减曲线。最廉价的失效是从未发生的写入:智能体目前持久化的大部分内容其实是应该随会话结束而消失的上下文。

冲突解决策略,而非冲突呈现。 简单的向量搜索会以同样的热情检索出“用户偏好 Postgres”和“用户偏好图形数据库”,并将两者都交给模型,导致模型陷入矛盾的指令中。检索在返回结果之前需要一套裁决规则:倾向于近期内容(对相似度得分施加明确的时间衰减惩罚)、优先选择用户直接断言的事实而非智能体推断的事实、优先选择权威性较高的来源。目标是返回当前真实的状况,而不是它经历过的每一个状态的记录。

使用墓碑机制 (Tombstones) 而非直接删除。 当一条记忆失效时,不要默默地丢弃它。将其标记为 INVALID(无效),保留记录并留存审计追踪。这之所以重要,原因与在数据库中相同:不可变的历史记录让你能调试“智能体为什么要那样做”,让你能从错误的失效操作中恢复,并让未来的工程师看到某个事实曾是正确的,但已被刻意废弃——而不是将其作为新鲜的惊喜重新发现。

为什么这在组织架构中被忽视

技术修复并非难事。难点在于,“记忆”被作为一项“产品”功能引入,却从未被作为一项“运维”责任分配给任何人。

当团队上线 Redis 缓存时,会有人负责其逐出策略 (eviction policy)、命中率、内存上限以及报错时的告警。当同样的团队上线智能体记忆 (agent memory) 时,产品侧拥有“智能体能记住事情”的能力,却没有人负责陈旧性 (staleness)。目前没有仪表盘显示检索到的记忆中陈旧记忆的占比,因为陈旧性是不可见的,直到用户重新纠正他们已经纠正过的事情——而这种重新纠正只会表现为一种模糊的“智能体有时感觉很笨”的投诉,而不是缓存未命中 (cache-miss) 指标。

因此,技术栈中每个其他缓存都存在的纪律——TTL(生存时间)、逐出告警、失效测试——从未为这个被命名为看起来不需要这些东西的缓存而建立。修复方法在某种程度上是文化上的:在设计文档中停止称其为“记忆”,开始称其为“记忆缓存”,这样那些保护其他缓存的评审问题也会针对这个缓存被提出。在设计评审中询问“逐出策略是什么”。针对每类存储的事实,询问“什么会导致此条目失效”。询问“我们如何知道命中率是健康的”,并接受目前诚实的回答通常是“我们不知道”。

针对陈旧记忆进行测试,而不只是召回

最后一个差距,因为正是它让其他问题在满是绿灯的仪表盘面前得以蒙混过关。大多数对记忆层进行评估的团队通常只评估“召回 (recall)”:假设智能体存储了一个事实,它之后能否检索并使用该事实?这是必要的,也是简单的一半。

几乎没有人构建的评估切面是“对抗性”的:在存储中植入一个事实,然后改变环境使该事实变得错误,并测量智能体是否察觉。它是基于陈旧的偏好行事,还是重新确认?当两条存储的记忆发生冲突时,它是选择最近的一条,还是将两者都呈现并卡住?当用户的查询包含一个过时的假设时,智能体是继承该假设还是纠正它?一个召回率得分 95% 但从未进行过陈旧性测试的记忆系统,只通过了那个永远不会伤害你的那一半问题的认证。

重新定义才是重点。长期记忆并不是智能体获得的一种新型智能。它是一个关于不断变化的世界的事实缓存,智能体运行的时间越长,缓存中悄然出错的部分就越多。一个没有失效策略 (invalidation strategy) 的缓存不是一个功能。它是一个缓慢发生的正确性 Bug——而“记忆”只是那个让它逃过代码审查的名字。

References:Let's stay in touch and Follow me for more thoughts and updates