文件记忆和 RAG 谁更好?——一个还没有证据的问题
本课一问:编码 agent 的记忆,是写成文件整份注入好,还是做成检索(RAG)、每次按需找几条好?
这一课先不碰:向量检索本身的算法(不在本课程范围);也不给「谁更好」的结论——因为没有证据。这一课练的是:没有证据的时候,还能说清什么。
先说证据:零
本课程的调研档案盘点过这个问题(A 报告 U7):
- 「文件式记忆 vs RAG」:没有任何比较性证据。Claude Code 官方的 agent-loop 文档只描述了文件式这一侧(CLAUDE.md 每个请求重注入并被缓存),没有和检索式做过对比。
- 「repo map / tree-sitter vs grep-first」同样是零;「Claude Code 是 grep-first」这句流传很广的话,没有找到官方直证,已从讲义里排除。
所以下面所有的比较都是设计维度,不是效果结论。
证据状态:无比较证据。没有一份公开材料在同一批编码任务上,用同一个模型,对比过「文件整份注入」与「检索式注入」的成功率或成本。看到「RAG 记忆让 agent 更聪明」或「文件记忆完胜 RAG」这类说法,先问它比的是什么、在哪些任务上、谁测的。
能讲清的:四个设计维度
Birgitta Böckeler 在《Context Engineering for Coding Agents》(2026-02-05)里给过一个好用的切法:谁决定加载这段上下文——模型(不确定它会不会在该加载的时候加载)、人(可控但不自动)、还是 agent 软件本身(在确定的时刻触发)。再加上本章前两课的三个问题,就能把几种做法放进同一张表:
| 做法 | 谁决定加载 | 什么时候注入 | 注入到哪 | 前缀缓存 | 真实例子 |
|---|---|---|---|---|---|
| 冻结快照(整份) | agent 软件 | 会话开始一次;压缩重建时再读 | system | 会话内不变 | Hermes MEMORY.md / USER.md;Claude Code 的 auto memory;本课项目 frozen 模式 |
| 让模型从目录里挑 | 模型(另花一次调用) | 每次用户发话 | system(每次发话重建) | 两次发话之间可能变 | learn-claude-code s09 |
| 外部 provider 每轮预取 | agent 软件取、provider 决定返回什么 | 每次用户发话 | 当轮 user 消息的发送副本 | 不动 system 与之前的历史 | Hermes 的外部记忆插件(默认关闭) |
| 按需读取正文 | 模型 | 用到时 | 工具结果 / user 消息 | 追加在末尾 | 第 3 课的 skills |
表里第四列「注入到哪」决定了第五列。第 2 课的真实数字就是「注入到 system、会话中途变了」的代价:刷新组第 7 轮,2,300 token 只命中 294。任何每轮都可能不同的内容(检索结果、按查询挑出的记忆),如果放进 system,就会在每次变化时付这个代价。
源码里的第二种:让模型挑
learn-claude-code s09 在每次用户发话时,把「记忆目录」(每条一行:名字 - 描述)交给模型,让它返回相关条目的序号,最多 5 条;挑出来的原文合计不超过 20,000 字符,拼进这一次发话的 system:
它是「选择式」注入,但选择靠的是模型读目录,不是 embedding 相似度——调研档案的勘误(L12)专门写明:它和 Hermes 冻结快照一样,都不是向量 RAG。
源码里的第三种:每轮预取,只拼进当轮的 user 消息
Hermes 的内置记忆是冻结快照(第 2 课)。它另外留了一个外部记忆 provider 的插件接口,配置里默认为空:
开了之后,每次用户发话,Hermes 先按这句话向 provider 预取,把结果拼到这一轮 user 消息的发送副本后面——不进 system,也不改之前的任何消息;并且把发出去的原样字节存下来,以后每一轮重放同样的字节:
这是一个值得记住的设计:每轮都可能变的内容,放在会变的位置(当轮消息),而且一旦发出就冻结。它不回答「检索式记忆好不好」,只回答「如果要用,怎么用才不打穿缓存」。
「谁在用」不是证据。Claude Code 官方文档说明了它怎么做,没有说明为什么比检索式更好,也没有公开对比数据。
常见误解二:「RAG 一定更先进——文件整份注入太原始。」同样没有证据。冻结快照小(Hermes 两个文件合计 3,575 字符上限)、确定、对缓存友好;检索式能装下更多,但加载与否取决于检索或模型的判断。哪边在编码任务上更好,没人测过。
常见误解三:「Hermes 的记忆就是 RAG。」错,这是本课程的事实红线。Hermes 内置记忆是会话开始注入一次的冻结快照;外部 provider 是默认关闭的可选插件,即使打开,也不能把它说成「Hermes 的记忆会自动检索」。
证据三问
| 问 | 本课的回答 |
|---|---|
| ① 它解决什么问题? | 记忆多到不能整份注入时,只放一部分进上下文 |
| ② 为什么可能有效? | 设计维度能说清各自的取舍:谁决定、什么时候、放在哪、缓存代价 证据等级 · 有理论动机 有数学或机制上的理由说明它可能有效,但没有证明它一定更好。最后是否采用,仍然要看实验。 本条只有设计动机与源码里的做法;没有任何一条是效果层面的结论。 出处待补 |
| ③ 实验上呢? | 没有比较证据 证据等级 · 实验验证 由对比实验得出的经验结论,只在出处写明的模型、数据和规模下成立。换了条件可能不再成立,引用时要带上实验设置。 本条未核实(缺口 U7):调研档案里「文件式 vs RAG」「repo map vs grep-first」两组比较的证据都是零。这个徽章在这里标的是「实验这一层是空的」,不是「实验支持某一边」。 出处待补 |
演进地图
这一课在演进链的旁支上:它不是被某个真数字逼出来的下一代,而是一个还没有答案的问题。
- 起点 把规矩写进第一条消息最省事的做法:任务说明里顺手写上「不许改测试文件」「日期用 DD/MM/YYYY」解决了不用改 harness,当场就生效。卡在A5 的分层压缩运行里,规矩写在任务说明中,17 份真实摘要只有 2 份还带着「不许改测试文件」;换一个新会话更彻底:T10 day2 的第一个请求只有 2 条消息、1,138 token,来自前一天对话的是 0 条。
- 人写的规矩 指令文件:每个请求都重新注入Claude Code 的 CLAUDE.md、Codex / OpenCode 的 AGENTS.md(Codex 从项目根到 cwd 逐级叠加、32 KiB 上限;OpenCode 同名文件 first-match)、Hermes 三段 prompt 的 context 段解决了会话开始从磁盘读一次,拼进每个请求;压缩之后从磁盘重新注入。T10 day2 的每一轮都带着 AGENTS.md 块(87 token),验收「按 AGENTS.md 的格式输出」:通过。卡在它只装人写好的规矩。agent 自己在干活时学到的东西(比如这个仓库怎么跑测试)写到哪、什么时候生效?
- 本课项目 miniagent 的 refresh 模式(T10 刷新组)解决了本会话马上就能用上刚学到的东西。卡在T10 刷新组 day1 第 7 轮:上一轮命中 2,072 token,刷新后这一轮 2,300 token 只命中 294——前缀在记忆块处断开,后面的工具定义与全部历史都要重算。
- Hermes MEMORY.md(2,200 字符)/ USER.md(1,375 字符);miniagent frozen 模式;仓库准则「Per-conversation prompt caching is sacred」解决了会话内 system 字节不变:T10 冻结组 day1 的 8 个后续请求里,8 个把上一轮的请求整个读回了缓存(最多差 1 个模板 token);day2 开新会话,第一个请求就带着前一天写的记忆。卡在流程性知识越攒越多:Hermes 随包的 77 个 SKILL.md 全文合计 215,494 token,是录制模型窗口(40,960)的 5.3 倍,全塞进快照放不下。
- Pi(name + description + location)、Hermes(描述截到 60 字符)、Claude Code(单条 1,536 字符上限)、agentskills.io 规范;分发:MCP Skills Extension(SEP-2640,2026-09-13 Final)解决了同样 77 个 skill,Hermes 实际注入的索引 2,209 token;模型觉得相关时再读正文。卡在知识的问题解决了,会话本身怎么存?想回到三轮前换条路:T10 从 e0005 分叉,线性列表只能删掉它后面的 15 条(原来那条成功的路径)。
- Pi(id / parentId,一个 JSONL,/tree /fork /clone)、Claude Code(/branch、--fork-session)、Codex rollout(append-only,压缩写成 CompactedItem)、miniagent session.py解决了两条分支并存,压缩有损、历史无损;分叉的第一个请求与原分支共享前缀:T10 fork 第 1 轮 1,236 token,实测命中 1,197。卡在一个会话、一个窗口的边界还在:一件事大到一个 agent 的上下文装不下、或需要别人把关时 → 下一章 A7 子 agent。
数字口径:A5 的摘要来自 pd-v2-layered-s1 的真实运行(a05-context.json);其余来自本课项目 miniagent 的 T10 两天会话(Qwen3-8B-MLX-4bit,本机 mlx_lm.server,2026-09-26),缓存命中是服务端报告的 cached_tokens;skill 的 token 数由录制模型的 tokenizer 在 Hermes pin 的 77 个 SKILL.md 上现算(a06-memory.json,2026-09-26)。
一句话
回到主线
流程性知识(skills)也这样全量注入吗? → 第 3 课:几十个技能说明,全塞进 prompt 吗?
你可能会问
- 「那我自己的 agent 该怎么选?」 先用这四个维度写下你的选择,再用自己的 trace 量两件事:缓存命中率(第 2 课的组件就是量法)和任务成功率。在出现公开的对照实验之前,你自己的 trace 就是最好的证据。
- 「Claude Code 到底是不是只用 grep 找代码?」 这句话没有找到官方直证,本课程不引用。能确定的是它把指令文件与 auto memory 整份注入,而读代码靠工具调用。