一文搞懂 Agent Memory:AI 是如何记住你说过的话的?

一文搞懂 Agent Memory:AI 是如何记住你说过的话的?

为什么 AI Agent 能完成复杂任务,却记不住昨天与你讨论过的事情?本文从 Context Window 出发,介绍 Agent Memory 的基本原理、记忆分类、实现机制,以及 Mem0、Letta、Claude Code 等主流方案。

一、为什么 Agent 需要记忆?

假设你正在使用一个 AI 编程助手开发项目。

第一次使用时,你告诉它:

  • 项目使用 TypeScript。
  • 测试框架是 Vitest。
  • 包管理器使用 pnpm。
  • 部署平台是 Cloudflare Workers。

经过半小时的交流,Agent 已经熟悉了这些信息,能够按照项目规范完成任务。

但当你关闭终端,第二天重新开启一个全新会话时,它可能又不知道项目使用什么技术栈,也不清楚之前做过哪些决策。

你不得不重新介绍一遍。

问题不在于模型不够聪明,而在于历史信息没有被有效保存和复用。

1. Context Window 的局限

要理解 Agent Memory,首先需要理解 Context Window(上下文窗口)。

Context Window 是模型单次推理能够处理的上下文范围。

对于一个典型的 Agent 系统,上下文通常包含:

  • System Prompt:系统指令。
  • Conversation History:历史对话。
  • Tool Definitions:工具定义。
  • Tool Results:工具执行结果。
  • External Context:检索到的文档或其他外部信息。

这些信息共同占用 Context Window。

它存在两个明显的限制:

第一,容量有限。

即使模型支持几十万甚至上百万 Token,也不意味着可以无限保存历史信息。

复杂任务中的代码文件、工具调用记录和执行日志,会迅速消耗上下文空间。

第二,Context Window 本身不负责持久化。

如果应用没有保存历史信息,也没有在新会话中重新加载,模型就无法直接利用上一轮会话的内容。

因此,Agent 需要一种独立于当前上下文的长期信息管理机制。

这就是 Agent Memory(智能体记忆系统)。

2. Memory 到底是什么?

一句话概括:

Agent Memory 是让智能体能够保存、更新并按需利用历史信息的一套机制。

需要注意,这并不意味着模型的权重发生了变化。

大多数 Agent 应用采用的是外部记忆机制:

  1. 从对话或任务中提取重要信息。
  2. 将信息持久化保存。
  3. 在后续任务中检索相关记忆。
  4. 将记忆重新注入模型上下文。

因此,Memory 并不是让 Context Window 变得无限大,而是让 Agent 能够有选择地利用历史信息。

二、Agent 需要记住什么?

Agent Memory 的分类借鉴了认知科学中的记忆概念。

从功能上,可以理解为三种常见类型。

1. 情景记忆(Episodic Memory):发生过什么?

假设你使用 Agent 排查一个数据库 Bug。

Agent 最初怀疑 SQL 查询存在问题,但排查后发现,真正原因是数据库连接池耗尽。

如果 Agent 保存了这段经历,下次遇到类似问题时,就可以参考过去的排查过程。

这就是情景记忆。

它主要保存:

  • 历史任务。
  • 对话记录。
  • 工具调用轨迹。
  • 执行结果。
  • 成功经验和失败教训。

核心价值:让 Agent 能够利用过去发生的事情。

2. 语义记忆(Semantic Memory):什么是事实?

语义记忆保存的是相对稳定的事实和知识。

例如:

  • 用户偏好简洁回答。
  • 项目使用 TypeScript。
  • 测试框架是 Vitest。
  • 数据库使用 PostgreSQL。

这些信息不依赖某一次具体事件,即使开启新会话,仍然可能有用。

因此,语义记忆可以理解为 Agent 对用户、项目和环境的长期认知。

3. 程序记忆(Procedural Memory):应该怎么做?

程序记忆关注可复用的操作步骤和执行策略。

例如,一个编程 Agent 可能需要遵循以下规范:

  1. 阅读相关代码。
  2. 修改目标文件。
  3. 运行单元测试。
  4. 修复测试错误。
  5. 汇总最终结果。

如果 Agent 能够保存并复用这套流程,就可以减少重复规划的成本。

