故事:一个凌晨2点被叫醒的模块
那是一个周二凌晨两点。告警群炸了:订单处理服务延迟飙到 12 秒,正常应该在 200ms 以内。我翻出那个模块的代码,差点没把咖啡喷屏幕上——一个 order_processor.py,2173 行,没有类型注解,没有文档字符串,except: pass 出现了 14 次。
这是三年前某个离职同事留下的”杰作”。需求一直往上堆,没人敢动它——因为一动就炸。但今晚它炸了,而且是在我没有选择的情况下。
这篇文章不讲”AI 编程入门”,也不搞工具横评。我就讲一件事:当你面对一个 2000 行的遗留代码模块,怎么用 Cursor/Copilot 安全地把它重构成可维护、可测试的生产级代码——以及我踩过的坑。
第一步:让 AI 读懂代码,而不是生成代码
很多人用 Cursor 的第一反应是:选中整个文件,Ctrl+K,输入 “refactor this”。这是最蠢的做法——2000 行代码塞给 AI,它只会给你一个看似合理但暗藏 Bug 的版本。
正确的第一步不是让 AI 写代码,而是让它帮你理解代码。
技巧 1:用 AI 生成模块地图
我用 Cursor Chat(Cmd+L)选中整个文件,输入:
Analyze this module. Output:
1. All public functions with their signatures and one-line purpose
2. Dependencies between functions (who calls whom)
3. External dependencies (imports, DB calls, API calls)
4. Potential side effects (mutations, I/O, global state)
5. Areas most likely to cause bugs (ranked by risk)
Cursor 花了大约 30 秒给了我一张完整的”模块地图”。这一步的价值远超过后面任何一步——你只有当真正理解代码的依赖关系时,重构才不会引入新 Bug。
从这张地图里我发现了几个致命问题:一个全局字典被 7 个函数修改、3 个函数共享同一个 requests.Session 但没有加锁、异常处理全是裸 except。
技巧 2:用 AI 生成测试用例,以测试驱动重构
在动手改任何一行代码之前,我先让 Cursor 生成测试:
Write pytest tests for the following functions. Focus on:
- Happy path
- Edge cases (empty input, None, very large input)
- Error paths (network failure, timeout, invalid data)
Use fixtures and parametrize where appropriate.
[粘贴相关函数代码]
这里有一个关键点:不要直接信任 AI 生成的测试。我手动 review 了每一个测试用例,发现 Cursor 在两个地方错误地理解了业务逻辑(它以为某个字段的默认值是 0,实际上是 None)。修正后,这些测试成了我重构的安全网——每改一个函数就跑一次测试,红了就回退。
最终生成了 47 个测试用例,覆盖了核心逻辑的 80% 以上。这花了我 20 分钟——比手写快了至少 5 倍。
第二步:分而治之,一次只重构一个函数
很多人用 AI 重构的失败模式:选中整个文件 → “重构” → 跑不起来 → 放弃。正确的做法是按依赖关系从叶子节点开始,一次一个函数。
实战:重构一个 80 行的订单校验函数
原函数大概长这样:
def validate_order(data):
# 80 lines of nested if-else with 14 return statements
if data.get('amount'):
amt = float(data['amount'])
if amt <= 0:
return False, "Invalid amount"
else:
return False, "Missing amount"
if data.get('items'):
for item in data['items']:
if not item.get('sku'):
return False, "Missing SKU"
# ... 50 more lines ...
# ... even more nested checks ...
return True, "OK"
我的做法:选中这个函数,在 Cursor Chat 中输入:
Refactor this validation function:
1. Split into smaller single-responsibility functions
2. Use a dataclass or TypedDict for the input
3. Replace (bool, str) return with proper exceptions or a Result type
4. Add type hints
5. Make each validation rule independently testable
6. Keep the exact same behavior — do not change any logic
Cursor 给出了一个漂亮的方案:用 dataclass 定义输入模型、每个校验规则封装成独立函数、用异常类代替 (bool, str) 元组。我逐行对比了原逻辑和新逻辑,确认行为一致后,跑测试——47 个测试全部通过。
这里有一个容易被忽视的技巧:Prompt 里一定要加 "do not change any logic"。不加这句话,AI 可能会"聪明地"帮你修改业务规则,比如把 amt < 0 改成 amt <= 0,因为它"觉得这样更合理"。
第三步:让 AI 帮你找 Bug,而不是帮你写新 Bug
重构完所有函数后,我让 Cursor 对整个模块做了一次安全审计:
Review this module for:
1. Race conditions (shared mutable state without locks)
2. Resource leaks (unclosed connections, file handles)
3. Silent error swallowing (bare except, except: pass)
4. SQL injection risks
5. Incorrect exception handling (catching too broad or too narrow)
6. Performance bottlenecks (N+1 queries, unnecessary copies)
Output each finding with file:line, severity, and fix suggestion.
Cursor 找到了 23 个问题。其中让我后怕的是:
# 原代码 — 悄无声息地吞掉了所有异常
try:
result = external_api.call(payload)
except:
result = default_value # 连 ConnectionError 都被吞了!
# Cursor 建议的修复:
try:
result = external_api.call(payload)
except (ConnectionError, Timeout) as e:
logger.warning("API call failed, using default", extra={"error": str(e)})
result = default_value
except Exception as e:
logger.error("Unexpected API error", exc_info=True)
raise # 未知异常不要吞!
就是这个裸 except 导致了凌晨的告警——外部 API 返回了一个新的错误码,被静默吞掉后下游数据全部错乱,但没有任何日志。
第四步:重构后的效果对比
重构总共花了大约 3 个小时(包括理解代码、写测试、逐个函数重构、跑回归测试)。代码行数从 2173 行降到 1247 行(因为去掉了大量重复逻辑和死代码),但可读性完全不是一个级别。
关键指标对比:
| 指标 | 重构前 | 重构后 |
|---|---|---|
| 函数平均行数 | 87 行 | 28 行 |
| 圈复杂度(平均) | 14.3 | 4.7 |
| 测试覆盖率 | 0% | 82% |
| 类型注解覆盖率 | 0% | 100% |
| 异常处理空 catch | 14 处 | 0 处 |
| P99 延迟 | 12.3s | 180ms |
延迟从 12 秒降到 180ms 主要不是因为"AI 重构",而是因为重构过程中发现了那个被吞掉的 API 异常——修复后不再超时重试。AI 的价值不在于写代码更快,而在于降低发现这些问题的门槛。
五条实战经验:怎么让 AI 重构真正靠谱
1. 先测试,后重构
这是铁律。没有测试覆盖的重构等于赌博——不管你是手写还是 AI 生成。花 20 分钟让 AI 生成测试用例 + 你手动 review 修正,这笔投资稳赚不赔。
# 每次改一个函数后立即跑测试
$ pytest tests/test_order_processor.py -x --lf
# 红了就 git checkout 那个函数,重新来
2. 小步提交,每改一个函数 commit 一次
git commit -m "refactor: extract validate_amount() from validate_order()"
git commit -m "refactor: convert OrderData to dataclass"
git commit -m "refactor: replace (bool, str) with Result type"
# 而不是
git commit -m "refactor: rewrite entire module" # ❌
小步提交的意义:出问题时 git bisect 能精确定位到是哪个函数的改动引入了 Bug。大提交的话你只能整个回退。
3. Prompt 里必须加 "preserve exact behavior"
AI 的默认倾向是"优化",但重构的目标是"等价变换"。这两句话效果完全不同:
# ❌ 危险 — AI 会按自己的理解"改进"
"Refactor this function to be cleaner"
# ✅ 安全 — AI 只在结构上调整
"Refactor this function: split into smaller functions, add types,
use exceptions instead of (bool, str). Preserve exact behavior —
do NOT change any business logic, edge case handling, or return values."
4. 用 Git Diff 做 AI 代码的人工审查
不要直接在 Cursor 里点 "Accept All"。我习惯用 git diff 逐段审查 AI 的改动:
# 在 Cursor 里应用修改后,立即在终端:
git diff --word-diff=color | less
# 逐段检查:这个地方的逻辑确实等价吗?默认值变了没有?边界条件处理对了吗?
我在这次重构中发现过 AI 的两类典型错误:一是把 data.get('amount', 0) 改成了 data.get('amount') or 0(前者只有 key 不存在时用默认值,后者在值为 0/空字符串时也会替换——这是 Python 的经典坑);二是把一个 sort(key=lambda x: x.created_at) 的排序方向反转了(因为它在另一个函数里看到 "降序" 的注释就全局做了推断)。
5. 不要连续重构超过 3 个函数而不跑测试
人的注意力有限,AI 也一样。重构到第 4、5 个函数时,你会开始"信任"AI 的输出,跳过大段 diff。这是危险的信号。我的规则:每改 3 个函数就跑一次完整测试套件,如果全绿就 commit,进入下一轮。
AI 重构不是银弹:什么时候不该用
说了这么多,我也必须坦诚地讲 AI 重构的局限性:
- 核心算法逻辑不要交给 AI 重构 — 比如排序算法、状态机、加密逻辑。这些改一行就可能全盘皆错,而 AI 的测试覆盖率不足以捕捉这些 Bug。
- 涉及金融计算/金额处理的代码 — 浮点数精度问题 AI 经常忽略。宁可手写,每条都加注释。
- 性能关键路径 — AI 生成的代码更"整洁"但往往更慢(多了函数调用开销)。如果是热路径,重构后要加 benchmark 验证。
- 多线程/异步代码 — AI 对并发安全的判断经常出错。它可能会把一个线程不安全的操作移到另一个线程里。
总结:AI 重构的方法论
如果你面对一个需要重构的遗留模块,这是我的推荐流程:
- 理解(30 分钟):用 AI 生成模块地图、调用关系图、风险点列表
- 设防(20 分钟):用 AI 生成测试,人工 review 修正后运行确认全部通过
- 重构(2 小时):从叶子函数开始,一次一个,每次改完跑测试、commit
- 审计(30 分钟):让 AI 做安全审计,人工逐条确认修复
- 上线(30 分钟):灰度发布,观察监控指标
总共 3-4 小时,把一个没人敢碰的模块变成可维护的生产代码。如果没有 AI 辅助,同样的工作量至少需要 2-3 天。
AI 在这里的角色不是"替你写代码",而是降低理解成本、加速机械劳动、发现隐藏问题。真正的决策——什么该改、什么不能动、怎么验证——仍然是你自己的判断。
⚠️ 免责声明:本文讲述的是我在生产环境中使用 AI 编程工具的真实经历和踩坑经验。不同的代码库、团队规范和业务场景可能需要不同的策略。AI 生成的代码必须经过人工审查才能用于生产环境。
FAQ
Q: Cursor 和 Copilot 哪个更适合做重构?
Cursor 的 Chat 和 Composer 模式在重构场景更好用——你可以在 Chat 里给一个完整的上下文和约束,它一次性给出改动方案。Copilot 更适合小范围的"写一个新函数"。重构用 Cursor,日常编码用 Copilot,这是我的分工。
Q: AI 重构会不会引入安全漏洞?
会的。我在审计中发现 AI 有时会把 SQL 查询从参数化改成字符串拼接(因为它"觉得这样更简洁")。这就是为什么第四步的 AI 安全审计和人工 review 不可省略。你用一个 AI 写的代码,用另一个 AI(或者同一个但换 prompt)来审计,这是最基本的防御。
Q: 多少行代码的模块适合用 AI 重构?
500-5000 行的单个文件效果最好。小于 500 行自己改更快,大于 5000 行 AI 的上下文窗口不够,需要先手动拆模块。2000 行左右是 AI 重构的甜蜜点。
相关文章
- 让AI生成的代码真正能用:从GitHub Copilot到生产环境的5道质量关卡 — 本文的姊妹篇,讲怎么让 AI 代码过审
- 用 LLM 搭建自动化代码审查流水线 — 把你从手动 review 中解放出来
- 2026年AI编程工具深度横向评测 — 选工具之前先看这篇
- Python性能剖析三件套:py-spy、Scalene、memray实战对比 — 重构后别忘了测性能