为什么 AI Agent 的长期记忆几乎都是错的?

0 阅读18分钟

很多人第一次做 AI Agent,都会很自然地加上一层“记忆”。

做法通常也不复杂:把历史对话存下来,切 chunk,做 embedding,查的时候再把相关内容捞回来,塞进上下文里。这样一来,Agent 看起来就像“记住了过去”。

刚开始跑 demo 的时候,这套方案通常还挺唬人。

用户昨天说过喜欢吃什么,今天再问,Agent 能答对。用户之前提过一个项目名,过几轮再问,Agent 也能接上。于是很容易得出一个乐观的判断:记忆这件事,好像也没那么难。

但只要把交互时间拉长一点,把问题变复杂一点,很快就会发现另一面:

大多数 AI Agent 的长期记忆,其实并不可靠。

更准确地说,很多系统并不是“没有记忆”,而是只有一套历史内容检索机制。平时看起来像记住了,真到跨时间、多条件、状态变化这些场景里,错误就会集中暴露出来。

这篇文章想讨论的,就是这个问题:

为什么现在很多 AI Agent 的长期记忆,几乎都是错的?

先说明边界:这篇文章不会直接展开完整方案,而是先把一个更根本的问题讲清楚——为什么很多看起来“已经有记忆”的 Agent,依然会在长期交互里频繁犯错。因为如果问题定义错了,后面的优化大概率也会做偏。


一个看起来很聪明的错误

先看一个很常见的例子。

假设在几周前的对话里,用户说过这样一句话:

“上个月开始减脂,现在不喝酒了。”

又过了一段时间,用户在聊天里随口问:

“晚上吃什么?”

很多 Agent 的回答,可能会让人觉得有点不对劲。比如它会根据更早的记录,推荐一份适合搭配精酿啤酒的晚餐,甚至顺手提一句:

“可以配一杯 IPA。”

如果只看局部信息,这个回答不算完全离谱。系统可能确实记得,用户以前喜欢啤酒,甚至对 IPA 有偏好。问题在于,这条信息已经不是当前最重要的信息了。

真正应该优先被使用的,是那句后来说过的话:

“现在不喝酒了。”

也就是说,这个错误并不是因为模型完全不知道用户的情况,而是因为系统没有正确处理“哪个信息现在还有效,哪个信息已经该退居次要位置”。

这类问题非常典型。

很多时候,Agent 不是彻底忘了什么,而是拿错了记忆、用错了顺序、错判了当前状态。表面上看是回答失误,底层其实是记忆系统设计有问题。

所以,讨论长期记忆时,一个很重要的判断是:

AI Agent 的问题往往不是记不住,而是记住的东西不会用。


现在很多 Agent 的“记忆”,到底是什么

如果把大多数现有做法拆开看,会发现它们的核心流程其实很相似:

历史对话 → 切分片段 → 向量化 → 检索 top-k → 拼接回上下文 → 交给模型生成

这套链路当然有价值,而且在很多场景里确实有效。问题不在于它完全没用,而在于它常常被叫成了“长期记忆”。

严格一点说,这更像是一套面向历史内容的检索增强机制,而不是一个真正意义上的记忆系统。

这两者的差别,乍看不大,实际非常关键。

检索系统的目标是: 给定一个查询,尽量从历史数据里找回相关内容。

记忆系统的目标则更进一步: 不仅要存,还要能组织、更新、取舍、整合,并在当前问题下恢复出正确的状态。

换句话说,真正的记忆不只是“把过去保存下来”,而是:

让过去的信息在未来还能以正确的方式被使用。

如果只是把历史对话扔进向量库,再在查询时拉回几段相似文本,这更像是一个会搜索聊天记录的系统,而不是一个能维持长期一致性的记忆系统。

所以这里可以先下一个判断:

很多 AI Agent 号称有长期记忆,本质上只是给聊天记录接了一层 RAG。

问题也正是从这里开始的。


为什么 RAG 做不好长期记忆

说 RAG 做不好长期记忆,不是说 RAG 不重要。事实上,RAG 依然是今天很多系统的基础能力。真正的问题在于,长期记忆的难点,并不等价于“从历史中找回相关文本”

只要把真实场景稍微展开,就会发现两者之间差了不止一层。

1. 信息天然是碎的

RAG 的基本单位通常是 chunk。

可能是一段对话,一条消息,一个窗口,或者若干句拼成的小块。这样的切分方式很适合向量检索,但不适合表达一个完整的长期事件。