需要注意,保存工作流不等于模型真正学会了一项新能力,而是系统通过外部信息帮助 Agent 重复使用既有方法。

4. 三类记忆对比

记忆类型 回答的问题 典型内容
情景记忆 发生过什么? 历史任务、执行轨迹、任务结果
语义记忆 什么是事实? 用户偏好、项目配置、领域知识
程序记忆 应该怎么做? 工作流、操作规范、调试策略

这三类不是互斥的。

例如,"上次测试失败是因为 Redis 没有启动,今后测试前应检查 Redis",既包含情景记忆,也包含程序记忆。

一个成熟的 Agent 可以同时利用不同类型的记忆。

三、Agent 的记忆存在哪里?

记忆的功能分类解决了"记什么"的问题。

接下来需要解决的是:记忆究竟存在哪里?

综述论文《Memory in the Age of AI Agents》从实现形态上区分了三个主要方向。

1. Token-level Memory:外部文本记忆

这是目前普通 Agent 应用开发最值得关注的方案。

核心思路是:

将记忆表示为可读取的内容,保存在外部存储中,需要时重新放进 Prompt。

例如:

用户告诉 Agent:

这个项目使用 TypeScript,测试框架是 Vitest。

系统可以提取两条记忆:

  • 项目编程语言:TypeScript。
  • 项目测试框架:Vitest。

随后保存到 Markdown 文件、SQLite 或向量数据库中。

下一次用户要求:

帮我给登录模块添加测试。

Agent 就可以读取相关记忆,得知应该使用 Vitest。

整个过程不需要修改模型参数。

Token-level Memory 还可以采用不同的数据组织结构:

  • 扁平结构:每条记忆独立存储,通过关键词或向量检索。
  • 图结构:通过实体与关系连接不同记忆,适合部分多跳查询。
  • 层级结构:按照主题和粒度组织记忆,例如项目摘要、模块信息、具体事件。

对于初学者和小型 Agent,通常建议从简单的文件或扁平存储开始。

2. Latent Memory:模型内部状态记忆

另一种研究方向,是利用模型的内部状态保存或复用信息。

例如:

  • KV Cache 复用。
  • 历史状态压缩。
  • 学习得到的隐式记忆表示。

这类方法通常需要访问模型的底层推理机制。

对于使用商业 LLM API 的开发者,往往无法任意读取或修改模型内部状态,因此不适合作为普通 Agent 的首选记忆方案。

3. Parametric Memory:模型参数记忆

第三种方式是通过训练,把知识或行为模式编码到模型参数中。

例如:

  • Fine-tuning。
  • LoRA。
  • 模型知识编辑。

它适合领域适配和模型行为调整,但不太适合频繁更新的项目配置或用户偏好。

毕竟,当用户把数据库从 PostgreSQL 换成 MySQL 时,没有必要专门微调一次模型。

结论:如果你正在使用 OpenAI、Anthropic 等商业模型 API 开发 Agent,优先掌握 Token-level Memory 就足够了。

四、Memory 是如何运转的?

存储只是第一步。

真正的记忆系统,还必须解决三个问题:

什么值得记住?已有记忆如何更新?什么时候应该回忆?

这对应 Memory 的三个核心环节:

1. Write:记忆写入

并不是所有对话都值得进入长期记忆。

例如:

今天天气不错。

对于编程 Agent,这通常没有长期保存价值。

但如果用户说:

以后这个项目统一使用 pnpm,不再使用 npm。

这条信息就值得保存。

常见的写入方法有三种:

摘要式写入(Summarization)

把一段长对话压缩成简短摘要。

适合保存历史背景、重要决策和任务过程,但可能丢失细节。

提取式写入(Extraction)

从对话中提取独立的事实。

例如:

  • 包管理器:pnpm。
  • 测试框架:Vitest。

这种方式便于精确更新和检索,但依赖信息提取的准确性。

结构化写入(Structured Writing)

将信息组织成具有明确字段或关联的数据,例如实体、属性、时间戳和来源。

它更适合复杂记忆,但实现成本也更高。

实际工程中,可以把摘要和事实提取结合起来。

2. Maintain:记忆维护

记忆不是写进去就永远不变。

