重构翻车通常因为:太大、不可测、悄悄改了行为。下面这 18 个 Prompt 强制更小、可验证的步骤——模型能一次做完,人能不通读整个文件就 review。
这套 Prompt 主要解决什么问题
重构的唯一职责:改结构、不改行为。所以 Prompt 必须 (a) 指出要改的单元,(b) 列出必须保留的不变量,(c) 圈定范围避免模型”顺手改一下”,(d) 强制先给计划或 diff 再动手。
这篇适合谁
用 Claude Code、Cursor、Codex 推大重构的资深工程师;整治遗留模式的 tech lead;在迁移代码范式(callback → async、class → hook、JS → TS)的独立开发者;上线前抽热点函数的 on-call。
什么时候不建议用
编辑器 1 秒就能搞定的单行重命名——别用,Prompt 成本比工作量大。完全没有测试——重构没有安全网就成了重写,这些模板默认有验证环节。别把重构和加功能塞进同一个 Prompt——模型会偷偷把功能塞进”重构”diff 里。
Prompt 结构公式
一个重构 Prompt 应包含 6 个要素:
- 目标单元:具体某个函数 / 文件 / 模块 / 模式——不要”整个代码库”。
- 目标形状:改完是什么样——“抽到模块 X”、“转 async/await”、“拆到每个函数 ≤80 行”。
- 不变量:行为保留、公开 API 保留、测试还绿、不引入新依赖。
- 范围围栏:模型可改的文件列表;其他都是只读上下文。
- 先计划后 diff:先输出迁移计划,等确认,再 apply。
- 验证钩子:跑哪些测试、过哪条 lint、type check 必须干净。
这套 Prompt 适合用在哪
- 模块抽取与 API 表面整理
- 严格类型迁移(TypeScript / mypy / Sorbet)
- 模式现代化(callback → async、class → hook)
- 拆 god 函数 / god 文件
- 把 one-off helper 换成 stdlib
- 跨多调用点的重命名
- Agent 模式重构任务(Claude Code / Cursor 的 agent 模式)
18 个可直接复制的 Prompt 模板
1. 抽取模块
用在一个文件长出两种职责、其中一种应该搬出去。
你是重构 agent。把 {functionality} 从 {source-file} 抽到新模块 {target-path}。约束:source-file 公开 API 保持、所有测试还过、不改行为。输出:(1) 迁移计划编号列表,(2) 新文件内容,(3) source-file 的最小补丁——重新导出被搬走的符号。不动列表外文件。
变量: {functionality}、{source-file}、{target-path}。
Tip: 显式要求 re-export shim,这样老 import 在同一 PR 里不会断。
2. 安全重命名
把 {old-name} 重命名为 {new-name}(全仓库)。步骤:(1) 列每处使用的 file:line,(2) 给一个代表性 call site 的 before/after,(3) 对任何含义现在不对的调用方变量(例如以旧名命名的局部变量)建议保语义重命名。不要 find-and-replace;给出每文件 diff,然后停下等我 review。
3. 内联过度抽象的 helper
函数 {name} 只被使用一次。请在调用点内联。输出:两个文件的 diff、一句话确认行为完全一致、我应该重跑哪条测试命令。
4. 继承换成组合
下面是一个类层级。请给出基于组合的重构方案。输出:(a) 新组件/策略接口,(b) 每个类的迁移计划,(c) 哪些测试需要改、为什么,(d) 应用变更的顺序——保证每一步 build 都绿。
层级:{paste}
5. callback → async/await
下面是 callback-based 代码。转 async/await。保留错误语义(rejected promise 错误形状必须和原 callback 收到的一致)。标出任何行为微差(例如并行变串行)。输出 diff 加一节"行为差异",列每个可能改变语义的地方。
代码:{paste}
6. 严格类型迁移
把 {file} 从松类型迁到严类型({source-config} → {target-config})。第 1 遍:识别所有隐式 any / unknown cast / 缺返回类型。第 2 遍:先修最有把握的;不确定的类型先留 `// TODO type`。不改运行时行为。
文件:{paste}
7. 拆 god 函数
函数 {name} 200+ 行。请拆成更小函数。每个新函数:名、单句职责描述、签名。不改行为。按可以一段一段独立提交(每个 commit 都绿)的顺序输出 diff。
函数:{paste}
8. 自制 util 换成 stdlib / 库
下面是自制代码。识别在重复造 stdlib 或常用库轮子的函数。每处匹配:行号范围、建议替换(含 import 路径)、删除前我应该验证的 1 个 edge case。
代码:{paste}
9. 边界重构——把 I/O 推到边缘
函数 {name} 把 I/O(网络 / 磁盘 / DB)和纯逻辑混在一起。请重构成把 I/O 推到边缘:抽一个纯内层函数(输入是已取到的数据,输出是结果);外层只留薄薄的 I/O 壳。输出:新签名、一句话说明现在哪些原本不可测的部分变可测了。
10. 删死代码
审计 {scope} 的死代码:未导出且无内部调用的符号、导出但下游零使用的符号、值已写死的 feature flag、永远不会执行的分支。每个:file:line、判定它是死代码的证据、建议删除步骤。跳过任何反射 / 动态调用(字符串 key 访问)。
11. Hooks 重构(React)——抽自定义 hook
组件 {name} 把 state、effect、render 混在一起。把数据层抽到自定义 hook `use{Name}`,返回 `{ data, loading, error, refetch }`。组件留作纯 render。输出新 hook 文件、组件 diff、每个关注点 1 个测试思路。
12. 数据库查询重构——把 N+1 收成单次拉取
下面是一段在循环里每次发查询的代码路径。请重构成单次批量拉取。约束:结果顺序保留、错误语义保留(一处失败仍以一个错误浮出)、不引入新 ORM 特性。输出:diff 加一段说明现在依赖哪个 DB 索引。
代码:{paste}
13. promise 链转 async/await
把下面的 promise 链转 async/await。完整保留 `.catch` 语义——每条 reject 路径都还要被处理。如果删掉某个 `.then` 分支,请用 1 行说明理由。输出 side-by-side before/after。
代码:{paste}
14. 两步弃用重构
弃用 {api-name}。第 1 步(本 PR):新 API 与老 API 并存、给老 API 标 @deprecated、把一个代表性 call site 切到新 API 作为证据。第 2 步(不在本 PR):迁移其余 call site。输出:剩余 call site 的迁移顺序——最容易的先。
15. 跨文件常量合并
{constant} 在 N 个文件里重复(粘贴)。请合并到单一来源。输出:规范化的文件 / 位置、每个消费方的 diff、一项检查(合并前每个原位置的值都一致)。
文件:{paste}
16. Agent 模式重构简报(Claude Code / Cursor agent)
你有仓库访问权限。把 {pattern} → {new-pattern} 重构跨 {scope} 应用。规则:(1) 每个 commit 一个文件,(2) 每个 commit 后测试必须过,(3) 公开 API 不变,(4) 遇到模糊就停下问我——不要猜。先按 commit 顺序列出你打算改的文件,等我说"go"。
17. 行为保留测试生成
下面是我即将重构的函数。动手前,请写 6 个特征化测试锁定当前行为——其中 2 个测覆盖现有测试漏掉的 edge case。重构后我会重跑,必须仍过。
函数:{paste}
18. 重构 diff sanity check
下面是我即将以"纯重构"合并的 diff。请审计:任何可能改变行为的变化——控制流、错误处理、返回形状、异常类型、null 处理、顺序。每处嫌疑:file:line、潜在差异、用什么测试能确认。
Diff:{paste}
容易踩的坑
- 大爆炸重构无验证。 Prompt 没要求先写测试;模型返回 400 行,你不知道哪里坏了。
- 行为改动偷偷塞进重构。 模型在重构时”顺手”修了 bug——diff 现在混着两种意图,review 时间翻 3 倍。
- 重命名跳过搜全使用。 一个文件改完;其他地方某个字符串 key 引用还指向旧名,运行时悄悄坏。
- 重构和加功能塞同一个 Prompt。 模型返回重构 + 你没要的新选项。一个 Prompt 一个意图。
- 没有范围围栏。 没显式”不要碰 X”,模型会扩散到相邻文件,因为它看到不喜欢的东西。
- 没有”先计划后 diff”步骤。 直接出补丁;apply 后才发现计划错了。
- 轻信模型的”行为没变”声明。 永远跑模板 17 的特征化测试——模型在这一点上错得意外频繁。
下一步怎么继续提升
- 每个 Prompt 锁定一个重构模式——抽取、重命名、内联。混在一起就稀释信号。
- 在 agent 模式里强制每个 commit 一个文件。回滚更容易、review 更容易、两天后 bisect 更容易。
- 把diff sanity check(模板 18)作为对模型自身输出的第二遍 pass。
- 跨多文件迁移时,先让 AI 按风险给文件排序(调用方最多、测试最多),低风险先做建立信心。
- 重构 Prompt 永远配特征化测试(模板 17)。变更前 pin 住的测试才说明实际改动。
- 用范围围栏让模型守规矩:“可改文件:A、B、C。其他只读。“放第一行,agent 模式也会守。
- 重构后,让模型用 5 个 bullet 把 diff 反向解释给你。如果它无法干净总结,说明重构做太多了。
FAQ
- 重构 Prompt 和代码 review Prompt 有什么区别? 重构改代码、review 评估代码。用代码 review Prompt审重构 Prompt 产出的 diff。
- 为什么模型重构时一直在加功能? 约束漂移。在 Prompt 末尾加一句:“如果重构中发现 bug 或缺失功能,列到 NOTES 一节,但不要改代码。” 这样意图就隔离了。
- 一个 Prompt 能做多大的重构? 大约一个函数、一个文件、或跨 ≤5 个文件的同一模式。再大就拆——模型会丢失不变量,你 review 时也会。
- agent 模式可以让它自动 apply 重构吗? 仅在每 commit 一个文件 + CI 跑测试的前提下。否则两天后某处坏了,你失去 bisect 能力。
- AI 说”行为没变”但我的测试挂了怎么办? 信测试。让模型把自己的输出和原文 diff,找语义实际偏移的那一行——通常它能找出来。
- 重构还是重写? 文件 >50% 改动 = 重写。这种情况用迁移规划 Prompt,不是重构 Prompt。
相关阅读
- 代码 review Prompt —— review 重构产出的 diff
- Claude Code 执行 Prompt —— 配合模板 16-18 的 agent 模式
- 迁移规划 Prompt —— 变更太大、不能叫重构时用
- Bug 审计 Prompt —— 重构前知道哪些行为必须保留
- 测试生成 Prompt —— 生成模板 17 的特征化测试
- API 契约 review Prompt —— 确认重构没改公开表面
- AI 重构工作流 —— 端到端工作流,按顺序串这些 Prompt