Agent Harness 源码拆解(九):Memory 与扩展——记忆怎么存才不越权,扩展怎么留口才不失控

这是系列的最后一篇。前八章把 harness 的骨架拆了一遍,最后一块拼图是两个”对外”的边界:记忆(agent 记住的东西)和扩展(别人给 agent 加的东西)。它们共享一个危险——都在把外部信息送进 agent 的决策里,处理不好,记忆会越权成命令,扩展会变成绕过权限门的后门。

记忆:它自己必须声明”我不是真相”

grok-build 对记忆的第一条设计原则,直接写进了提示词:“记忆是历史不是真相”,每条记忆还自带日期。为什么?因为模型有个坏习惯——把”曾经记录过的事”当成”现在成立的事”。记忆系统要做的第一件事,就是让它自己声明不可信。

它还有一个工程上值得抄的纪律:两代管线物理隔离,互不读写。v2 记忆和 legacy 记忆不共享文件、不共享搜索、不共享 flush——否则合并逻辑会渗进所有代码路径。v2 的布局是三件套:topics(维护的主题笔记)、observations inbox(新观察的收件箱)、生成的只读索引。

配套的还有 Maka 的一条:目录进提示,正文按需加载。记忆条目只把索引/摘要进系统提示,全文靠工具按需读取——这和工具系统的”默认少、按需开”是同一笔账。

记忆越权的反面案例是 CodeWhale 明确防御的:它的记忆指引教模型把记忆读作偏好,不是命令。给模型任何”可自定义”的层(记忆、风格、人格)时,同时给它”我绝不覆盖什么”的合同——风格层才不会变成行为层。

扩展:进入的是既有收口,不是平行宇宙

CodeWhale 对扩展的立场最鲜明,一句话:扩展进入的是既有收口,不是平行宇宙。MCP(外部工具)、Skills(指令知识)、Plugins(能力打包)三个扩展面,接入点是同一个——同一套工具目录(eager/deferred)、同一套九层审批、同一条 KV-cache 契约。它文档里写得很直白:reviewed 的 plugin 贡献 MCP servers 时,”without creating a second transport or approval system”。

这条的迁移价值极高:扩展面再多,审批、缓存、授权都只有一份实现,审计面不随扩展数量膨胀。反过来,每给扩展开一条”捷径”(绕过审批、绕过缓存、绕过工具目录),就是多一个不受控的后门。

pi 的扩展系统是另一条路线:40+ 个类型化事件 + 一个注册面,扩展用 jiti 运行时加载 TypeScript,不需要编译步骤,内置扩展和外部扩展用同一个 API——“吃自己的狗粮”。它把策略全下放成扩展(权限门、plan mode、沙箱都是扩展),核心只留机制。

代价它自己也诚实标注了:provider_stream_event 每个解析块都触发一次,慢的 handler 真的会拖慢流——文档把代价交给开发者自己判断。还有一个安全默认值得记:tool_call handler 失败了 fail-safe 阻止该工具,坏了就拦,不是坏了就放。

opencode 和 Maka 的两笔

opencode 的”注册即 Scope”用生命周期解决了一个脏问题:工具注册、context source 注册、插件,全部绑定调用者的 Scope,关闭 Scope 自动反注册——“禁用插件/热重载”不需要任何子系统实现反注册逻辑。配套的还有 stale rejection:turn 物化的注册身份在结算时校验,”广告给模型的定义”和”实际执行的实现”必须是同一个。

Maka 贡献的是一条哲学:renderer 不自证。客户端渲染出来的值,不是有效状态的证明——重连不是重放授权,completed 的 todo 不是测试通过的证据,模型自报不能替代 RuntimeEvent。有效状态永远在 Runtime Host,客户端只是投影。

系列收口:六家的共同地基

九章拆下来,六家实现天差地别,但地基是同一块,我把它归结为三条:

  1. 事实与投影分离——事件日志是真相,模型上下文、UI、恢复状态都是投影。这一条决定了你能不能同时拥有激进压缩、完整审计、崩溃恢复。
  2. 核心只留机制,策略下放——pi 最极端(连权限都不内置),但 CodeWhale、grok 也各自把”政策”和”机制”分层。内核里每塞一条策略,就少一种被复用的可能。
  3. 架构纪律的工程化——分层画在文档里三个月就烂,六家用守护测试、棘轮、policy 检查器三种方式,把”守住边界”从自觉变成机制。

还有一条贯穿始终的写作暗线:每个设计都有代价,代价是设计的一部分。pi 的零策略换装配成本,opencode 的 Effect 换不可逆绑定,CodeWhale 的缓存契约换灵活性受限。读源码最大的价值不是看别人多聪明,而是看他们为聪明付出了什么。

这个系列到这里就收尾了。六家的仓库地址都在每篇末尾的参考资料里,我推荐从 pi 的 packages/agent(约 2500 行,读它就是读 agent 语义本身)和 CodeWhale 的 docs/CACHE.md、docs/AUTHORIZATION_ORDER.md 开始,对照着这套笔记读,会快很多。


本篇术语

  • 记忆越权:模型把”记录过的事”当成”现在成立的命令”,记忆系统需声明不可信
  • 收口(existing收口):扩展接入既有审批/缓存/工具目录,而非开平行通道
  • 吃自己的狗粮(dogfooding):内置功能和外置扩展用同一个 API
  • 注册即 Scope:扩展生命周期绑定调用者 Scope,关闭自动反注册
  • stale rejection:结算时校验”广告的定义”和”执行的实现”是否同一
  • renderer 不自证:客户端渲染值不是有效状态证明,权威在 Runtime Host
  • 文件即记忆:AGENTS.md / SKILL.md 作为可 diff、可版本化的记忆载体

参考资料

参照系仓库(结论基于 2026-09 下旬至 10 月上旬各仓库 HEAD):

  1. earendil-works/pi —— extensions/ 40+ 类型化事件与注册面
  2. anomalyco/opencode —— 注册即 Scope 与 stale rejection
  3. xai-org/grok-build —— xai-grok-memory 两代管线与 v2 三件套
  4. zai-org/ZCode
  5. apache/maka —— 目录进提示正文按需加载
  6. Hmbown/CodeWhale —— docs/MCP.md 扩展进入既有收口

Harness 设计方法论文献:

  1. Anthropic,《Agent Harness Design: 3 Patterns for Harnessing Claude’s Intelligence》
  2. Anthropic,《Building agents with the Claude Agent SDK》