一个完整的记忆系统至少需要支持:

合并(Merge)

例如:

  • 用户喜欢简洁回答。
  • 用户偏好精简回复。

两条记忆内容相似,可以合并。

更新(Update)

例如:

我们已经从 PostgreSQL 迁移到 MySQL。

系统应该将当前数据库配置更新为 MySQL,而不是继续使用旧信息。

必要时,还可以保留历史版本和生效时间。

遗忘(Forget)

临时任务、过期配置、重复日志和用户要求删除的信息,不应该无限积累。

不过,不能简单根据访问频率判断记忆价值。

有些重要知识可能很久才使用一次。

3. Retrieve:记忆检索

记忆保存得再好,如果需要的时候找不到,也没有意义。

假设系统保存了一条信息:

项目使用 JWT 进行身份认证,认证逻辑位于 auth.ts。

用户询问:

我们之前的登录验证是怎么做的?

问题中没有直接出现"JWT"或"身份认证"。

如果只依靠关键词匹配,就可能漏掉相关信息。

因此,记忆检索通常采用几种方法:

  • BM25:关键词检索,适合文件名、函数名和专有术语。
  • Embedding:语义检索,适合理解不同表达之间的语义联系。
  • Hybrid Search:混合检索,结合关键词和语义匹配。
  • Reranking:对检索结果重新排序,筛选最相关的记忆。

此外,还可以利用查询改写,让用户问题更容易匹配存储中的记忆。

但要注意:

不是检索出的记忆越多越好,而是越相关、越准确越好。

大量无关记忆进入 Context Window,可能反而干扰模型判断。

五、主流 Agent 是怎么实现 Memory 的?

理解了基本原理,再来看三个具有代表性的方案。

1. MemGPT / Letta:让 Agent 自主管理记忆

MemGPT 提出了一个直观的类比:

Context Window 类似计算机 RAM,外部存储类似磁盘。

Agent 可以在两者之间管理和交换信息。

经典 MemGPT 架构包含三个重要概念:

  • Core Memory:持续存在于上下文中的重要信息。
  • Recall Memory:可检索的历史对话。
  • Archival Memory:更大规模的长期信息存储。

Letta 延续并发展了这种设计理念。

其核心特点是让 Agent 参与记忆管理,例如通过工具读取、修改或维护相关记忆。

优势是灵活,缺点是记忆管理的质量会受到 Agent 决策能力的影响。

2. Mem0:自动化记忆管理

Mem0 更强调把记忆能力封装为独立服务。

其代表性的设计思路是:

  1. 从用户对话中提取重要事实。
  2. 查找相关的已有记忆。
  3. 根据具体实现执行保存或维护操作。
  4. 在后续任务中检索相关信息。

Mem0 的能力和更新策略会随版本变化;例如,早期自动更新流程与部分新版实现并不完全相同。

此外,Mem0 也探索了结合图结构表达实体关系的方案。

它比较适合需要为产品增加用户长期记忆能力的场景。

3. Claude Code:基于文件系统的记忆

Claude Code 展示了一种更加直观的实现方式。

它主要使用两类机制。

CLAUDE.md:持久化指令

例如:

  • ~/.claude/CLAUDE.md:用户级指令。
  • 项目根目录的 CLAUDE.md:项目级规范。

这些文件可以保存技术栈、代码规范和开发约定。

Auto Memory:自动积累长期信息

Claude Code 还可以将部分经验和知识保存到独立的 Markdown 文件中,并利用 MEMORY.md 作为索引。

会话开始时可以加载索引中的部分内容,详细记忆则按需读取。

这种方式的优势非常明显:

  • 透明,用户可以直接阅读。
  • 简单,不必引入复杂数据库。
  • 易于编辑和维护。
  • 与开发者的文件系统工作流契合。

不过,当记忆数量很大、关系复杂时,纯文件组织也可能遇到检索效率和维护成本问题。

4. 三种方案对比

方案 核心理念 主要特点
MemGPT / Letta Agent 管理记忆 灵活、强调 Agent 自主性
Mem0 独立的记忆管理能力 自动化提取、存储与检索
Claude Code 文件系统记忆 简单、透明、易于维护

