跳转到内容

高效修 Bug

修 Bug 这件事,难的不是「改一行代码」,而是「让 AI 改对那一行」。

大部分人和 Claude 修 Bug 的姿势是:甩一句「登录坏了,修一下」,然后看它在哪里胡乱试。这种做法的失败率,和你把车扔进修理厂说「车不好开,你看着办」差不多——能不能修好全凭运气。

高效的修法,是给 Claude 三样东西:症状、位置、修好的样子

三件套:症状 + 位置 + 验收标准

Section titled “三件套:症状 + 位置 + 验收标准”

官方 common-workflows 给的范例 prompt,本身就是教科书级别的写法:

users report login fails after session timeout. check auth flow in src/auth/, especially token refresh. write a failing test that reproduces the issue, then fix it

三句话讲清三件事:

  1. 症状:用户报告登录在 session 超时后失败。
  2. 可能位置:去 src/auth/ 看,重点盯 token refresh。
  3. 修好的样子:先写一个失败测试复现问题,然后修到测试通过。

第三条是关键。它不是说「修一下让我看看」,而是给了一个可验证的完成标准——测试从红变绿,就是修好了。这种 prompt 让 Claude 不再「凭感觉改」,而是「靠证据收」。

这是修 Bug 最有效的一招:先复现,再修复

write a failing test that reproduces the bug where empty cart checkout throws TypeError. then make it pass without changing the public API

为什么这一招这么灵?

  • 复现即诊断:要让测试失败,Claude 必须先理解 bug 触发条件——这一步往往就暴露了根因。
  • 防止假修:测试不通过,改了等于没改。AI 不能靠「看起来修了」蒙混过关。
  • 回归保护:修完之后这个测试留下来,下次有人改坏同一处,立刻被挡住。

如果 Claude 跳过测试直接动手,打断它,让它先补一个。

错误日志是 Bug 的「现场指纹」。不提供日志,Claude 就只能靠猜;提供了日志,它就能精准定位。

两种给法:

管道式(适合长日志或工具输出):

Terminal window
npm test 2>&1 | claude -p "this test suite is failing on test_user_login. find the cause and fix it"

粘贴式(适合短堆栈):

here's the stack trace:
File "src/api/handler.py", line 42, in process_request
result = cache.get(key)
TypeError: argument of type 'NoneType' is not iterable
the cache should never return None for an existing key. find why it does

第二种写法的好处是,你不仅给了日志,还给了你的判断(「cache 不该返回 None」)。Claude 会顺着这个判断找根因,而不是去猜「None 是哪儿来的」。

官方 best-practices 反复强调这条:治本,不治标

什么意思?看到 TypeError: NoneType,治标是加一个 if result is None: return 把异常吞掉;治本是去找「为什么 cache 返回了 None」——是初始化顺序错了?是并发覆盖?是某个分支忘了赋值?

the error is a NoneType crash in cache.get(). don't add a None check to suppress it — find why the cache returns None in the first place and fix that

把「不要 suppress 错误」写进 prompt,能挡掉大部分「看起来修好了其实埋了雷」的修复。AI 喜欢「最小改动」,但最小改动常常是「吞掉异常」而不是「修掉根因」。

一个 bug 可能有多种修法:A 路线改源头、B 路线加保护、C 路线重构掉这个分支。哪种最好?不试不知道。

/rewind 让你低成本试错

  1. 让 Claude 走 A 路线修一遍,跑测试,看结果。
  2. /rewind,把代码回到 bug 状态,对话保留。
  3. 让它走 B 路线再修一遍,对比。
  4. 选一个最干净的合并。

不用手动 git stash、不用记改了什么——/rewind 自动回到检查点。这就是 Checkpointing 当「安全绳」最香的时候:你敢试,因为掉不下去

  • 跑一遍相关测试:不只是你新写的那个,跑整个相关模块,防止「修了这个,坏了那个」。
  • 让它解释修了什么explain what the root cause was and why this fix addresses it——它会逼着自己把因果讲清楚,你也能审计它的逻辑。
  • 加回归测试:把你新写的失败测试留下来,作为这个 bug 的「墓碑」。

下次遇到 Bug,按这个模板填空:

Symptom: [用户报告/线上现象,复现步骤]
Suspected area: [可能的文件/模块]
Reproduction: write a failing test that reproduces [具体触发条件]
Fix policy: address the root cause, don't suppress errors or add silent fallbacks
Verification: the failing test must pass; existing tests must stay green
Constraints: don't change the public API

填完丢给 Claude,胜率比「修一下」高一个数量级。