真实世界的信息分布并不是均匀的,也不会老老实实待在一个 chunk 里。很多关键结论,往往是跨时间形成的。

比如:

  • 三月时提到开始健身
  • 四月时说膝盖不舒服,暂停跑步
  • 五月时又提到恢复训练,但强度还不高

这时候如果问:

“现在适合恢复跑步吗?”

答案显然不在某一个单独片段里。它需要把不同时间点的几条信息拼起来,才能接近正确判断。

但 RAG 的工作方式决定了,它更擅长找“最像当前问题的几个片段”,不擅长还原一个跨时间展开的连续状态。结果就是,系统很可能只召回“开始健身”,或者只召回“膝盖不舒服”,而漏掉后续恢复的信息。于是回答就会变得片面。

这类问题的本质是:

长期记忆面对的不是单点查找,而是跨片段重组。

而 chunk-based 检索,天然容易把原本属于同一件事的信息打碎。


2. 历史记录不等于当前状态

这是长期记忆里最容易被低估的一点。

很多系统以为,只要把过去说过的话都存下来,记忆问题就差不多解决了。可现实里,用户真正需要的并不是“过去说过什么”,而是“现在什么仍然成立”。

这两个问题看起来接近,其实完全不是一回事。

举个更简单的例子。历史里同时存在两条记录:

  • “喜欢 IPA。”
  • “这两周在吃药,不喝酒。”

这两句都是真的,也都应该被记住。但在当前这个时间点,它们的权重显然不一样。

如果系统只是把两条记录都找回来,然后简单拼给模型,模型未必总能稳定判断出哪条是当前生效的约束。尤其当检索结果不全、顺序不佳、上下文噪声偏高时,这种判断很容易出错。

所以,长期记忆真正需要维护的,不只是一个“历史事实仓库”,而是一种持续更新的状态表达

这也是为什么很多 Agent 在个性化、计划执行、健康建议、长期陪伴这些场景里特别容易翻车。因为这些任务真正依赖的不是“有没有历史”,而是“能不能得到当前有效状态”。

可以把这句话记住:

记忆的本质不是历史记录,而是状态管理。


3. 没有结构,信息就很难被正确使用

很多 RAG 系统有一个默认假设:每个 chunk 都是独立的,关系主要靠语义相似度去恢复。

这在文档问答里经常还能凑合。但一旦进入长期对话场景,这个假设就会迅速失效。

因为真实的记忆不是平铺的文本集合,而是带结构的。

有些信息属于同一个主题。 有些信息构成同一事件的前后阶段。 有些信息是事实,有些信息是偏好,有些信息则是临时约束。 还有些信息之间存在明显的因果关系、覆盖关系或时间顺序。

如果这些不同层次的信息,在系统里都只是“若干段相似文本”,那检索出来的时候就很容易乱。

比如:

  • “最近工作压力大”
  • “项目 deadline 临近”
  • “连续几天睡不好”
  • “想周末去徒步放松一下”

这几句单独看都没问题,但它们显然不是同一个层级的信息。真正有用的,是把它们组织成一个结构化的场景:项目压力上升,影响睡眠,进而引发对休息和放松的需求。

如果系统没有能力建立这种结构,模型每次看到的都只是一些零散片段,那么输出就只能依赖临场拼接。偶尔对,更多时候靠运气。

从工程视角看,这一点很关键:

没有结构的记忆,最后通常只会退化成“能搜到一些相关内容”。

而“能搜到一些相关内容”,距离“真正理解长期上下文”还差得很远。


4. 检索不是推理

很多系统的默认流程是这样的:

query → 检索 top-k → 拼接上下文 → 生成答案

这条链路的问题不在于简洁,而在于它默认把“找信息”和“理解问题”近似地合成了一步。

但现实里,很多长期记忆问题根本不是一步检索能解决的。

举个例子:

“为什么最近总觉得工作状态不太对?”

这其实不是一个单跳问题。

系统可能先要找到最近工作相关的对话,发现 deadline、加班、会议变多这些线索;接着还要继续找睡眠、情绪、作息变化;有时还要再回头确认是不是最近生活安排也发生了变化。整个过程更像是在逐步扩展证据链,而不是一次性把“正确答案所在的 chunk”召回来。

也就是说,这类问题真正需要的是:

  • 先检索一批初始线索
  • 根据线索调整问题表述
  • 再继续搜索更具体的证据
  • 最后再综合生成回答

这已经不是简单的 retrieval 了,而是一种检索驱动的推理过程