它们并不是严格互斥的方案,而是从不同角度解决长期记忆问题。

六、如何实现一个简单的 Agent Memory?

如果现在要给自己的 Agent 增加记忆能力,没有必要一开始就引入向量数据库和知识图谱。

可以先构建一个最小可用版本。

第一步:使用 Markdown 保存记忆

例如:

复制代码
memory/
├── MEMORY.md
├── project.md
├── preferences.md
└── experiences.md

其中:

  • MEMORY.md:记忆索引。
  • project.md:项目配置和技术规范。
  • preferences.md:用户偏好。
  • experiences.md:历史任务经验。

第二步:为 Agent 提供记忆工具

可以通过 Function Calling 定义几个工具:

工具 作用
save_memory 保存新记忆
search_memory 搜索已有记忆
update_memory 更新已有记忆
delete_memory 删除指定记忆

例如,用户说:

以后项目统一使用 pnpm。

Agent 可以调用 save_memory,将这一信息写入项目记忆。

第三步:按需读取记忆

每次开启新会话时,可以先加载少量重要记忆或记忆索引。

当任务需要更多历史信息时,再调用 search_memory 查找对应内容。

例如:

用户要求:

帮我修改登录模块,并执行测试。

Agent 可以先检索项目测试规范,得知应该执行 pnpm test,随后继续完成任务。

第四步:定期维护

任务完成后,根据需要执行:

  • 重复记忆合并。
  • 过期记忆更新。
  • 无效记忆删除。
  • 重要经验保存。

实际部署时,还应考虑用户权限、信息来源和隐私保护,避免把不可信的外部内容直接当成高优先级指令。

这样,一个最小可用的 Agent Memory 系统就基本形成了。

等实际遇到检索瓶颈时,再考虑加入 Embedding、BM25、向量数据库或图结构。

七、思考与总结

1. Memory 和 RAG 是一回事吗?

不是,但它们存在很大的技术重叠。

RAG(Retrieval-Augmented Generation)强调从外部知识源检索信息,增强模型的回答能力。

Memory 则更关注信息如何产生、保存、更新,以及如何在未来任务中持续复用。

例如:

  • RAG:查询 PostgreSQL 的官方文档。
  • Memory:记住当前项目使用 PostgreSQL,以及之前为什么选择它。

两者都可以使用向量检索、BM25 和 Reranking。

RAG 可以作为 Memory 的检索技术基础,但 Memory 不只是检索,还包括写入和维护。

2. 有了 Memory,模型就能持续学习了吗?

需要区分两种情况。

一种是系统层面的经验积累:Agent 保存过去的任务经验,在未来重新利用。

另一种是模型层面的学习:通过训练更新模型参数,使模型自身的行为或能力发生变化。

大多数 Agent Memory 系统主要实现前者。

它能够改善 Agent 的信息连续性,但不代表模型参数发生了更新。

3. Memory 越多越好吗?

不一定。

记忆越多,可能带来的问题也越多:

  • 过时信息干扰决策。
  • 不同记忆之间产生冲突。
  • 检索结果包含大量噪声。
  • 上下文和检索成本增加。

因此,一个优秀的记忆系统并不是无限保存所有信息。

它真正需要解决的是:

什么值得记住,什么时候应该忘记,以及在什么任务中应该回忆什么。

总结

理解 Agent Memory,只需要抓住三条主线:

第一,记什么?

情景记忆保存历史事件,语义记忆保存事实,程序记忆保存可复用的方法。

第二,存在哪里?

对于普通 Agent 应用,Token-level Memory 是最实用的起点,可以通过文件或数据库持久化保存。

第三,如何运转?

围绕 Write、Maintain、Retrieve 建立完整的记忆生命周期。

MemGPT / Letta、Mem0、Claude Code 分别展示了 Agent 自主管理、自动化记忆服务和文件系统记忆等不同工程路线。

最终,Agent Memory 要解决的并不是让模型拥有无限上下文,而是让它在有限的 Context Window 中,持续利用最有价值的历史信息。

Context Window 决定模型当前能看到什么,Memory 则帮助 Agent 决定哪些过去的信息值得在此刻重新出现。

这也是 Agent 从一次性对话工具,发展为长期协作系统的重要基础。