一文搞懂 Agent Memory:AI 是如何记住你说过的话的?
一文搞懂 Agent Memory:AI 是如何记住你说过的话的? - Tomorrowland_D
文章从 Context Window 的容量与持久化局限出发,解释 Agent Memory 的基本原理,将记忆分为情景记忆、语义记忆和程序记忆三类。实现形态上区分 Token-level、Latent 和 Parametric 三种记忆,并围绕 Write、Maintain、Retrieve 三个环节展开。
一文搞懂 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 应用采用的是外部记忆机制:
- 从对话或任务中提取重要信息。
- 将信息持久化保存。
- 在后续任务中检索相关记忆。
- 将记忆重新注入模型上下文。
因此,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 可能需要遵循以下规范:
- 阅读相关代码。
- 修改目标文件。
- 运行单元测试。
- 修复测试错误。
- 汇总最终结果。
如果 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 更强调把记忆能力封装为独立服务。
其代表性的设计思路是:
- 从用户对话中提取重要事实。
- 查找相关的已有记忆。
- 根据具体实现执行保存或维护操作。
- 在后续任务中检索相关信息。
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 从一次性对话工具,发展为长期协作系统的重要基础。
来源:博客园 · cnblogs.com