老代码不敢动、动了又怕改出隐藏 bug,是很多人找 AI 帮忙重构时的真实处境:模型改得挺快,可行为有没有变、边界有没有漏,心里没底。这篇不讲怎么让 AI 写得漂亮,只讲怎么把重构拆成小步、先立好回归网、改完按顺序核对,让每一步都能回滚、能验证。
老代码不敢动、动了又怕改出隐藏 bug,这是很多人找 AI 帮忙重构时的真实处境。模型改得确实快,一次能吐几百行,但行为有没有变、边界有没有漏,你心里没底。问题不在 AI 写得漂不漂亮,而在你有没有一套能回滚、能核对的流程兜底。这篇只讲怎么把重构拆成小步、先立回归网、改完按顺序核对,让每一步的可验证性握在自己手里。
换个角度想:AI 重构的本质是「一次大规模的类型替换或结构搬移」,它天生比人快,也天生比人容易顺手多改。你要做的不是限制它写代码的能力,而是限制它一次能影响的范围,并且每次影响之后都有东西替你确认「行为没变」。能做到这两点,出错概率就能压到可控。
AI 重构为什么容易「看着对、其实错」
模型只看到你贴进去的那一段代码。调用方、副作用、全局状态、配置默认值、并发场景,这些常常不在它的视野里,但它不会主动告诉你「这段我判断不了」。它照样输出一份结构漂亮、命名规范、看起来毫无破绽的版本,而你如果只靠读代码确认,读得越快漏得越快。
- 视野受限:只看到片段,看不到调用链和运行时行为,容易把「这里应该不会为空」当成前提
- 顺手优化:它会觉得你的循环写得笨、你的判空多余,于是一边重构一边改语义,重构和改行为混在一起
- 风险均质:在它眼里,抽个函数和改一段计费逻辑难度差不多,不会替你区分哪块碰不得
- 静默替换:把字符串拼接换成模板、把 for 换成推导式这类改动,语法都对,边界行为可能已经变了
- 无法自证:它给不出「我改完行为一致」的证据,能给的只有「看起来一致」
先划边界:哪些能交给 AI,哪些必须人来定
重构出错的根源,八成不是 AI 写错了,而是你把不该交出去的模块交给了它。动手前先做一次分类,把「结构类」和「语义类」分开,前者放心让它跑,后者只让它出方案、人来拍板。
| 改动类型 | 典型例子 | 交给谁 |
|---|---|---|
| 纯结构 | 抽函数、改命名、拆文件、去重复、调目录 | AI 直接改,你只审结构 |
| 局部语义 | 循环换写法、异常分支合并、空值处理重写 | AI 出方案,你逐条确认 |
| 高风险语义 | 并发与锁、事务边界、计费、权限、序列化格式 | AI 只做阅读和解释,人来写 |
| 外部契约 | 对外接口签名、日志格式、配置默认值 | 谁都不许在这轮动 |
还有一条硬规则:一轮只允许一种类型的改动。重构和改行为不要放在同一轮,否则出了问题你根本分不清是结构搬错了还是逻辑改错了。提示词里把「不许改什么」写死,比如不改对外接口签名、不改日志格式、不动配置默认值、不删任何已有的异常处理。
动手前先织一张回归网
很多人跳过这一步直接让 AI 开改,改完才发现没有基准,只能靠肉眼比。回归网的优先级是明确的:先补特征测试,再补单测,最后才是集成测试。特征是「记录当前真实输入输出」,单测是「你期望它是什么」,两者顺序不能反。
- 补特征测试挑这个模块最常被调用的几个入口,喂真实或接近真实的输入,把当前输出原样存成断言。这一步就是给老代码拍快照,不需要你理解它为什么这么输出。
- 跑基线并留档在动手前跑一遍全部测试,确认全绿,把结果和覆盖率存下来。这就是你的对照物,别等改完才发现原本就有红的。
- 锁定边界用例补上空值、超长字符串、负数、并发重入、时区与编码这几类边界输入,它们是最容易在重构后行为漂移的地方。
- 确认测试可重复跑两遍同一套测试,结果必须一致。如果本来就不稳定,先修测试,别拿它当验收标准。
没有测试的老模块,就让 AI 先帮你把现有行为固化成测试,跑通之后再让 AI 重构。这一步看着绕,其实比重构本身值钱:固化的过程就是一次隐性理解,而且这份测试以后每一轮都能复用。
小步走的操作节奏:一轮只做一件事
把「重构一个模块」拆成「一个函数 / 一个文件 / 一个模块」的轮次,每轮结束就提交一次。提交粒度决定回滚粒度,轮次越小,回滚成本越低,你定位问题的速度也越快。
- 一轮只动一个函数或一个文件,改完立刻提交,提交信息写清这轮做了什么
- 每轮固定四步:贴上下文 → 说明约束 → 让 AI 只输出改后代码 → 你本地跑编译和测试
- 上下文给全:相关调用点、类型定义、已有注释一起贴,别只丢一个孤零零的函数进去
- 禁止跨文件连锁改:这轮改 A,就只改 A,发现 B 也要改就留到下一轮
- 每轮结束记录一句「这轮验证了什么」,下一轮出错时能快速缩小范围
提示词里明确「只输出改后的代码,不要解释、不要顺带改其他东西」。如果你用的是网页对话框,改完把代码复制回本地立即跑一遍;如果是带仓库权限的工具,务必确认它没有自动提交或自动改多文件。
改完怎么验证:一个固定的排查顺序
验证不要凭感觉,按固定顺序从最快、最客观的信号往下走。顺序乱了就容易跳步,最后变成「看着没问题」就合了。第一层看编译和类型检查能不能过,第二层跑测试,第三层对比重构前后的输出是否一致,第四层才是人工读关键分支。
| 层次 | 检查什么 | 没过怎么办 |
|---|---|---|
| 1 编译/类型 | 能否构建通过,类型报错是否新增 | 直接改,别往下走 |
| 2 测试 | 单元与特征测试是否全绿 | 回滚本轮再定位 |
| 3 行为对照 | 同输入同输出是否一致,重点看边界 | 回滚本轮,缩小到函数级 |
| 4 人工读 | 关键分支、异常路径、默认值是否被动过 | 补测试再决定是否放行 |
行为对照优先看边界输入:空值、超长字符串、负数、并发重入、时区与编码。这些地方平时不跑,一跑就是线上事故。发现对不上,先把整轮回滚,再在干净版本上定位,千万别在已经改乱的版本上继续叠改动,那样只会越查越乱。
把 AI 的输出当 PR 来审,而不是当答案
AI 给你的东西是一份待审的改动,不是最终答案。审的时候重点看它「顺手多改的地方」:默认值变没变、异常分支是不是被合并了、日志有没有被删、注释掉的老代码有没有被搬家。这些地方它不会主动标出来,但往往才是问题所在。
- 要求它列出改动清单和不确定点,清单里没提到的改动要单独追问一遍
- 警惕静默语义替换:循环换推导式、字符串拼接换模板、判空条件被重写
- 对比重构前后的公开接口、函数签名、配置项名称,任何变化都要有理由
- 看它有没有引入新的依赖或新的工具函数,能不引入就不引入
- 检查注释:它是改成了更准确的注释,还是直接把原有注释删了
如果你用的是能读仓库的工具,让它把改动以 diff 形式给你,而不是直接提交。你要的是审阅权,不是自动合并。审完再手动合,中间留出你自己判断的空档。
留退路:回滚、留痕与长期维护
没有回滚点的重构等于裸奔。每轮一个提交、一个可回滚点,大模块重构用分支隔离,别直接推主干。这样即使某一轮验证失败,你损失的也只是这一轮的几分钟,而不是整个下午的排查。
- 每轮一提交
- 提交粒度等于回滚粒度,越小越好,提交信息写清改了什么、验证了什么
- 分支隔离
- 大模块重构开独立分支,合主干前再跑一次完整测试
- 提示词留痕
- 把这轮用的提示词和约束记下来,下次同类重构直接复用,不用重新摸索
- 补文档
- 改完顺手补注释和模块说明,否则下一轮 AI 又只能靠猜,重复交学费
这些记录别嫌麻烦。重构不是一次性的,同一块代码半年后可能还要再动一次,到时候有提示词和验证记录,第二轮的成本会比第一轮低很多。
什么情况下不该用 AI 重构
有些场景不是「小心用」,而是「先别用」。判断标准很简单:你能不能验证结果。验证不了,就不该让 AI 直接产出可合并的改动。
- 没有版本控制、没有测试、也没有人能确认业务语义的模块,先补基础设施再谈重构
- 对性能极度敏感的热路径,重构后必须压测,只跑单测不够,AI 也看不出来你的延迟分布
- 合规、加密、资金相关逻辑,AI 可以辅助阅读和给建议,但不要让它直接产出可合并的改动
- 正在被多人同时改动的模块,先协调好改动窗口,避免和别人的提交互相踩
- 你对业务语义本身就没搞清楚的模块,AI 只会把不确定性写得更整齐,不会替你消除它
反过来说,只要验证手段到位、回滚路径清晰、改动范围可控,AI 在纯结构类重构上的效率优势是很实在的。它真正的价值是省掉机械的搬移和命名时间,让你把精力花在判断和验证上,而不是替你做判断。
下一步如果你还没确定用哪个工具来跑这套流程,先去站内工具目录按「能读仓库、能出 diff」这两个条件筛一遍;再顺手到模型资料库看看各家在长上下文代码任务上的定位,对照自己项目规模选。→常见问题
让 AI 重构完,怎么快速判断它没改坏行为?
先跑基线和测试,再看边界输入的前后输出是否一致,最后才人工读关键分支。顺序反了就容易先入为主觉得没问题。没测试的老代码,先用 AI 把当前行为固化成特征测试,跑通再动手重构。
能不能让 AI 一次性重构整个模块?
不建议。一次只做一件事、一个文件一轮,每轮提交留回滚点。改得越多,出问题时越难定位是哪一处引起的。真要大改,用分支隔离,分多轮推进,每轮都跑一遍验证。
AI 顺手把逻辑也优化了,算不算问题?
算。重构和改行为必须分开。同一轮里既有结构调整又有逻辑变化,出问题你分不清是哪种引起的。提示词里明确写「只做结构改动,不改行为」,并要求它列出所有改动点。
没有单元测试的老项目怎么开始?
先补特征测试:把现有函数的真实输入输出记录下来当断言,不改实现。这一步可交给 AI 批量生成,但断言值要以实际运行结果为准,人工抽检几条。有网之后再重构,心里才有底。
改出问题了,回滚还是往前修?
优先回滚整轮。在已经改乱的版本上继续叠加修复,很容易引入新的不一致。回滚后把这一轮的提示词和改动缩小范围,再走一次流程,比硬修省时间。