模型说修好 5 条,考试只对 8/12:我给 Claude Code 记忆做了一次梦
1. 模型说修好 5 条,考试只对 8/12:我给 Claude Code 记忆做了一次梦
作者通过在 Claude Code 记忆中埋入错误并进行“做梦”修复实验,验证了利用代码库和会话转录作为证据进行记忆审计的有效性,并提出了一套包含 checklist 核对、索引同步及下游考试验收的标准化修复流程。
[!abstract] 速览
文章复盘了作者对 Claude Code 记忆库进行的一次“做梦”修复实验:在记忆副本中埋入 6 条错误,用代码库和会话转录作“地面真相”证据,测试模型修复记忆的能力。
- 只给记忆抓到 0/6,加代码 2/6,再加转录才到 5/6(这是上限)。
- 一次性重写 39 个文件花了 1.89 美元、489 秒,其中 33 个一字没变;只许 Edit 局部改,降到 0.73 美元、116 秒。
- 修完后开新会话考试,12 次答题只对 8 次;补一次索引核对,才到 10/12。
- 结论:仅凭记忆本身发现不了错误;重写不如逐文件核对或拆分会话;修完必须过“下游考试”,并特别注意索引文件(
MEMORY.md)与正文的同步。
按 Anthropic 的做梦思路查本机记忆:加转录才抓到 5/6,索引里一个标题没改,新会话就答错。附 prompt 和命令。
我让模型修一份被我埋了 6 个错的 Claude Code 记忆。它交回来的报告里,6 条有 5 条写着已修好。
我另开新会话,只给它修好后的记忆,问 6 道题,每题问 2 次,共 12 次。答对 8 次。
错的有一题问的是 target_file 是相对路径还是绝对路径。笔记正文改对了,索引里的描述也改对了,但 MEMORY.md 里那一行的方括号标题还写着“Newspic target_file Is Absolute”。新会话没有打开笔记,看索引标题就答了,2 次都答错。
1.1. 主要内容
| 要点 | 说明 |
|---|---|
| 记忆修复必须依赖外部证据 | 实验证明模型无法通过自身记忆发现错误,必须引入代码库(src/)和会话转录(transcripts/)作为事实依据,才能有效识别过期或错误的记忆条目。 |
| 修复流程的优化:从重写到局部编辑与核对 | 重写全部文件成本高且效率低。采用 checklist 逐文件 Grep 核对,或将任务拆分为多个小会话并行处理,能显著提高修复准确率并降低费用。 |
索引文件(MEMORY.md)是验收的关键盲点 |
模型修复正文后,往往会忽略索引标题的同步。由于 Claude Code 启动时优先加载索引,若索引未更新,模型会基于旧信息回答,导致修复失效。 |
| 建立下游考试验收机制 | 模型的自评报告不可全信。应构建一个只加载修复后记忆的独立会话,通过特定问题进行“考试”,以验证记忆是否真正被更新。 |
1.2. 起因:Anthropic 11 月 6 日那篇文章
Anthropic 发了《The components of agent memory》。其中一段讲得很直白:Claude 玩宝可梦时,把 PokéCenter 记在了东边,笔记里还写着“Mt Moon DONE”,结果走下单向台阶,掉回旧路线。后来在“做梦”阶段让它对照会话转录去检查并改写笔记,再走就进了 Mt. Moon,到了 Cerulean City。原话是:
The transcript gave Claude a ground truth to validate its memory against.
我想知道的是更具体的几件事:我自己的 Claude Code 记忆要不要这样做,最便宜怎么做,能修好什么,修不好什么。
先说明范围:Anthropic 另有官方的 Dreams API(research preview,输入的 store 不会被改,每次处理 1 到 100 个 session),我这次没用它。我用 claude -p --no-session-persistence 自己搭,模型是 Sonnet,工具只开 Read、Glob、Grep 和对 dreamed/ 目录的写入。实验过程中真实记忆没动。
1.3. 实验怎么搭的
- 记忆副本:复制本机一个工作区的 Claude Code 记忆,39 个文件,共 135.6KB。
- 埋错:在副本里埋 6 条错。3 条靠代码就能查出来,3 条只有会话转录能查。
- 转录:最近 17 次会话的 jsonl 共 196MB,压成约 680KB 的文本,保留用户消息、命令、输出开头和报错。第一版压得太狠,11MB 只剩 2KB,命令和输出都没了,等于没有证据。改成保留命令和输出的前 240 字才可用。
| 能查出错的证据 | 埋进去的错 |
|---|---|
| 代码 | publish.py 是幂等的;generate_image.py 支持 --image-style;target_file 是绝对路径 |
| 会话转录 | codex 登录 11-03 失效没恢复;0.166.0 不传 --model 会被拒;--no-session-persistence 不留痕 |
费用按 list 价算。
1.4. 规则一:给它转录当证据
| 给模型的材料 | 抓到 | 费用 |
|---|---|---|
| 只有记忆 | 0/6 | 0.06、0.24 美元 |
| 记忆 + 代码 | 2/6(两次一样) | 0.19、0.29 美元 |
| 记忆 + 代码 + 转录 | 5/6、5/6、2/6 | 1.89、0.73、0.28 美元 |
只给记忆,它一条也抓不到。记忆写错了,自己看自己,看不出来。加上代码,能抓到那 3 条里的 2 条。再加转录,才摸到“登录失效”“--model 被拒”这类只存在于过去对话里的事实。
--no-session-persistence 那条,所有方案都没抓到。我回头 grep 了 17 份转录,里面没有这个词。证据不存在,这条种子埋得不公平,所以 5/6 就是上限。
这条埋错说这个参数不留痕,实验自己就是反例:跑完后 ~/.claude/projects 多了 12 个项目目录,确实没有 jsonl,但其中 3 个留了子代理元数据或工具输出文件,我按名字清掉了。
1.5. 规则二:每条笔记都要留痕,或者拆开跑
1.5.1. 一次性重写会浪费
第一次加转录时我让模型重写全部文件。39 个文件它重抄了一遍,其中 33 个一字没变,花了 1.89 美元、489 秒。改成先复制一份,只许用 Edit 局部改:同样抓到 5/6,0.73 美元、116 秒。
| 做法 | 39 个文件的改动 | 费用 | 耗时 |
|---|---|---|---|
| 重写全部文件 | 33 个一字没变 | 1.89 美元 | 489 秒 |
| 只许 Edit 局部改 | — | 0.73 美元 | 116 秒 |
1.5.2. 用 checklist 把波动压下来
同一个 prompt 会跑出两个结果。5/6 和 2/6 差很大,模型自己说只细读了部分笔记。我加了一条规则:先把全部文件列进 checklist.md,每个文件用 Grep 查过才能打勾,全部打勾之前不许结束。三次跑出来是 4/6、5/6、5/6,费用 0.76 到 1.10 美元,83 到 105 轮。波动小了很多。
1.5.3. 拆到一条笔记一个会话
更彻底的是拆开跑:一条笔记开一个新会话,39 个会话,6 并发。
| 跑法 | 抓到 | 费用 | 耗时 |
|---|---|---|---|
| Sonnet | 5/6 | 4.36 美元 | 112 秒 |
| Haiku | 4/6 | 0.38 美元 | 189 秒 |
拆开跑的结果和一次跑不一样:
- Sonnet 比一次跑多查出 3 处真实的旧说法,我逐条对过代码和转录,都成立。
- Haiku 的 39 个输出里有 11 个解析不了,另外报了 26 条问题,其中至少 4 条是把我自己定的规矩当成错误。比如我已弃用 knowledge-card,
SKILL.md里还列着,它就判笔记写错了。
Anthropic 那篇也测到类似现象:多代理合写一页,57 个事实留下 41 个;一个合同一个 agent、原文引用,57/57。一个 agent 只管一份材料,漏得就少。
[!tip] 怎么选
日常用打勾清单一次跑,约 1 美元;想查得更深再拆开跑,但要用 Sonnet,别用 Haiku 判断真假。Haiku 报出来的问题要人一条条审,省下的钱不一定划算。
1.6. 规则三:改完用下游考试验收
1.6.1. 考试怎么设计
新会话只看记忆,答 6 道题,每题 2 次。索引放进 system prompt,和 Claude Code 启动时加载 MEMORY.md 的方式接近,笔记正文要它自己用 Read 打开。
1.6.2. 8/12 卡在索引标题
我的打分脚本和修复报告都说修好 5 条,考试只对 4 道题。多出来的一条是 target_file:正文改了,索引标题没改。
[!warning] 自评不算数
记忆修得好不好,模型的自评不算数,要让一个只看记忆的新会话答题验收。
1.6.3. 补一次索引核对
再加一遍索引核对,用 Haiku 逐行对比 MEMORY.md 的标题和描述与笔记内容:0.025 美元,29 秒,改了 1 行。再考,10/12,只剩那条证据不存在的 --no-session-persistence。
[!caution] 索引标题要单独核对
索引每次启动都加载,标题和描述够回答的时候,它就不去打开正文了。
1.7. 做梦修不好什么
证据里没有的,修不了。上面那条就是。
证据目录之外的变化,它也看不见。我只给了 wechat-publisher 的代码,别的目录搬家了它不知道。我另外写了个零 token 的检查脚本 dead_paths.py,用正则抓出路径逐个 ls。结果 92 处路径里有 46 处不存在,涉及 10 条笔记,其中 31 处集中在一条笔记里。脚本有误报(前缀、相对路径、带空格的路径),但它查到了做梦查不到的:new-x-skill 已经搬到 ~/codes/skills/ 下面。
1.8. 在真实记忆上跑出了什么
我埋的错之外,模型还在真实记忆里查出了本来就有的旧说法:
| 核对依据 | 查出的旧说法 |
|---|---|
| 代码 | newspic_build 笔记说按 ASCII 空格切,实际按标点和中文旁的连字符切,再硬切 18 字 |
| 转录 | html_converter 笔记写 10-30 推送,转录显示 11-06 才推 |
| 代码 | placeholder 笔记写“静默跳过”,现在默认中止发布 |
| 笔记之间矛盾 | 贴图风格笔记还在推荐已弃用的 knowledge-card |
我逐条确认后改了 9 条真实笔记,新增 1 条。
1.8.1. 体积是另一类问题
有一类问题做梦不管:体积。我的 prompt 只许改被证据推翻的说法,所以大笔记跑完还是那么大。
project_mp_articles_image_backend.md 一条笔记 40.8KB,占全部记忆的 30%,141 行,里面是 49 条按日期堆的流水,29 个 /tmp 路径现在全部不存在。全机 94 个记忆目录的索引最大 12KB,都没到 Claude Code 只加载 MEMORY.md 前 200 行或 25 KB 的线。我这里还没到装不下,问题是流水账里混着过期说法。这部分要另外拆笔记。
Anthropic 那篇对比过两种写法:Sonnet 3.7 写了 413 个文件,拿 1 枚徽章;Fable 5 写了 9 个文件加一个 global.md,拿 4 枚。
1.9. 可以直接抄的流程
1.9.1. 七步流程
- 先跑零 token 检查,看路径和命令还在不在。
- 把最近若干次会话压成文本,保留用户消息、命令、输出开头、报错。
- 建目录:
memory/放原件,dreamed/放副本,src/放代码,transcripts/放转录。 - 用下面的 prompt 做梦,Sonnet 约 1 美元。
- 单独核对
MEMORY.md索引。这一步只比对文字,不判断真假,Haiku 够用。 - 用新会话考试,问题要你自己确知答案。
- 自己看 diff 再合并。我的 9 条真实笔记是逐条对过代码和转录才改的。
1.9.2. 做梦 prompt
把这段存成 dream_prompt.md:
你在给一个 agent 的记忆做梦。memory/ 是记忆文件夹,MEMORY.md 是每次启动都会加载的索引。
1. 逐条读 memory/ 里的笔记,找出可核对的说法:路径、参数、默认值、版本、状态、结论。
2. 用 src/(当前代码)和 transcripts/(最近的会话转录)核对。记忆自己不算证据,只有笔记之间互相矛盾时才能当线索。
3. 证据推翻的说法才改。查不到证据的不动。
4. dreamed/ 已经是 memory/ 的副本。只用 Edit 在 dreamed/ 里做局部修改,不要整篇重写,不要碰 memory/。MEMORY.md 要同步,标题和描述都要改。
5. 最后写 report.json,一个数组,只列你改动过的说法:{"file","claim","verdict":"wrong|stale","evidence":"文件:行号 或 转录原句","fix"}。
6. 动手前先把 memory/ 下全部文件列进 checklist.md,一个文件一行。每个文件都要用 Grep 去 src/ 和 transcripts/ 搜关键词,查过才打勾。全部打勾之前不许结束。
1.9.3. 运行命令
claude -p --no-session-persistence --model sonnet \
--setting-sources project --strict-mcp-config \
--output-format json --permission-mode acceptEdits \
--allowedTools 'Read(./**)' 'Glob(./**)' 'Grep(./**)' \
'Write(./dreamed/**)' 'Edit(./dreamed/**)' \
'Write(./report.json)' 'Write(./checklist.md)' 'Edit(./checklist.md)' \
--disallowedTools Bash Agent WebFetch WebSearch \
-- "$(cat dream_prompt.md)" > dream.json
1.9.4. 考试一题的写法
claude -p --no-session-persistence --model sonnet \
--setting-sources project --strict-mcp-config \
--append-system-prompt "这是你的记忆索引,笔记正文在 memory/ 目录下,需要时用 Read 读。$(cat memory/MEMORY.md)" \
--allowedTools 'Read(./**)' \
--disallowedTools Bash Agent WebFetch WebSearch Write Edit \
-- "card_plan.json 里的 target_file 是绝对路径还是相对路径?只答 absolute 或 relative。"
跑完看一眼 ls ~/.claude/projects。--no-session-persistence 不写 jsonl,但目录还是会建,也可能留工具输出。
1.10. 局限
这是一台机器上的一份记忆、6 条埋错,每种跑法只跑 1 到 3 次,数字只说明量级。埋的错我知道答案,真实记忆里的错没有这样的标准答案,模型漏了多少我不知道。记忆的写法也不是越细越好,Anthropic 测到 record only failures 这类规则会让 Opus 5 和 Opus 4.7 失去大部分记忆收益,改写笔记的规矩本身也值得用考试验证。