所以长期记忆系统常见的失败,并不只是 recall 不够好,更多时候是因为它把一个本该分阶段完成的推理任务,硬塞进了一次 top-k 检索里。

从这个角度看,可以进一步把问题说透一点:

长期记忆问题,本质上不是单纯的检索问题,而是一个带状态、带结构、带迭代推理的系统问题。


真正的问题,其实不在模型

每当长期记忆效果不好,最常见的第一反应通常是两种。

一种是:模型不够强。 另一种是:上下文还不够长。

这两个方向当然都重要,但它们都不是根因。

先说模型。

更强的模型确实更会“在已有上下文里读懂信息”,也更擅长在冲突信息中做出合理判断。但前提是,相关信息真的被送到了面前,而且组织方式基本正确。否则模型再强,也只能在一个混乱、缺失、噪声偏高的上下文里硬做推断。

再说上下文长度。

上下文变长当然会缓解一部分问题。可只靠堆上下文,并不能自动获得长期记忆。因为长度解决的是“能不能放得下”,不是“能不能用得对”。

把一大堆历史对话全塞进去,不代表系统就理解了哪些是核心事件,哪些是过期状态,哪些信息属于同一主题,更不代表它能稳定地在未来几十轮对话里保持一致。

所以,长期记忆效果差,很多时候并不是模型本身出了问题,而是系统在更早的阶段就已经把问题处理坏了:

  • 写入时没有形成稳定记忆单元
  • 存储时没有建立结构
  • 检索时没有维护层次
  • 调用时没有判断当前有效状态
  • 生成时只能在一堆松散证据上临时拼凑

如果这些基础环节没做好,那么换更强的模型,通常只能把错误变得更“像那么回事”。

因此,这里更准确的判断是:

长期记忆的核心瓶颈,往往不在模型,而在记忆工程范式。


长期记忆真正的解法,不是一招,而是四层能力

需要强调的是,这并不意味着长期记忆无解。真正的问题在于,过去很多系统把“长期记忆”误写成了“历史检索”。一旦问题定义被纠正,解决方向其实会逐渐清晰:先把对话写成稳定记忆单元,再把记忆组织成状态和结构,最后用推理式检索去重建当前真正需要的上下文。

如果把视角从“怎么搜历史”切换到“怎么构建记忆系统”,会发现长期记忆的解法至少分成四层。

1. 写入层:把对话变成稳定记忆单元

原始对话不是长期记忆的最佳形态。

一条消息往往过于零碎,一个固定长度 chunk 又经常切断完整事件。真正适合长期维护的,通常是更稳定的语义单元,比如 episode、event、fact,或者某种经过整理的事件摘要。

只有写入单元本身足够稳定,后续的整合、更新和检索才有意义。


2. 组织层:把记忆从平铺存储变成结构化存储

长期记忆不该是一个“所有历史平等堆在一起”的仓库。

系统需要区分不同层次的信息,比如:

  • 主题
  • 事件
  • 事实
  • 用户画像
  • 当前约束
  • 临时计划

这一步的意义在于,不再把所有内容都交给相似度去碰运气,而是先在数据层面建立最基本的秩序。


3. 检索层:把 top-k 检索变成带判断的推理式召回

长期记忆的调用,不该假设一次 top-k 就能结束。

更合理的方式是:先召回线索,再判断是否足够;如果不足,再改写查询、补充检索、扩大范围。也就是说,检索过程本身应该具备一定的“会回头、会补证据、会收敛”的能力。

很多复杂问题不是找不到答案,而是第一次根本问得不够对。


4. 状态层:把历史事实整合成当前有效状态

这是最关键的一层。

用户真正需要的,通常不是“把历史原话原样念出来”,而是系统能给出一个当前适用的判断。过去的偏好、最近的变化、短期的限制、长期的稳定画像,都需要被整合成一个更接近“现在”的状态表示。

这也是长期记忆和聊天记录检索最本质的差别。

可以把这一节收敛成一句话:

长期记忆真正要解决的,不是历史保存,而是当前状态重建。


为什么现在必须认真谈 Memory Engineering

过去一段时间里,很多团队都在做 Agent。最开始的关注点通常是 Prompt、Tool Use、Workflow、Planning。记忆当然也会提到,但经常被放在一个相对靠后的位置,像是“后面再补的一层能力”。

这种节奏在早期是合理的。因为那时很多系统还停留在短任务、单轮执行或轻量多轮交互,长期记忆的重要性还没有完全显现。

但现在情况正在变。

