Refactor Legacy Prompt:安全地给老代码动手术
让 AI 按「先锁行为、再小步改、每步可验证」的纪律重构遗留代码:列测试锚点、圈出高风险区、给出分步计划,禁止一次性大改写。强调保留外部行为、降低回归风险。
发布 2026-09-06用法
把要重构的文件 / 模块贴进去,明确「目标」(降耦 / 提可读性 / 抽函数 / 去重复),让 AI 出一份可逐步执行、每步可回滚的重构计划。适合接手祖传代码、偿还技术债前先对齐方案。
什么时候用
- 接手祖传模块、改动面大于你能在脑内模拟的范围——先让它出锚点与分步计划,再决定动不动。
- 重构前需要和团队对齐方案——这份计划本身就是一份可评审的 RFC 草稿。
- 代码没有测试但必须改——用「行为锚点」这一步逼出「先补什么最小测试」。
- 想让 AI 在 Claude Code / Cursor 里自主跑多步重构——把「每步验证 + 回滚路径」写进提示词,是防止它一次性大改写的唯一有效手段。
什么时候别用
- 目标本身就是改行为(加功能、改接口)——那是开发任务,不是重构。混在一起会让「行为没变」这条铁律失效。
- 单文件、几十行、一眼看完的改动——直接改更快,走流程反而是负担。
- 你已经知道该怎么改——提示词的价值在逼出你没想到的风险点;如果你已有完整方案,直接用
/review校验即可。 - 没有版本控制兜底——本模板的回滚策略依赖
git checkout,没进版本库的代码别用本模板。
Prompt
你是一位谨慎的重构专家。我要对下面的遗留代码做重构,目标是:{降耦 / 提升可读性 / 抽公共函数 / 消除重复 — 选 1,可补描述}。
# 铁律(不可违反)
1. 不改变外部可观察行为:输入输出、公共接口、副作用保持不变。
2. 小步前进:把改动拆成一系列独立、可编译、可单测的小步骤,禁止一次性大改写。
3. 每步可验证:明确这一步改完后跑哪条命令 / 哪个测试来确认没炸。
4. 不引入新依赖、不改目录结构、不顺手「优化」无关代码。
# 输出要求
- 第一步:先列出「行为锚点」——哪些已有测试 / 日志 / 接口能证明行为没变?没有就先建议补什么最小测试。
- 第二步:标出高风险区(隐式依赖、全局状态、被多处调用),这些区域最后动、最小动。
- 第三步:给出分步计划,每步格式:
「步骤 N:{做什么}|风险:{low/mid/high}|验证:{命令/测试}|回滚:{git checkout 该文件}」
- 结尾给一句话总原则:本次重构的「绝不越过」的边界。
<粘贴代码 / 文件路径>
为什么有效
- 「不改外部行为」铁律:把重构和「顺手加功能」切开,避免范围蔓延引入回归。
- 行为锚点前置:没有测试覆盖的遗留代码直接重构 = 赌博;先逼出锚点降低风险。
- 每步可回滚:小步 +
git checkout回滚路径,出问题立刻撤,不卡在半改写状态。 - 高风险区最后动:全局状态、被多处引用的代码最易炸,放到计划末尾最小改动。
验收判据:怎么判断它给的方案能用
别看计划「写得好不好看」,看这六条。任何一条不满足,就把它打回去重写:
| # | 判据 | 不合格的典型表现 |
|---|---|---|
| 1 | 行为锚点具体到可执行的命令 | 写「有单元测试覆盖」却不给测试文件名与断言 |
| 2 | 每一步都能单独编译 / 单独跑通 | 出现「步骤 3 依赖步骤 5 的改动」这类交叉依赖 |
| 3 | 每步都给了验证命令 | 只有「改完后测试通过」这种无法执行的表述 |
| 4 | 每步都给了回滚路径 | 只写 git checkout 却不指明具体文件 |
| 5 | 高风险区被单独标出并排在后面 | 全局状态与高频调用函数混在普通步骤里 |
| 6 | 没有夹带无关改动 | 出现「顺便」「同时」「顺手」——这是范围蔓延的信号 |
最硬的一条验收是变异测试(mutation testing):如果你的行为锚点真的有效,故意改坏一处实现,测试应该失败。改坏了还全绿,说明锚点是假的,重构后的「没炸」也不作数。
# 以 Stryker(JS/TS)为例:锚点是否有效,用变异分数说话
npx stryker run --mutate "src/target-module/**/*.ts"
# 分数低 = 测试没真正锁住行为 → 先补测试再重构,别急着动代码
变异测试跑得慢、且对无断言的「烟雾测试」无效;小模块用、整库慎用。
变体 A / B / C
A · 只出计划不动手(评审用) —— 在铁律前加一句:
只输出重构计划,不要修改任何文件、不要输出完整改写后的代码。
计划里每步的文件路径必须是我仓库里真实存在的路径。
B · 边改边验(交给 agent 自主跑) —— 在输出要求末尾追加:
执行时严格按步骤串行推进:每完成一步立即运行该步的验证命令;
验证失败立即用该步的回滚路径撤销,然后停下报告原因,不要继续下一步。
全部步骤完成后,输出一张「步骤 / 验证结果 / 是否回滚」的汇总表。
C · 无测试遗留代码专用(先补锁再动刀) —— 把第一步换成:
第一步改为「先写锁定当前行为的特征测试(characterization test)」:
只描述代码现在实际做什么(包括看起来像 bug 的行为),不要修正它。
测试通过后再进入分步计划。
B 变体是唯一建议交给自主 agent 跑的写法——它把「验证失败就停」写成了硬约束。没有这句,agentic coding 场景下最常见的失败就是一口气改完十步,最后一步炸了,前面九步的 diff 混在一起无法定位。
进阶(自动化)
配合 Claude Code 的 /review 或 CI 单测,让计划里的每一步改完即跑测试:
# 每步改完
npm test -- --watch=false 2>&1 | tail -20
# 有问题立刻回滚
git checkout -- path/to/changed/file.ts
反例(AI 默认会写的烂重构)
「我重写了整个模块,更优雅了,顺便加了 3 个新配置项。」——违反铁律 1/4,行为可能已变、范围爆炸。
「步骤 3:把 formatUser() 抽出到 user.util.ts,保持签名与返回不变;验证:npm test user;回滚:git checkout -- src/user.ts。」
没有测试就直接改被 12 处调用的函数。 先列「12 处调用 + 现有单测覆盖 3 处」,标红未覆盖区,建议先补最小冒烟测试再动。
延伸阅读
- 代码审查:Code Review Prompt
- 测试生成:Test Generation Prompt
- 编码范式:Agentic Coding