主题
03.4 压缩 Compact 与会话续航
会话越长越笨是必然的。这一章讲怎么延缓它,以及什么时候该果断重开。
读完你能做什么:让一个复杂任务跨越 100 轮对话仍然保持质量。
一、三个"清理"命令的区别
| 命令 | 保留什么 | 丢弃什么 | 什么时候用 |
|---|---|---|---|
/compact | 对话摘要 + 项目记忆 | 详细的历史消息 | 同一个任务但上下文快满了 |
/clear | 项目记忆(CLAUDE.md) | 全部对话历史 | 切换到不相关的新任务 |
/rewind | 到指定检查点的状态 | 该点之后的对话和/或代码改动 | 走错方向要回退 |
决策树:
text
你还在做同一个任务吗?
├─ 是 → 上下文压力大吗?
│ ├─ 是 → /compact
│ └─ 否 → 继续
└─ 否 → 新任务和旧任务有关联吗?
├─ 有 → /compact 后继续
└─ 无 → /clear二、/compact 的幸存规则
这是最需要精确掌握的部分 —— 压缩后什么会留下,什么会消失。
2.1 会幸存的
| 内容 | 机制 |
|---|---|
项目根目录的 CLAUDE.md | 压缩后从磁盘重新读取并重新注入 |
.claude/rules/ 中的无条件规则 | 同上 |
| 系统提示词 | 不参与压缩 |
| MCP 工具定义 | 不参与压缩 |
| 对话的摘要 | 由模型生成,保留主要脉络 |
2.2 会丢失或退化的
| 内容 | 后果 |
|---|---|
子目录中的嵌套 CLAUDE.md | 不会自动重新注入,要等下次读该目录文件时才重新加载 |
| 你在对话中口头说的规则 | 可能被摘要成一句模糊的话,丧失具体性 |
| 读过的文件的完整内容 | 变成"读过 xxx 文件"的描述,细节丢失 |
| 工具调用的详细输出 | 大幅压缩 |
| 早期讨论的细节权衡 | 只保留结论,理由可能丢失 |
2.3 压缩前的必做动作
在 /compact 之前,把口头约定固化下来。
text
> 在压缩之前,把我们本次会话确定的所有约束和决策,
追加到 CLAUDE.md 的「本次重构约定」小节里。
包括:
- 我们决定不动 legacy 目录的理由
- 命名约定(xxxHandler 而不是 xxxController)
- 已经确认过的三个不能改的接口
写完后再执行 /compact这样这些内容会以 CLAUDE.md 的形式幸存,而不是被摘要成一句「用户提出了一些约定」。
2.4 引导压缩
/compact 可以带参数,指示保留重点:
text
> /compact 重点保留:已完成的改动清单、剩余待办事项、
三个不能修改的接口签名。可以丢弃前期的方案讨论过程。三、检查点与回退(Checkpointing)
3.1 /rewind 的三种模式
text
> /rewind会让你选择回退范围:
| 模式 | 效果 |
|---|---|
| 只回退对话 | 代码改动保留,对话回到之前 |
| 只回退代码 | 对话保留,文件恢复到之前状态 |
| 两者都回退 | 完整回到检查点 |
别名:/checkpoint、/undo。
3.2 什么时候用 rewind 而不是"让它改回来"
text
❌ 「刚才那个改动不对,改回去」
→ 它可能改不干净;而且错误的方案仍留在上下文里持续干扰
✅ /rewind 到改动之前
→ 代码和上下文一起干净判据:如果错误的尝试污染了上下文(模型现在同时"知道"两个矛盾的方案),用 rewind。如果只是一个局部小错,让它改就行。
3.3 主动创建检查点的习惯
在做危险操作之前:
bash
# 用 git 做外部检查点(最可靠)
git add -A && git commit -m "checkpoint: 开始重构对账模块前"
# 或者用 worktree 完全隔离
claude -w refactor-reconcileWorktree 的好处:实验完全隔离在另一个目录,失败了直接删掉,主工作区毫发无损。见 06.7 Worktrees 与并行开发。
四、长任务的会话续航策略
4.1 策略:外部状态文件
这是跨越 100 轮对话的核心技巧 —— 把任务状态写到文件里,而不是留在上下文里。
markdown
<!-- PROGRESS.md,放在项目根目录 -->
# 对账模块重构 · 进度
## 已完成
- [x] 抽出 ReconciliationEngine 接口(commit a3f2c1)
- [x] 迁移 alipay 适配器(commit 7b9e40)
- [x] 迁移 wechat 适配器(commit 2c1d88)
## 进行中
- [ ] 迁移 unionpay 适配器
当前卡点:unionpay 的回调格式与其他渠道不同,需要额外的字段映射层
## 待办
- [ ] 迁移剩余 9 个渠道
- [ ] 删除旧的 ReconciliationService
- [ ] 补充集成测试
## 关键约定(不要违反)
1. 不修改 src/legacy/ 下任何文件
2. 每个渠道迁移必须独立可上线、独立可回滚
3. 金额一律 BigDecimal
4. 接口 IPaymentCallback 的签名不能改(有外部系统依赖)
## 已知坑
- alipay 的 SDK 在并发下有线程安全问题,不要在 static 字段里缓存 client
- 测试环境的 unionpay mock 服务经常挂,跑测试前先 curl 检查在 CLAUDE.md 里加一句:
markdown
## 当前任务
正在进行对账模块重构。开始工作前先读 `PROGRESS.md` 了解进度,
完成任何一步后立即更新它。效果:即使 /clear 完全清空对话,新会话读一下 PROGRESS.md 就能接着干。
4.2 策略:按子任务开新会话
bash
# 每个渠道一个独立会话,每个会话都很短
claude -n "migrate-unionpay" "根据 PROGRESS.md,完成 unionpay 渠道的迁移"
claude -n "migrate-jd" "根据 PROGRESS.md,完成 jd 渠道的迁移"用 -n 给会话命名,之后可以精确恢复:
bash
claude --resume migrate-unionpay4.3 策略:Auto Memory
Claude Code 的自动记忆会跨会话保留学到的东西(构建命令、调试经验、你的偏好)。
text
> /memory可以查看和编辑。存储位置:
bash
~/.claude/projects/<project>/memory/
├── MEMORY.md # 索引,每次会话加载前 200 行 / 25KB
├── debugging.md # 详细笔记,按需加载
└── ...注意:MEMORY.md 有 200 行 / 25KB 的加载上限,超出部分会被丢弃。让它保持索引性质,详细内容放到主题文件里。
关闭自动记忆:
json
{
"autoMemoryEnabled": false
}或环境变量 CLAUDE_CODE_DISABLE_AUTO_MEMORY=1。
五、上下文变笨的早期信号
学会识别这些信号,在质量崩塌前干预:
| 信号 | 含义 |
|---|---|
| 开始重复之前说过的话 | 它在"回顾"上下文,说明检索变困难 |
| 格式漂移(不再遵守你定的输出格式) | 格式约束的权重被稀释 |
| 忘记早期约束(又开始用 double 了) | 早期指令衰减 |
| 反复问你已经回答过的问题 | 检索失败 |
| 响应明显变慢 | 上下文长度导致的延迟 |
| 开始给出泛泛而谈的答案 | 具体信息被噪音淹没 |
看到任意两条同时出现,立刻 /context 检查占用,准备压缩。
六、一份长任务的标准操作流程
text
【开始】
1. 建 PROGRESS.md,写清目标、约束、验收标准
2. 在 CLAUDE.md 里加一句「先读 PROGRESS.md」
3. git commit 作为起始检查点
【每完成一个子任务】
4. 更新 PROGRESS.md
5. git commit
6. 检查 /context,占用 > 60% 就准备压缩
【压缩前】
7. 把口头约定写进 CLAUDE.md 或 PROGRESS.md
8. /compact 并指定保留重点
【走错方向时】
9. /rewind 到检查点(而不是让它改回来)
【切换到不相关的任务】
10. /clear(不是 /compact)
【每天结束】
11. 确保 PROGRESS.md 反映真实状态
12. 明天从新会话开始,读 PROGRESS.md 即可续上