Skip to content

附录 C 横向对比:几种 agent 记忆的设计 ​

本附录把 letta-code 的 MemFS 和几种常见的 agent 记忆方案放在一起比较。对其他系统只描述其公开的、稳定的设计思路,不涉及具体版本的 API 细节;需要精确信息时请以各项目的官方文档为准。

C.1 比较维度 ​

一个记忆系统可以从下面几个问题来刻画:

  1. 存储介质与单位:数据库字段?向量?文件?一条“记忆”多大?
  2. 谁来写:agent 自己调工具?harness 自动抽取?另一个 agent?
  3. 什么时候写:对话中(hot path)?对话后(background)?
  4. 怎么读:常驻上下文?按需检索?两者结合?
  5. 历史与回滚:能不能看到记忆是怎么演变的?写坏了怎么办?
  6. 约束:格式、大小有没有强制?
  7. 多机与多 agent:怎么同步?怎么隔离?

C.2 四种思路 ​

Letta 服务器(MemGPT 一脉)。 记忆分三层:常驻系统提示的记忆块(agent 用 core_memory_* 一类工具改写),可检索的归档记忆(archival,向量存储里的段落,agent 用工具插入和搜索),以及回忆记忆(recall,对话历史,可搜索)。写入主要由 agent 自己在对话中通过工具完成;Letta 后来也引入了在后台整理记忆的 sleep-time agent。letta-code 的 MemFS 可以看作这套设计的“文件化”:块变成文件、改写工具变成 shell + git,后台整理变成 worktree 里的反思子 agent。

抽取式记忆服务(以 Mem0 为代表)。 harness(而不是 agent)在每轮对话后用一个 LLM 从消息里抽取事实,与已有记忆做相似度比较,决定新增、更新、删除还是忽略;使用时按当前问题检索相关记忆注入上下文。记忆的单位是一条条短事实,存储在向量库(可选图结构)里。它的优势是对 agent 透明、接入简单;代价是没有“常驻层”的概念——没检索到就等于不存在——也没有人类可读、可编辑、可回滚的整体视图。

通用长期存储(以 LangGraph 的 Store 为代表)。 提供一个按命名空间组织的键值存储(值是 JSON 文档,可选语义检索),把“存什么、何时存”留给应用决定;配套的工具包把记忆形成分为对话中(agent 通过工具写)和后台(另一个流程在对话后整理)两种模式,并把“程序性记忆”实现为对提示词本身的优化。它是积木而不是成品:灵活,但每个应用都要自己回答本附录 C.1 的七个问题。

Claude Code 的项目记忆。 以文件为中心:项目里的 CLAUDE.md(以及用户级、本地级的同名文件)在会话开始时进入上下文,团队可以把它提交到代码仓库;用户或 agent 编辑这些文件就是在“改记忆”。较新的版本还有自动记忆:每个项目一个记忆目录,MEMORY.md 作为一行一条的索引常驻上下文,每条记忆一个带 name/description 等 frontmatter 的 Markdown 文件、按需读取——与 MemFS v2 的“根索引 + 带描述的文件 + 按需加载”几乎是同一个思路,只是没有 git 版本控制、hook 校验和后台反思这几层。(本书正是在这样一个会话里写成的,它的记忆目录就在用户主目录下的 .claude/projects/<项目>/memory/。)

C.3 对照表 ​

维度letta-code MemFSLetta 服务器抽取式(Mem0 类)通用存储(LangGraph Store 类)Claude Code 项目记忆
存储git 仓库里的 Markdown数据库(块)+ 向量库(归档)向量库(+ 可选图)命名空间 KV(+ 可选向量)Markdown 文件
单位文件(可大可小)块 / 段落短事实应用定义的文档文件 / 一条记忆一个文件
谁写agent(shell+git)、反思子 agent、memory workeragent(工具)、后台 agentharness 抽取应用决定用户、agent
何时写对话中 + 对话后(后台)对话中 + 后台每轮之后应用决定对话中
怎么读core 常驻;子目录与技能只放索引;recall 检索块常驻;归档、recall 检索检索注入应用决定常驻(CLAUDE.md、索引)+ 按需读文件
历史 / 回滚完整 git 历史,可 diff、revert有限记忆项有更新记录(视实现)视实现依赖用户自己的版本控制
约束hook:frontmatter、索引链、预算、只读块大小上限抽取器决定无无强制
多机git 远端,回合后 push / rebase服务器即真相服务即真相存储即真相CLAUDE.md 随代码仓库同步
多 agent 隔离路径守卫 + 内核沙箱服务端权限按用户 / agent id 分区命名空间按项目目录

C.4 MemFS 的独特取舍 ​

把这些放在一起看,letta-code 的选择很鲜明:

  • 把记忆当代码管。 版本控制、提交前检查、分支隔离、合并、远端同步——软件工程里管理“一群人并发修改的文本”的整套工具,原封不动地拿来管理“一群 agent 并发修改的记忆”。第 16、17 章的并发设计几乎全部建立在 git 的语义上。
  • 让 agent 用通用工具写记忆。 这给了 agent 最大的表达力(可以重组目录、建技能、存图片),也把格式正确性的负担从工具 schema 转移到了 hook 和提示词上。第 6、9、15 章里小模型的种种失误,正是这个取舍的代价;更强的模型和后台反思是它的补偿。
  • 常驻与按需由目录结构表达。 不需要额外的元数据或检索系统来决定“什么常驻”——mv 一下就能升级或降级一条记忆。
  • 对人透明。 记忆就是一堆 Markdown 和一段 git 历史,人可以直接读、改、审。这对一个会“自己改自己”的系统来说,可能是最重要的安全属性。

没有哪种设计在所有维度上占优。如果你的 agent 只需要记住几十条用户偏好,抽取式服务可能最省事;如果你在构建一个会长期演化、需要人类审计、跨机器运行的 agent,MemFS 的这套“把记忆当代码”的思路值得认真考虑。

配套代码:github.com/luxiang0412/mini-letta