第一,Agent 正在从一次性问答,走向持续交互。 越来越多应用不再是“问完就结束”,而是会在更长时间尺度上和同一个用户、同一个任务、同一个环境持续互动。

第二,上下文成本越来越显性。 不能指望把所有历史都塞进窗口里解决问题。即便技术上能塞,成本、延迟、噪声和推理稳定性也会迅速变成负担。

第三,个性化和长期一致性开始变成产品体验分水岭。 在真正面向用户的系统里,大家很快就会发现:能答题不算难,能在几周甚至几个月的交互里保持对同一个人的理解,这才难。

也正因为如此,记忆问题已经不再只是“一个附加模块”,而越来越像 Agent 进入生产环境之前必须补上的基础设施。

换句话说,接下来真正拉开差距的,未必只是模型能力本身,而是围绕长期记忆形成的一整套工程方法。

这也是为什么,最近越来越多讨论开始从 Prompt Engineering、Context Engineering,走向一个更底层的话题:

Memory Engineering。


如果现在就要改一个 Agent,最应该先改什么

哪怕这篇文章暂时不展开完整实现,也不意味着只能停在抽象层面。

如果现在就要对一个 Agent 的长期记忆做改造,最值得优先处理的通常不是换更大的模型,也不是盲目拉长上下文,而是先做三件事:第一,不再直接把原始对话当作长期记忆;第二,把“偏好”和“当前约束”分开建模;第三,不再把长期记忆调用固定成一次 top-k 检索。哪怕只做到这三步,很多看起来“模型不够聪明”的问题,都会立刻下降一个数量级。

可以展开成更具体的三个建议。

建议 1:不要直接把原始对话当长期记忆

至少先做一层事件级整理。哪怕只是把连续对话整理成 summary + facts,也通常会比直接存聊天记录强很多。因为后者更像原始日志,前者才开始接近“可维护的记忆单元”。


建议 2:把“偏好”和“当前约束”分开存

“喜欢什么”和“现在不能做什么”不是一回事。

前者更接近稳定画像,后者更接近短期状态。如果两者混在一个 memory bucket 里,系统在调用时就很容易错判优先级。很多实际错误,不是信息缺失,而是这两类信息没有被区分。


建议 3:不要把长期记忆调用设计成固定 top-k

哪怕暂时做不到完整的 agentic retrieval,也应该增加一个简单的二次检索、查询改写,或者 sufficiency 判断。

因为很多长期问题的第一轮召回,本来就不可能完整。允许系统“先找线索,再继续找”,通常会比盲目扩大 top-k 更有效。


这篇文章提出的问题,会在后续几篇里分别解决

如果把这篇文章当成系列开篇,它真正完成的任务不是给出全部答案,而是把问题空间切开。

后续几篇会分别回应这里提出的几类核心问题:

  • 针对“信息碎片化”,会继续讲如何把对话写成稳定的记忆单元
  • 针对“没有当前状态”,会继续讲长期状态管理、Profile、Constraint 和记忆更新
  • 针对“没有结构”,会继续讲为什么 Memory 不能只是 chunk,也不能只是简单 KV
  • 针对“检索不是推理”,会继续讲 Agentic Retrieval、Sufficiency 和多轮召回闭环
  • 再往后,还会讨论模型是否会逐渐拥有更原生的长期记忆能力

也就是说,这篇文章不是为了停在“指出问题”,而是为了先把问题定义得足够准确。因为很多后续方案之所以看起来无效,不是实现不努力,而是从一开始就把长期记忆误解成了“多轮聊天 RAG”。


结尾:这不是记忆的终点,只是问题的起点

如果把今天很多 Agent 的“记忆”拆开看,会发现它们之所以经常出错,并不是因为完全没保存历史,而是因为保存下来的历史没有被组织成真正可用的长期记忆。

问题不只在检索,也不只在模型。 更深的症结在于:系统还没有建立起稳定的记忆单元、明确的状态层、可维护的结构,以及一条完整的记忆生命周期。

所以,这篇文章真正想说的其实只有一句话:

长期记忆不是一个把聊天记录存起来的问题,而是一个如何把历史转化为当前有效状态的系统问题。

如果把 RAG 看作第一代 AI 记忆方案,那么接下来真正值得关注的,可能是第二代 Memory Engineering: 不再只是“能从历史里搜到什么”,而是“系统如何持续形成、更新、组织和调用记忆”。

如果说过去大家在讨论的是“怎么让模型会做事”,那么接下来真正绕不开的问题,可能是:

怎么让一个会做事的 Agent,真正记住事情。