
上一篇用 read-only 模式读懂了陌生代码库。这篇往前走一步——从"看懂"到"动手改",场景是每个开发者的日常:修 Bug。
先说一个我踩过很久才明白的点:修 Bug 最贵的一步不是改代码,是复现。
改错三行代码只需要一分钟,但如果你没办法稳定复现这个 Bug,你连"改对了没有"都验证不了。很多所谓"修好了"其实是"这次没再出现",下次换个环境照样炸。
这件事上 Codex 有个别家不太一样的地方:它跑在自己的沙箱里,能执行命令。也就是说——它不只是听你转述报错,它能自己把错误跑出来。
这个差别,是整篇文章的核心。
三种能力档位,决定了修 Bug 的上限
按"能不能自己复现"划分,AI 修 Bug 有三档:
第一档:转述式。你把报错粘给它,它基于文本猜。这种情况它只能告诉你"可能是空指针"“可能是依赖没装”——方向大概率对,但落不到你项目的具体某一行。
第二档:推断式。它能读你的代码,沿调用链推。这一档已经很有用,能定位到具体文件和函数。但推出来的结论有个隐患:它没见过错误真正发生的样子,可能把一个不会触发的分支当成根因。
第三档:复现式。它能跑起来、能拿到真实堆栈、能改完再跑一遍验证。这时它做的判断和你是同一套证据——不是推理,是实验。
Codex 在第三档。它能在工作区里执行构建、跑测试、跑脚本,拿到第一手的报错,改完自己验证。
所以用 Codex 修 Bug 的正确姿势,和"把报错丢给 AI"不太一样:你要给的不是报错文本,是复现入口。
模式怎么选:修 Bug 别用 read-only
上一篇强调探索陌生代码要用 read-only,那是安全前提。但修 Bug 场景不一样。
回想 read-only 的定义:不能改文件、不能执行命令。这就意味着它连 npm test 都跑不了——复现都做不了,只能退回到"推断式"那一档。
修 Bug 我用的模式组合:
- auto-edit 起手。它能改文件(改完有 diff 可以审查,Git 能回退),执行命令前会问你——你正好可以在批准那一刻看清楚它要跑什么
- 命令批准时不偷懒。它提议跑
npm test就批准;提议跑rm、git checkout .、装全局依赖这类,停下看清楚再决定 - full-auto 只在收尾阶段用。比如已经确认修复方向、只剩"跑十个测试文件验证"的时候。全程 full-auto 修 Bug 我不建议——你连它试过什么都不知道
一句话:定位阶段要它跑,就必须放开执行权限;但放开的是"跑测试"的权限,不是"随便动"的权限。
实战一:能本地复现的 Bug(最有价值的一类)
场景:本地跑构建报错,TypeError: Cannot read properties of undefined (reading 'map'),堆栈只指到打包后的代码,看不出源文件。
第一步:给复现入口,而不是给报错
差的问法:
帮我修一下这个错:TypeError: Cannot read properties of undefined
好的问法:
运行
npm run build报错了,完整输出如下(贴全)。这个错只在 build 时出现,dev 模式正常。
你先自己跑一遍npm run build确认能复现,再定位根因。
定位到之后先告诉我结论和证据,我确认了你再改。
最后两句是重点:
- 「你先自己跑一遍确认能复现」——把"实验权"交给它,它拿到的是真实堆栈,不是打包后的乱码
- 「先告诉我结论和证据,我确认了再改」——把修复卡在定位之后,方向错了零代价
第二步:看它怎么定位
Codex 拿到真实报错后,路径通常是:
- 跑构建,拿到带 sourcemap 的原始堆栈,定位到
src/utils/format.ts - 读这个文件,发现一个对
config.rules.map()的调用 - 往上追
config从哪来——buildConfig()的返回值 - 读
buildConfig():正常分支返回带rules的对象,某个 early return 分支返回{} - 根因浮出:某个构建条件下
rules缺失,下游直接.map()
这个过程里,第 3、4 步是它自己读代码读出来的,第 1 步是它自己跑出来的。这两样结合,结论才立得住。
第三步:验证修复
改完别只看"能构建了"。让它做三件事:
- 重跑原始的
npm run build——原路径必须通 - 跑相关测试——确认没改坏别的
- 说明改动影响了哪些调用方——防止修了这个地方炸了另一个
第三条经常被忽略。一个 buildConfig() 的返回值改了,所有调用它的地方都可能受影响。让它主动列出调用方,你再扫一眼。
实战二:本地复现不了的 Bug(更常见)
线上偶发、CI 上挂本地过、只在某个同事机器上出问题——这类 Bug 才是真正的麻烦,因为你给不出复现命令。
思路:把"复现不了"本身当成问题交给它。 你给的是证据包:
这个 Bug 本地复现不了,但线上每小时报几次,错误日志如下(完整贴)。
已知信息:
- 只有生产环境出现,staging 正常
- 出现时间集中在业务高峰
- 最近一周这个模块有过两次提交
请你先分析:环境差异里哪些因素可能导致这个错,然后尝试构造一个最小复现脚本。
不要改任何业务代码,先只做分析和最小复现。
证据包的四样东西:完整日志、环境差异、时间规律、近期变更。这四样给齐,它能在沙箱里搭一个模拟环境把问题复现出来——这一步做成了,后面的定位就和实战一没区别。
一个特别好用的杠杆:git log 追回归。
如果它判断"最近一周有两次提交",让它直接看这两次提交改了什么:
看一下
src/order/目录最近一周的提交,逐个分析改动内容,判断哪一次可能引入这个问题。
很多"莫名其妙的 Bug"其实是最近某个改动漏了分支。让它读 diff 找嫌疑人,比让它猜快得多。
修不动的时候,三条退路
它第一轮定位错了很正常。别急着重开任务(上下文丢了更慢),按顺序试这三条:
退路一:补线索,不重开。在同一个会话里追加:"我试过 XX 了,不是这个原因;Y 是正常的。"否掉的假设越多,它的搜索空间越小。
退路二:让它用二分法。问题范围太大时,指令它"把可能出问题的代码块按嫌疑排序,先验证嫌疑最大的那一处"。一次只验证一个假设,比一次性给你五个猜测有用得多。
退路三:先写测试锁死问题。如果 Bug 复现不稳定,让它先写一个能失败的测试——把 Bug 现象固化成断言。测试红了,你就有稳定的复现手段;测试绿了,说明你的理解本身有问题,方向得推倒重来。
第三条是我最常用的。修 Bug 的成本大头在"确认修好了没有",一个能稳定失败的测试,等于给这次修复装了个验收标准。
五个坑
坑 1:只贴报错不贴复现方式。报错文本是"结果",复现方式是"入口"。没有入口,Codex 只能退回推断档。
坑 2:一次性要求"定位 + 修复 + 优化"。三个目标混在一句里,它大概率会跳步——还没定位清楚就开始改。全部拆开,一步一确认。
坑 3:批准命令时不看。auto-edit 模式下每条命令都要你点确认,这是你唯一的把关点。它可能提议 git checkout . 来"重置到干净状态"——这一下就把你未提交的改动全清了。
坑 4:改完只看"不报错了"。不报错 ≠ 修对了。必须回到最初的复现路径上验证一遍,再跑测试。三条都过才算完。
坑 5:不做 git 快照就让它改。动手前把当前状态 commit 一下。有了这个快照,git diff 看改动、git checkout 回滚,成本都是零。没有快照,你只能靠记忆判断它动了哪。
总结
- 修 Bug 最贵的一步是复现,不是改代码——不能稳定复现,就没法验证"修好了"
- Codex 的独特之处是在沙箱里能跑命令:它拿到的是一手报错,不是你的转述
- 所以正确的给法是给复现入口(命令、环境、日志、近期变更),而不是只给一行报错
- 修 Bug 别用 read-only(跑不了命令就复现不了);用 auto-edit,命令逐条批准
- 定位和修复要卡一道:先要结论和证据,确认方向再放它改
- 修不动时三条退路:同会话补线索、二分法缩小范围、先写一个能失败的测试
下一篇换个场景:让 Codex 给存量代码补单元测试,覆盖率从 0 拉起来的完整打法。
如果这篇帮你把修 Bug 的流程理顺了,欢迎分享给天天和线上告警搏斗的同事。你遇到最难复现的那个 Bug 是什么样的?评论区聊聊~
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/sg_knight/article/details/169553945




