MyPrototypeWhat

ContextChef (5):Core Memory——读取零成本,写入结构化

English version: ContextChef (5): Core Memory — Zero-Cost Reads, Structured Writes

Agent 对用户说”我记得你之前提过更喜欢 TypeScript strict mode”。用户觉得这个产品真的在记事。下次会话,Agent 又问了一遍。

这不是记忆问题,是持久化问题——信息有了,没有活过 session 边界。

记忆不是 RAG

解决记忆问题的第一反应通常是向量数据库:把对话存进去,每次检索相关片段注入上下文。Letta(MemGPT 的继任者)在他们的 Context Engineering 指南 里专门写了一篇 RAG is not Agent Memory 来反驳这个思路。

区别在于访问模式:RAG 的访问是概率性的——当前 query 必须和记忆内容在语义上足够接近,才能召回。但用户的编程语言偏好、项目约定、AI 的角色设定,不应该依赖”这轮对话恰好和它语义相近”才能出现。这些信息应该每次都在,无条件注入。

Letta 把这类信息称为 memory blocks:上下文窗口中的预留区域,有固定的大小上限,由系统自动注入,而不是按需检索。Anthropic 在 Claude Code 里用的是 structured note-taking,让 Agent 维护一个持久化笔记文件,每次上下文重置后先读取笔记再继续工作——他们举的例子是 Claude 玩《精灵宝可梦》:数千步游戏之后,Agent 通过笔记记住了探索过的地图、升级进度、有效的战斗策略,没有这些笔记就完全无法维持长程策略。

设计角度:读取零成本,写入结构化

Core Memory 的设计核心是一个简单的原则:读取应该是零成本的,写入应该是结构化的

读取零成本是指:core memory 的内容在每次 compile() 时自动注入到上下文,开发者不需要在每个 Agent 循环里手动 fetch 记忆、手动拼接到消息里。这件事库来做。好处是:你不会因为忘记写 inject memory 就让模型失忆;记忆的注入位置也是固定的(system prompt 之后、历史消息之前),不会因为开发者各自的拼装方式不同而导致注入位置不稳定。

写入结构化是指:记忆不是通过在消息里堆自由文本实现的,而是通过有明确语义的键值对。这带来两个好处:一是记忆内容可以被程序精确操作(覆盖、删除、查询),不依赖从大段文本里解析;二是注入时生成的 XML 格式(<core_memory><entry key="...">...</entry></core_memory>)对 LLM 的结构理解更友好,比自由文本更稳定。

存储后端可插拔是这个设计带来的额外优势。InMemoryStore 用于测试和快速原型,VFSMemoryStore 用于生产持久化,你也可以实现自定义的 MemoryStore 接口对接 Redis 或数据库。切换存储后端不需要改任何业务逻辑,因为读写记忆的接口是统一的,存储实现被隔离在外。

缩小模型的决策面,而不是消除它

在设计记忆系统时有一个容易踩的陷阱:让模型决定某条信息应该放进”核心记忆”还是”归档记忆”。

MemGPT 把两个 tier 暴露为命名不同的工具——core_memory_replacearchival_memory_insert,通过工具描述引导模型做分类,同时给 core memory 设了硬字符上限,满了就写不进去,逼模型思考”这条信息真的需要一直在吗”。这是一种有效的缓解,但本质上还是在用 prompt 和工具描述引导 LLM 分类,模型选错层级的可能性依然存在,而且这类错误极难复现和调试。

公平地说,ContextChef 也没有从根本上解决这个问题——inline 模式和 tool 模式下,模型仍然在决定”要不要写”、“写什么内容”。ContextChef 做的是缩小模型需要决策的范围:tier 由调用路径固定,模型只需要决定写不写,不需要判断层级。这把一个难以观察的分类决策(“core 还是 archive?“)变成了一个可预测的行为——写进来的,永远是 core。代价是灵活性:如果你需要模型自主决定分层,这个设计不适合你。

具体来说:模型通过 <update_core_memory> XML 标签或 core_memory_update 工具写入的,永远是 core;开发者通过 chef.memory().set() 写入的,默认也是 core。接口设计本身锁死了层级,不留给模型选择的余地。

Inline 与 Tool:两种写入协议覆盖不同集成需求

Core Memory 有两种写入模式,不是为了提供选择而提供选择,而是因为两类集成场景各有约束。

Inline 模式针对的是响应延迟敏感的场景:模型在正常响应文本里嵌入 XML 标签来更新记忆,不需要额外的工具调用轮次。开发者收到响应后调用 extractAndApply() 解析并写入,然后清理标签再展示给用户。流程简单,但模型的输出混合了内容和操作,需要后处理。

Tool 模式针对的是工具调用密集、响应格式严格的场景:记忆更新通过专用工具(core_memory_updatecore_memory_delete)进行,结构上和业务工具调用一致,不需要后处理,但每次更新多一轮工具调用的延迟。

两种模式下读取方式完全相同——compile() 自动注入,模型直接看见,不需要任何工具调用。选择写入模式不影响读取,可以根据项目的延迟和格式要求自由切换。


下一篇:Snapshot & Restore——Manus 说要保留错误记录,但有时候你就是需要撤回。