模型说修好 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 个留了子代理元数据或工具输出文件,我按名字清掉了。

点阵图:每次运行抓到几条埋的错。一组圆点代表一次运行,深色表示抓到。只给记忆 0/6,加代码 2/6,加转录 2 到 5/6

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.89 对 0.73 美元,耗时 489 对 116 秒,两者同样抓到 5/6

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 只管一份材料,漏得就少。

对比表截图:四种跑法的抓到数、费用、耗时与说明。一次跑完 2 到 5/6、0.28 到 1.89 美元;加打勾清单 4 到 5/6、0.76 到 1.10 美元;Sonnet 逐笔记 5/6、4.36 美元;Haiku 逐笔记 4/6、0.38 美元、11 个输出解析失败

[!tip] 怎么选
日常用打勾清单一次跑,约 1 美元;想查得更深再拆开跑,但要用 Sonnet,别用 Haiku 判断真假。Haiku 报出来的问题要人一条条审,省下的钱不一定划算。

1.6. 规则三:改完用下游考试验收

1.6.1. 考试怎么设计

新会话只看记忆,答 6 道题,每题 2 次。索引放进 system prompt,和 Claude Code 启动时加载 MEMORY.md 的方式接近,笔记正文要它自己用 Read 打开。

阶段条形图:新会话 6 道题各问 2 次,共 12 次答题。原始记忆 12/12,埋错后 0/12,只给记忆 0/12,加代码 2/12,加转录和清单 8/12,再加索引核对 10/12

1.6.2. 8/12 卡在索引标题

我的打分脚本和修复报告都说修好 5 条,考试只对 4 道题。多出来的一条是 target_file:正文改了,索引标题没改。

[!warning] 自评不算数
记忆修得好不好,模型的自评不算数,要让一个只看记忆的新会话答题验收。

代码截图:修复后的 MEMORY.md 第 25 行,方括号标题仍写着 Is Absolute,描述里已是相对路径;新会话两次都答 absolute;Haiku 索引核对后标题改成 Is Relative

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 枚。

数据卡片:不花 token 的体检。92 处路径里 46 处不存在,涉及 10 条笔记;一条笔记 40.8KB,占全部 135.6KB 的 30%,含 49 条日期流水和 29 个已不存在的 /tmp 路径

1.9. 可以直接抄的流程

流程图:记忆副本、当前代码、会话转录三路输入汇入“做梦”,产出修复后的记忆,再做索引核对,最后新会话考试

1.9.1. 七步流程

  1. 先跑零 token 检查,看路径和命令还在不在。
  2. 把最近若干次会话压成文本,保留用户消息、命令、输出开头、报错。
  3. 建目录:memory/ 放原件,dreamed/ 放副本,src/ 放代码,transcripts/ 放转录。
  4. 用下面的 prompt 做梦,Sonnet 约 1 美元。
  5. 单独核对 MEMORY.md 索引。这一步只比对文字,不判断真假,Haiku 够用。
  6. 用新会话考试,问题要你自己确知答案。
  7. 自己看 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 失去大部分记忆收益,改写笔记的规矩本身也值得用考试验证。