用 AI 调试与重构:定位 bug 与梳理遗留代码

调试和重构是两个最容易「看起来做完了」的任务:报错消失了但根因还在,代码变漂亮了但行为变了。AI 在这两件事上非常有用,前提是你按证据给料、按假设推进、按测试收口。核心纪律三条:先给全上下文、先要假设后要改动、危险操作人工确认

给足上下文:调试四件套

「帮我看看为什么报错」几乎必然得到编造的答案。一次有效的求助至少包含四样东西。

要素要给什么常见缺失
报错全文完整堆栈、错误码、时间点、发生频率只给最后一行
最小复现能稳定触发的步骤或测试用例「有时候会错」
相关代码出错函数 + 调用方 + 涉及的类型定义只贴一个函数
已尝试你改过什么、结果如何不提,导致它重复给同一建议
我在排查一个线上问题,先只看证据、不要给方案,等你读完再回答。

【现象】POST /api/order/submit 大约每 200 次请求出现 1 次 500,持续两天,
         昨天开始变频繁。发生时间集中在上午 10 点前后的高峰时段。
【报错全文】
  (这里粘贴完整堆栈,从第一行异常到最后一个业务帧,不要截断)
【最小复现】本地用脚本并发 50 个相同请求可复现,单线程请求无法复现。
【相关代码】
  - service/order_submit.go 第 120~210 行(主流程)
  - repository/order_repo.go 第 60~110 行(事务与库存扣减)
  - 类型定义 model/order.go
【已尝试】1) 加了重试,错误率下降但没消失;2) 怀疑连接池,把最大连接数调大后无变化。
【要求】
1) 先指出你认为最可能的原因,按可能性排序,每条说明依据来自堆栈或代码的哪一行;
2) 明确区分「代码里能看到的证据」与「你的推测」;
3) 如果信息不足,列出你需要我补充什么,不要凭想象补全;
4) 现在不要改代码。

最小复现:把「有时候错」变成「每次都错」

手段做法目的
写测试复现把线上输入固化成一条失败用例有了确定的红,才有确定的绿
缩小数据从大文件/大表里裁剪出最小数据集排除数据量干扰
隔离依赖用桩替换下游,固定返回确认是不是依赖侧问题
对齐环境比对版本、配置、时区、字符集排除环境差异
# 把线上出错的那一条输入固化成回归用例,先确认它能稳定失败
go test ./service -run TestOrderSubmit_DuplicateStock -count=5 -v
# 并发复现:只在并发下出现的问题,单线程测试永远是绿的
go test ./service -run TestOrderSubmit -race -count=20
# 观察资源层面是否有异常(连接、文件描述符、线程)
ss -s && cat /proc/<pid>/limits | grep -i 'open files'

先要假设,再要验证

让 AI 一次给三个假设并按证据排序,比让它直接改代码有效得多。它最常见的失败模式是「猜一个原因 → 改一处代码 → 说修好了」。

基于我给的堆栈与代码,请给出这份分析:
1) 假设列表(至少 3 条,按可能性从高到低):
   每条写:假设内容 | 支持它的证据(引用文件与行号或堆栈帧)| 如果成立会看到什么现象;
2) 验证方法:每条假设对应一个最小验证动作,说明预期结果与「被推翻」的判定标准;
3) 优先级建议:先验证哪一条,为什么;
4) 明确写出「我无法从现有信息判断的部分」。
规则:不要给修复方案,不要假设我没提供的代码存在;任何结论都要能被我按你给的步骤验证。
假设支持证据验证动作结果
事务里重复扣库存堆栈停在扣减处并发跑 50 次并打印库存成立
连接池耗尽错误率随时段升高打点连接池等待时间被推翻
重试导致重复提交加过重试检查是否幂等成立

把这张表填满,比读十页 AI 分析更有用。成立的假设才算根因,其余都只是猜测

重构前先补测试

没有测试的重构等于赌博。顺序永远是:先固化现状,再改结构,再验证行为不变。

步骤做什么完成标志
1跑通现有测试并记录覆盖率有一份「改之前」的基准
2给要重构的代码补特征测试覆盖主要分支与边界,改坏会红
3做结构性改动,一次一步每步之后测试全绿
4对比改动前后行为输出一致,性能无明显退化
我要重构 legacy/pricing.py 里的 calculate_price 函数(约 300 行,无测试)。
请按顺序做,每步停下来等我确认:
第一步:读代码,用一张表列出它的输入、输出、分支条件、副作用(读写数据库/缓存/日志)
        以及你发现的隐藏假设;
第二步:列出重构前必须补的测试用例清单(覆盖主要分支与边界),先只给清单;
第三步:等我确认后写出这些测试,我先跑通它们、确认是绿的;
第四步:再开始重构,每次只做一种改动(先提取函数,再消除重复),
        每次改完运行测试,全绿才继续下一步。
约束:不改公开函数签名与对外行为;遇到不确定的行为,保留原样并在报告里标出。

危险操作必须人工确认

危险动作为什么危险替代做法
删除文件或目录不可恢复先移到备份目录,确认后再删
改数据库结构影响线上、回滚成本高生成变更脚本,人工评审后执行
直接改生产数据可能污染业务事实只生成 SQL 与影响行数,人工执行
强制推送/重写历史覆盖他人工作用普通提交,必要时人工操作
升级或删除依赖可能带来连锁影响单独提交、单独验证
批量替换代码误伤面大先出清单与影响文件数,小批多次
在任何删除、覆盖、改动数据库、强制推送之前,你必须先停下来输出:
1) 你要执行的确切命令或 SQL;
2) 影响范围:涉及哪些文件、多少行、哪些表、预计多少行数据;
3) 回滚办法:如果这一步错了,怎么恢复;
4) 风险点:你认为最可能出问题的地方。
必须等我回复「确认执行」后才能动手。没有得到确认时,宁可停下并说明卡在哪里。

常见坑

后果规避
只贴报错最后一行得到编造的根因贴完整堆栈与上下文
让它直接给修复方案掩盖根因,问题复发先要假设与验证步骤
没有失败用例就重构行为悄悄变了没人发现先补特征测试
一次重构多个模块出问题无法定位一次一种改动,逐步验证
相信「已修复」没验证就上线自己跑复现用例确认
让它直接改生产库数据事故只出 SQL,人工执行

小结:调试的关键是证据链——给全堆栈与最小复现、让 AI 先列假设和验证方法、用实验推翻或确认,成立的假设才是根因;重构的关键是安全网——先补测试固化现状,再一次一步地改,危险操作一律先出清单与回滚办法、人工确认后才执行。

笔记加载中…