Claude Code 中途丢了项目上下文:auto-compact 摘要 + rewind/重启加固

Agent 忘了之前定的事、反复读 CLAUDE.md、和 plan 矛盾——auto-compact 把承重细节压没了。用 /rewind 回滚、重新锚定,或带紧凑 handoff 重启。

Claude Code session 进行 45 分钟。早些时候你定了「不用 GraphQL、坚持 REST」。突然它建议加一个 GraphQL resolver;或者第四次重读 CLAUDE.mdpackage.json、像没见过一样;或者它现在的 plan 和 10 分钟时的 plan 互相矛盾。

对话长到一定程度,auto-compact(自动压缩)触发了。Claude Code 把前面的对话摘要成一块来塞进上下文窗口,而那些具体约束(不用 GraphQL、用 vitest、在 apps/web/ 改)没能挺过摘要。Agent 现在用的是一份有损的「你说过什么」记忆。

最快的修法(截至 2026 年 6 月):如果压缩刚刚发生,按两下 Esc,选 Restore conversation 回滚到摘要之前,然后立刻用一条消息重申你的约束。如果你已经走得太远,就开一个干净 session、带上 5 行 handoff(见下方 Step 1)。别试图把 agent「劝」回记忆——用显式状态重新锚定。

compaction 到底怎么工作的

搞清机制就知道该用哪种修法。截至 2026 年 6 月,Claude Code 有三层,从轻到重依次触发:

  1. Microcompact——session 一长,它会在 API 调用前静默运行,清掉旧的 tool 结果(大约保留最近 5 个,其余用占位符替换),且不调用模型。所以你早期 Read 的某个文件会「消失」,但你定的决定通常还在。
  2. Auto-compact——重量级那一趟。上下文逼近窗口上限时(Sonnet 4.6 / Opus 4.7 默认 200K-token 窗口的约 95%),Claude Code 暂停,把整段对话摘要成一块结构化内容,然后从这份摘要继续。就是这一趟把你早先的约束丢了。
  3. 手动 /compact——同样的重量级流程,但由你按自己的节奏触发,而且你能指定保留什么。

状态栏会显示 Context left until auto-compact: X%。这个数字变小,就说明重量级那趟快来了。

常见原因

按命中率从高到低:

1. 上下文撞满、auto-compact 摘要前面对话

context 满了(约窗口的 95%),整段对话被摘成一块。摘要保留大意、丢具体——「讨论了方案」取代「定了不用 GraphQL、用 vitest、不允许 inline style」。然后 agent 做的决定就和被摘掉的内容不一致。

如何判断:出现了 “Conversation compacted” / “Compacting conversation…” 之类消息——之后就要预期有损记忆。跑 /context 可以确认 conversation 那块缩小了。

2. 长 tool-call 链比预期更快吃光 context

每次 ReadGrepBash 都加 context。5 次大文件 Read 可能 20K token——auto-compact 比对话长度暗示的更早触发。

如何判断:session 感觉不长但工具调用密集。跑 /context——高占用来自 Files / tool output 那一类,而不是你的消息。

3. 摘要保留大目标、丢了具体约束

Auto-compact 留「user 想加 billing feature」,丢「user 说:要 GraphQL、apps/web/、测试 vitest」。任务在做、护栏没了。

如何判断:输出在 task 上但违反了你早先设定的约束——约束被丢了,task 还在。

4. 约束只写在 path-scoped rule 或嵌套 CLAUDE.md 里

这条最隐蔽。按 Anthropic 的 context-window 文档,compaction 并不对所有指令一视同仁:

