数一数你机器上有多少种记忆格式
列出你的编码工具保存它们"记得"的东西的每一个地方。如今一个典型配置:
- 一个
AGENTS.md或CLAUDE.md在大多数仓库里,以及.cursor/rules/*.mdc在少数几个里 - 一个智能体通过 Anthropic 的记忆工具把文件写入一个
/memories目录 - Copilot 把每个仓库的事实保存在 GitHub 那一侧
- 一个记忆 MCP 服务器维护着一个 JSONL 知识图谱
这是四种不同的形态,而它们中没有一个能读取其他的。你的 CI 智能体学到的一课会留在写下它的那个东西里。你的编辑器智能体读不到它,你接下来尝试的下一个工具也读不到。
每种格式单独看都合理。合在一起,它们一次又一次地重建同一个小想法:一条智能体留给未来自己的笔记,存放在某个地址上,在一段时间内为真。
而且这个列表还在不断变长。逛逛 r/ClaudeAI、r/LocalLLaMA 或 r/cursor,你会发现源源不断的"我为我的智能体构建了一个记忆层"的帖子,每一个都有自己的存储、自己的 schema 和自己的 MCP 工具。这有力地证明问题确实存在:人们反复撞上它,撞得足够疼,以至于要动手造点东西。但每一个新方案都多添了一种其他东西读不了的格式。问题不在于缺一个工具。而在于缺一个共识,而这只能靠社区一起努力才能达成。
我构建了这类工具中的一个,LoreKit,它是开源的。这不是在推销说 LoreKit 已经解决了记忆问题。它的格式只是若干提案之一,本身也有缺口。重点在于现在正是就一个共享形态达成共识的时刻,而且另一个领域已经展示了该怎么做。
我们以前见过这一幕
2019 年之前,每个可观测性厂商都发布自己的 agent、自己的埋点库和自己的数据格式。换厂商就意味着要重新给你的代码做埋点。两个开源项目 OpenTracing 和 OpenCensus 试图解决这个问题,结果彼此之间也互相竞争。
2019 年,它们合并成了OpenTelemetry。真正重要的是厂商们同意不再竞争的那些东西:
- 一个数据模型:span、metric 和 log record 分别是什么。
- 语义约定:共享的命名,比如
service.name和http.*。 - 一个协议:OTLP,一种发送数据的方式。
- 参考实现:共享的 SDK 和 Collector。
厂商们继续在它们做的事情上竞争包括数据:存储、查询、分析。用户只需接入一次。我每天都在用 OpenTelemetry,在Dash0,而正是这种共识让整个工具生态能够读取彼此的数据。
智能体记忆正处于可观测性在 2019 年之前的阶段。时机很好:这些格式还很年轻,足以改变,而且智能体标准已经有了一个中立的归属。MCP 和AGENTS.md都隶属于 Linux 基金会的 Agentic AI Foundation。
形态巡览
这些变化很快,所以请把细节当作 2026 年末的快照。
| 家族 | 示例 | 记忆单元 | 寻址方式 | 遗忘 |
|---|---|---|---|---|
| 指令文件 | AGENTS.md、CLAUDE.md、Cursor.mdc规则 | 一整个 Markdown 文件 | 文件路径(外加globs用于 Cursor) | 从不。由人来编辑 |
| 智能体管理的文件 | Anthropic 的记忆工具 | 位于以下路径下的一个文件/memories | 模型选择的路径 | 从不,除非模型将其删除 |
| 托管的仓库事实 | GitHub Copilot Memory | 带代码引用的事实 | 一个仓库 | 闲置 28 天后删除 |
| 上下文块 | Letta 核心记忆 | 一个带字符上限的带标签块limit | 一个label位于智能体上 | 从不。始终在上下文中 |
| 抽取的事实 | Mem0 | 服务从消息中抽取的事实 | user_id/agent_id/run_id/app_id | 可选的过期日期 |
| 命名空间存储 | LangGraphBaseStore | 一个 JSONvalue字典 | 一个namespace元组 +key | 可选的 TTL,在条目被读取时重置(默认行为) |
| 知识图谱 | MCP 参考记忆服务器 | 实体、关系、观察 | 实体名称 | 从不 |
| 时序图 | Graphiti / Zep | 图边上的一条事实 | 实体 + 边 | 事实被置为无效而非删除,基于两条时间线 |
| 寻址记录 | LoreKit | 一条带作用域、键和生命周期的记录 | 一个作用域字符串 +key | 从不,除非设置了 TTL |
其中一些做对的地方,值得共享规范保留。Copilot Memory把可对照代码核验的引用与默认遗忘结合起来,尽管它被锁在一个产品内部。LangGraph展示了核心可以有多小:put(namespace, key, value)。Graphiti正确地建模了时间,为事实何时为真和何时被记录分别设置了时间线。而AGENTS.md表明,位于已知路径的普通文件可以成为标准。
已经存在的提案
已经有人开始做这件事了。MacPaw Research 的Portable Memory是一个.membundle 具备字节级可复现的序列化、删除墓碑和可选签名;其作者表示它尚未被广泛采用。这个Open Memory Protocol是 2026 年 4 月的一份草案,用于以带清单的 ZIP 形式在平台之间迁移对话以及由对话派生出的记忆。Cognee 的COGX格式可从 Mem0、Letta 和 Zep 导入。
这些主要解决的是导出:把一个人的记忆从厂商 A 迁移到厂商 B。编码工具还有第二个尚未解决的问题:实时寻址。当一个 CI 任务、一个编辑器智能体和一个评审机器人同时在同一仓库中工作时,它们如何读写同一个位置,并就其含义达成一致?一份完整的规范需要两者兼备。
剥去品牌包装,每种格式对同样四个问题的回答各不相同:在哪里一条记忆为真,它的身份是什么(第二次写入是更新它还是复制它?),它说了什么,以及它何时不再为真。没有人否认这些很重要。工具们只是在答案上存在分歧,OpenTelemetry 最初也是如此。
有一个真正的分叉点:谁来写记忆。在指令文件中,是人。在 memory 工具、Letta 和 LoreKit 中,是模型。在 Mem0 和 Graphiti 中,由服务从对话中提取事实。规范不需要选定其中一种。它需要记录是哪一种,这样读者就知道该在多大程度上信任所读到的内容。
下面大致展示一条记录作为文件可能是什么样子。它用于说明数据模型;字段名并非提案:
---
spec:agent-memory/0.1
id:8f0c2a6e-4b1d-4c7a-9e2f-3a5b6c7d8e9f
address:{level:repo,value:github.com/acme/checkout}
key:tests-need-local-postgres
kind:lesson
written_by:{type:agent,name:claude-code}
content_type:text/markdown
lifecycle:{expires_at:null,extended_by:write}
attributes:{vcs.pr:482,ci.run_url:"https://ci.example/runs/123"}
---
集成测试会失败并报`ECONNREFUSED 127.0.0.1:5432`,除非 Postgres
已经在运行。在`pnpm test`之前启动它:
docker compose up -d db
测试环境不会替你启动它。
frontmatter 就是信封:address以及key说明它在何处为真,id是它的身份,lifecycle说明它何时停止,以及written_by回答分叉问题。其下方的 Markdown 就是记忆本身,而content_type告诉读者如何对待它。工具需要的其他任何内容都放在attributes中,置于其他工具可以忽略的命名空间下。同一条记录同样可以很好地序列化为 JSON,供想要通过网络传输它的工具使用。
围绕这条记录,一份规范会镜像 OpenTelemetry 的分层:
- 约定:地址层级的共享名称(
global,project,repo,branch,以及 monorepo 所需的任何内容),种类的共享名称,以及属性命名空间的共享名称(vcs.*,ci.*,agent.*),放在一个带版本的注册表中。 - 契约:若干操作(写入、读取、列出、搜索、归档),具有固定的输入和输出,通过 MCP 暴露。许多记忆服务器现在都提供 MCP 接口,但每个暴露的工具不同、含义也不同。
- 一致性测试取代参考实现:对一条记录做往返测试并检查没有丢失任何内容,检查未知属性在重写后仍然保留,检查过期行为与所述一致。
哪些留在外面同样重要:存储、排序、嵌入、用户界面。那才是工具应该竞争的地方。规范应该放在某个中立的地方,而不是 LoreKit 的仓库或任何单一厂商的仓库里。
怀疑者会怎么说
“你做了一个记忆工具,所以你当然想要一个照着它形状做的标准。”有道理。这正是 LoreKit 在表中只是一行、而不是模板的原因。如果一份共享规范看起来不一样,LoreKit 也应该照样采纳它。
“MCP 已经是标准了。”MCP 标准化的是调用,而不是记录。OpenTelemetry 需要一个协议和一个数据模型。记忆两者都需要。
“共享记忆是一条提示注入通道。”是的。智能体读到的任何东西都能操纵它,而共享记忆扩大了谁能写入它。规范应该让这一点可见:记录每条记忆是谁写的,允许签名(Portable Memory 已经这样做了),并让一条记录能指向它所依赖的代码,以便读者检查那段代码是否发生了变化。没有任何格式能让投毒变得不可能。
“又一个标准不会解决碎片化。”那就是xkcd 927,而且它是最有力的反对意见。我的回答是 OpenTelemetry 式的:共识是在现有项目合并而不是在别人又加了一条的时候。这里的工作是一样的:把现有提案和工具各自做对的部分拿出来,就它们共有的部分达成一致。
悬而未决的问题
我不知道这些问题的答案,我更愿意公开地把它们弄清楚:
- 哪些地址层级?Monorepo 想要一个介于
repo和branch之间的层级。层级应该是一个固定列表还是约定? - 遗忘应该是默认行为吗?Copilot 默认遗忘,LoreKit 不会,而 LangGraph 在读取时延长生命周期。
- 记录是否应该指向它所依赖的代码?这是防止记忆过时的最佳保护,但它会把记录绑定到某个代码托管平台。
- 谁来协调?一个工作组、一个基金会,还是一份人们向其提交变更的规范草案?
如果你构建了表格中的任何工具,或者撰写了其中某份提案,我想和你交流一下。LoreKit 的 schema 和磁盘格式以 MIT 许可证发布,作为一个具体的输入。要查看真实记录,LoreKit 的离线存储会写出纯 Markdown 文件,你可以打开、grep 和 diff:
npx@lorekit/cliinstall
把它们与你的其他工具写出的内容进行比较,然后告诉我,一个共享格式需要具备哪些它们目前都还没有的东西。