主题
11.3 Bug 猎杀与根因分析
复现 → 定位 → 修复 → 回归,一套不靠猜的调试流程。
读完你能做什么:用真实证据而非猜测来定位 bug,并防止"修了表面漏了根因"。
核心原则
根因分析是幻觉高发区(见 04.3 的类型 5:推理跳跃)。Claude 容易从"看到现象"直接跳到"我觉得是 X 导致的",而 X 只是它的推测。
对策贯穿全程:每一步都要真实证据,区分"观察到的"和"推断的"。
第 1 步:复现(不复现不修)
text
> 不要急着看代码。先帮我稳定复现这个 bug。
1. 根据报告,写出精确的复现步骤
2. 实际执行这些步骤,确认能触发
3. 如果无法稳定复现,告诉我还需要什么信息
在能稳定复现之前,不要开始猜测原因。为什么:不能复现的 bug,修了也无法验证是否真修好。复现是一切的前提。
第 2 步:收集证据(观察,不推断)
text
> 现在收集证据,只记录你实际观察到的,不要推断:
1. 完整的错误信息和堆栈(实际跑出来的,不是回忆的)
2. 出错时的输入和状态
3. 相关的日志
4. 用 git log 看看相关代码最近的改动
用 [观察] 标注每条实际看到的事实,暂时不要下结论。第 3 步:定位(二分 + 证据)
text
> 基于证据定位根因。要求:
1. 每个假设都标注 [假设],并说明"如果成立会观察到什么"
2. 用二分法缩小范围:加日志/断点,实际运行观察,逐步缩小
3. 每次运行的实际结果标 [观察]
4. 不要跳到结论——每个推断必须有观察支撑
找到根因后,用一句话说清:根本原因是什么,它如何导致了观察到的现象。二分定位的实操
text
> 这个函数从输入到出错经过 5 个处理阶段。
在每个阶段后加一行日志打印关键变量,实际运行,
告诉我数据在哪一阶段开始不对。不要猜,用日志证据。第 4 步:区分根因与触发条件
最容易出错的一步。
text
> 明确区分:
- 触发条件:什么情况下会暴露这个 bug(表面)
- 根本原因:为什么代码在这种情况下会错(本质)
举例:
触发条件 = "订单量超过 1000 时报错"
根本原因 = "分页逻辑用了 int16 存计数,溢出了"
只修触发条件(比如限制订单量)不算真修复。
告诉我你要修的是根因还是触发条件。第 5 步:修复(先写复现测试)
text
> 修复前,先写一个能复现这个 bug 的测试(现在应该是失败的)。
然后修复,让测试通过。
<anti_cheat>
不要改测试迁就实现,不要 skip。
修复必须针对根因,如果你只能修触发条件,明确告诉我。
</anti_cheat>先写复现测试保证了两件事:一是证明你真的理解了 bug,二是防止未来回归。
第 6 步:回归验证
text
> 修复后:
1. 复现测试通过(贴输出)
2. 跑完整测试套件,确认没有连带破坏其他功能
3. 手动复现原始 bug 的步骤,确认不再触发
4. 想一想:这个根因还可能在别处以类似形式存在吗?如果有,一并检查第 4 点很有价值 —— 同一个根因(比如"到处都用 int16 存计数")可能潜伏在多个地方。
完整流程模板
text
<task>
排查并修复这个 bug:[粘贴报告]
</task>
<workflow>
1. 复现:写出复现步骤并实际验证能触发。不能复现就停下要信息。
2. 收证据:只记录 [观察] 到的(堆栈、输入、日志、近期改动),不推断。
3. 定位:二分法 + 日志,每个 [假设] 都要 [观察] 支撑,缩小到根因。
4. 区分:明确根因 vs 触发条件。
5. 修复:先写复现测试,再修根因。
6. 回归:复现测试过 + 全套件过 + 手动验证 + 检查同类问题。
</workflow>
<constraints>
- 每步用真实证据,不猜
- 区分 [观察] 和 [推断]
- 修根因,不是掩盖症状
</constraints>
<anti_cheat>
禁止改断言/skip 测试/硬编码。修复针对根因。
</anti_cheat>疑难 bug 用 Opus + 高 effort
难以定位的 bug(并发、内存、间歇性)值得上最强配置:
bash
claude --model opus --effort high并善用 /debug:
text
> /debug 从现在开始捕获日志。这个 bug 是间歇性的,我会尝试触发它。独立验证根因
对重要的根因结论,用独立子代理交叉验证(防确认偏误):
text
> 你的结论是"根因是 X"。派 verifier 子代理独立验证这个结论,
只给它结论和证据,不要给它你的推理过程。见 06.4 验证型子代理。
常见错误
| 错误 | 后果 | 对策 |
|---|---|---|
| 不复现就开始猜 | 修了无法验证 | 先稳定复现 |
| 从现象直接跳结论 | 修错地方 | 每步要证据 |
| 只修触发条件 | 根因还在,换个场景复发 | 区分根因/触发 |
| 不写复现测试 | 无法证明修好,未来回归 | 先写复现测试 |
| 修完不查同类 | 同样的坑别处还有 | 第 6 步查同类 |