随笔
Claude Code 源码解读 06:Memory 不是玄学记忆,而是有边界的输入
区分 memory prompt、项目规则、relevant memory、nested memory 和 session memory,说明长期经验如何被边界化地带入当前任务。
Memory 不是“模型记住了我”,而是不同类型的记忆怎样被条件化、去重、异步预取、路径触发和权限收缩。
快速了解
- Memory 不是模型人格化地记住一切,而是不同来源的长期信息按条件进入当前任务。
- CLAUDE.md、memory prompt、relevant memory、nested memory、session memory 不是同一类东西。
- relevant memory 是异步预取,不阻塞当前 turn,也不是实时反馈。
- session memory 后台写入要收缩工具权限,避免记忆机制变成自我修改风险。
如果只想快速理解,可以先读这一节;如果要看源码机制,再往下看“主线与场景插入分类”和机制图。
设问与回应
| 设问 | 回应 |
|---|---|
loadMemoryPrompt() 注入的是完整记忆,还是 memory 机制说明? | loadMemoryPrompt() 注入的重点不是完整记忆内容,而是 memory 机制说明和进入 memory 流程的前缀支撑;真正的记忆材料会按条件、路径和来源分别进入。 |
| CLAUDE.md / rules 和 auto memory 的可信度是否一样? | CLAUDE.md / rules 和 auto memory 的可信度不一样。项目规则来自当前仓库上下文,auto memory 更像跨任务经验,必须区分来源、作用域和新鲜度,不能混成同一种“记忆”。 |
| relevant memory 是同步阻塞当前 turn,还是异步预取后以附件进入? | relevant memory 不是同步阻塞当前 turn 的实时反馈,而是异步预取后以附件形式进入。它服务上下文增强,但不应该拖住主链路推进。 |
| session memory 后台写入为什么要收缩工具权限? | session memory 后台写入必须收缩工具权限,因为写记忆本质上是在修改未来上下文。若不限制可用工具和目标文件,记忆机制会变成高风险的自我修改通道。 |
主线与场景插入分类
| 机制/模块 | 分类 | 我保留的判断 |
|---|---|---|
loadMemoryPrompt() | 场景插入 + 主线前缀支撑 | 只有 auto memory 或 SDK 自定义 memory path 等条件满足时注入;它不是完整记忆内容 |
startRelevantMemoryPrefetch() | 场景插入 + 恢复支撑 | 异步预取,不阻塞当前 turn,也不是动态运行反馈 |
filterDuplicateMemoryAttachments() | 主线支撑 | 避免已经读取或 surfaced 的 memory 重复注入 |
nestedMemoryAttachmentTriggers | 场景插入 | 由文件访问路径触发目录级规则加载 |
createMemoryFileCanUseTool() | 安全/治理横切 | session memory forked agent 只能 Edit 指定 memory 文件 |
Memory 的专业判断
Memory 的价值不是“越多越好”,而是“进入当前任务时有边界”。relevant memory 如果没有体积边界,会变成长期上下文污染;nested memory 如果没有路径触发,会变成全局规则噪声。
从 Codex 差异拆解 Memory 设计
Codex 的差异价值,不是拿来问“有没有记忆”,而是帮助拆开 Memory 这个容易被说虚的机制:一类材料服务恢复,一类材料服务压缩,一类材料服务跨任务经验,一类材料服务当前仓库约束。它们都可能进入模型上下文,但工程语义不能混在一起。
所以我会把同一个 Memory 问题拆成四个检查点:来源是否可追溯,作用域是否受当前项目/目录/会话约束,进入上下文的时机是否清楚,写回记忆的工具权限是否被收缩。Claude Code 的 CLAUDE.md、memory prompt、relevant memory、nested memory、session memory 分别落在不同位置;Codex 侧则适合继续观察 compact、resume、AGENTS 规则和 session summary 是否把这些材料维持为不同层。这个对比带来的设计理解是:优秀 agent harness 的记忆层不是“更长的上下文”,而是有来源、有作用域、有新鲜度、有写入边界的输入治理系统。