约束写在哪auto-compact 之后
项目根 CLAUDE.md、无 scope 的 rule从磁盘重新注入(存活)
Auto memory(MEMORY.md从磁盘重新注入(存活)
paths: frontmatter 的 rule丢失,直到再次读到匹配文件
子目录里嵌套的 CLAUDE.md丢失,直到再次读到该目录下文件
你只在对话里说过的决定丢失(被摘掉了)

所以写在 .claude/rules/api-conventions.md(scope 到 src/api/**)里的约束会在 compaction 后消失,只有下次 Claude 碰到匹配文件时才回来。

如何判断:丢的那条 rule 是 path-scoped 的、或在嵌套 CLAUDE.md 里,而且 agent 恰好在 compaction 后不再遵守它。修法:把它挪到项目根 CLAUDE.md

5. Tool 报错占 context 没贡献信号

Bash 命令连失败 5 次,每次错误 trace 都进 context。Microcompact 本该清掉旧 tool 结果,但一墙相同的 permission-denied 仍会把你更快推向重量级那趟。

如何判断:session 里很多重复 tool 错误——只加噪音不加信号。

6. Plan mode 出长 plan,code 还没开始就吃满 context

100 行 plan + 你的修改 + 用来验证 plan 的 tool read = 真干活之前 context 已半满。第一个长代码生成就触发 compaction、把 plan 丢了。

如何判断:session 开局花大量时间做 plan,bug 在开始 codegen 时出现。

最短修复路径

按收益从高到低。Step 0 是新的「撤销」键,Step 1 是干净重启,Step 2-3 是耐久加固。

Step 0:刚压缩完,先 rewind 回去

Claude Code v2 起每条 prompt 都建一个 checkpoint,对话可以回滚:

  1. 按两下 Esc(或跑 /rewind)。
  2. 选压缩之前的那条消息。
  3. Restore conversation——这会回滚对话历史,但保留你磁盘上当前的文件。(“Restore code” 或 “Restore both” 会同时回退文件改动,按需选。)
  4. 下一条消息重申你的约束,让它们在 context 里是新鲜的。

注意:checkpoint 只捕获通过 Claude 文件工具做的改动。Bash 的副作用(git pushnpm install、API 调用)不会被回退。checkpoint 约 30 天后清理。

Step 1:停、snapshot、重启

如果你已经远远越过了那次坏压缩,就别硬救——开新 session 带 handoff:

  1. 写一段 5 行「我们现在在哪」:
## 状态(2026-06-14 15:30)

任务:给 apps/web/ 加 billing feature
决定:
- 不用 GraphQL——REST only
- 测试 vitest,紧挨源
- 结构照 `apps/web/src/features/auth/`
进度:
- 已完成:`apps/web/src/features/billing/index.ts`、`types.ts`
- 下一步:实现 `billing.service.ts`
阻塞:无
  1. /clear(清掉对话但留在同一个项目里),或者开新 session。
  2. 把状态贴成第一条消息,加「continue from here」。

清空后的 session 对这份 snapshot 是全 context、逐字保留——没有衰减记忆。

Step 2:把 per-session 决定升级到 CLAUDE.md

每个被丢的约束都是 CLAUDE.md 空缺。把它放进项目根 CLAUDE.md(不是 path-scoped rule),因为只有它会在 compaction 后被重新注入:

## 架构决定

- API 风格:REST only(不 GraphQL——2025-Q4 试过弃了)
- 测试框架:vitest only(不 jest——见 `apps/web/AGENTS.md`
- 新 web feature 工作目录:`apps/web/src/features/`

下次 session 启动就读到,而且每次 compaction 都会被重新注入。跑 /memory 确认到底哪些 CLAUDE.md 真的加载了。文件保持在 ~200 行以内——CLAUDE.md 太大只会更快吃光预算。

Step 3:每 30 分钟把进度落盘

长 task 把进度写到文件,跨任何 context reset 存活:

# session 开始时 claude 建这个文件
echo "## 进度日志" > .agent-progress.md
echo "Started: $(date -Iminutes)" >> .agent-progress.md

Prompt:

完成有意义的一步就 append 到 `.agent-progress.md`:
- 时间戳
- 完成了什么
- 改的文件
- 下一步

context 丢了,这个文件就是权威状态。

Step 4:减少 context-吃货 tool 调用

降噪让 compaction 晚点触发:

- 找东西用 Grep 不用 Read——输出小得多
- Read 时用行区间不读整文件
- 同一个文件不要 Read 两次——记住内容
- 大输出写到 /tmp/<name>.txt 再 refer
- Bash 命令一直 fail 就停下来问,不要重试 5 次

Step 5:正交子任务交给 subagent

长 task 多关切——把它们 delegate 给 subagent(Task tool)。每个 subagent 跑在自己独立的 context window 里,文件在那里读,只有最终摘要回到主 session:

DB migration 这步开一个 subagent。
返回:migration 文件路径 + 应用了的 migration 名。

按 Anthropic 文档,一个读了 6,000 token 文件的 subagent 可能只回 400 token 摘要——那些文件读取从不碰你的主窗口。内置的 ExplorePlan agent 就是为此设计的。

Step 6:在 auto 那趟之前、按自己的节奏 compact

状态栏会倒数 Context left until auto-compact: X%。别等它归零——Claude 在窗口最后 ~20% 时推理会变差。截至 2026 年 6 月,实操目标是在 60-75% 占用时动手:

  • /compact focus on the billing feature, keep the no-GraphQL and vitest constraints——带 focus 的手动 compact 保留你点名的内容,而不是 auto 那趟瞎猜的。
  • 动手前先把进行中的决定存进 CLAUDE.md.agent-progress.md
  • 接下来是不相关的活,就用 /clear 而不是 compact——干净窗口胜过摘要窗口。

在 60% 按自己节奏 compact,远比从撞坏的 95% 摘要里救回来便宜。

如何确认修好了

重新锚定或重启之后:

  1. 问:「写代码之前,先列出你正在遵守的约束。」健康的 session 会把 REST-only、vitest、apps/web/ scope 复述给你。
  2. /context,确认 conversation 那块很小,而你的约束在刚被重新注入的 CLAUDE.md 里。
  3. 盯着下一次矛盾。如果又出现,说明约束还只活在对话里——把它升级到项目根 CLAUDE.md(Step 2)。

常见问题

为什么 Claude 老是重读同一批文件? microcompact 清掉旧 tool 结果(保留约最近 5 个)后,或者一次完整 compaction 把它们摘掉后,Claude 的 context 里就没有文件内容了,于是重读。这是正常的。要减少:session 短一点、prompt scope 紧一点让它少读文件、大块读取交给 subagent。

能不能直接把 auto-compact 关掉? 能(设置里 autoCompact: false,或走 /config),但这样一来窗口满了会直接停下 session,而不是从摘要继续——这是拿有损记忆换一堵硬墙。更好的习惯是自己在干净边界 /compact(带 focus)或 /clear

1M-token 上下文窗口能解决这个吗? 它只是推迟。Sonnet 4.6 和 Opus 4.7 支持 1M-token 上下文窗口(在你的套餐允许时选 [1m] 模型变体),compaction 会晚很多发生。但同样的摘要会在更高的上限上跑,而且一个塞满陈旧读取的大窗口照样会让推理变差。把更大的窗口当余量,不是「永不 compact」的许可证。

为什么写在文件里的 rule 也被忘了? path-scoped rule(带 paths: frontmatter 的 .claude/rules/*.md)和嵌套 CLAUDE.md 会在 compaction 时被摘掉,只有下次 Claude 读到匹配文件时才重载。项目根 CLAUDE.md 和 auto memory 则每次都从磁盘重新注入。必须存活的约束放项目根。

/compact/clear 有什么区别? /compact 把对话摘成摘要并保留为 context(想继续同一个 task、又想瘦身时用)。/clear 彻底清掉对话、在同一个项目里从头开始(切到不相关的活时用)。想撤销某个最近改动而不是把全部压缩,用 /rewind

预防建议

  • per-session 决定升级到项目根 CLAUDE.md,跨 compaction 存活;文件保持 ~200 行以内。
  • 别把必须存活的约束埋在 path-scoped rule 或嵌套 CLAUDE.md 里——那些会被摘掉。
  • 超过 20 分钟的 task 维护一份 .agent-progress.md——context reset 时的 fallback。
  • 在干净边界(一步完成后)重启或 /clear,不要硬撑过 compaction。
  • 减少 tool 噪音——Grep > Read、行区间 > 整文件、不重复 read。
  • 正交子任务给 subagent,每个独立 context window。
  • Context left until auto-compact: ~20-30% 当收尾信号;归零前就 /compact(带 focus)或 /clear

相关阅读

标签: #排查 #Claude Code #排查 #上下文缺失