老系统没人敢动?用AI做遗留代码迁移的六步法
遗留系统迁移最大的成本不是写新代码,而是理解旧逻辑。本文给出一个以「行为快照」为核心的AI辅助迁移流程,把不可验证的重写变成可对照的工程。
几乎所有公司都有一块“没人敢动”的代码:没文档、原作者离职、跑着但不知道它在算什么。业务想重构,技术评估的结论永远是“需要六个月”。
AI 编程助手让这件事出现了转机,但不是因为它写得快——是因为它擅长读你不愿意读的东西。
关键在于方法:把“重写”变成“对照”。
核心思路:行为快照优先于代码理解
传统迁移顺序是:读懂旧代码 → 设计新架构 → 写新代码 → 测试。前两步是黑洞。
更有效的顺序是:先固化旧系统的行为,再重写,最后用行为快照做对照。
原因很简单:旧系统的“正确”不是文档定义的,是它当前的行为定义的。只要新系统在相同输入下产生相同输出,就完成了迁移——不管旧代码当初为什么那样写。
这就是金丝雀迁移的思路。
六步法
第一步:圈定边界与入口
不要“重构整个模块”。找出系统与外界的全部接触面:HTTP 接口、定时任务、消息队列消费点、导出文件。
逐个列出输入形态。这一步不需要AI,需要耐心,也是最容易漏的。
漏掉一个入口,后面所有的对照都是残缺的。
第二步:采集真实输入语料
从生产日志/数据库中捞出至少 10000 条真实输入,覆盖:
- 最常见路径(占70%以上)
- 边界值(空、超长、负数、零、非法编码)
- 一年内的历史异常(批量导入那天的数据、大促的极值)
存成一个可回放的语料集。这份语料后面会成为你唯一的裁判。
第三步:给旧系统拍行为快照
批量回放语料到旧系统,把输入 + 输出 + 副作用全部落盘。
副作用也要记:写了哪几行数据库、发了哪些消息、调了哪些外部接口(用 mock 拦截记录)。
这是本方法的核心资产。以后每次改新系统,都用它做回归。
第四步:用AI做“逐块翻译 + 意图注释”
这是AI辅助真正发挥的地方,但用法和大多数人不同。
不要扔整个文件说“帮我重写”。正确的提示词模式是:
这是旧系统的一个函数(附代码)。请完成两件事:
- 用自然语言描述它实际做了什么,包括每个分支的触发条件和它修改的字段;
- 指出其中的可疑之处——看起来像是历史遗留的补丁、边界特判、防御性但永不触发的代码。
第2项极有价值。AI 会标出类似 if (x == null) return 0; // 但有日志显示从未进入 的地方,你可以逐个确认哪些是业务规则、哪些是当初的临时补丁。
必须人工确认每一条可疑点。这是整个流程里最需要人的地方。
第五步:重写,并同步生成“意图文档”
重写时让AI同时产出两份东西:新代码 + 一份逐函数的意图说明(这个函数确保什么业务不变量)。
这份文档比任何事后补文档的方式都靠谱,因为它是写在理解还热的时候。
同时,对每一个“看似多余的保护性代码”,在代码注释里写明:保留/删除/原因。半年后接手的人会感谢你。
第六步:双跑对照
新系统部署到旁路,和旧系统同时接收真实流量,比较结果。
对比维度要分层:
| 层级 | 判定 | 处理 |
|---|---|---|
| 输出结构 | 字段齐全、类型一致 | 自动 |
| 核心数值 | 精确相等(金额、数量、状态码) | 自动,不容忍偏差 |
| 文本/展示 | 语义等价即可 | 抽样人工 |
| 副作用 | 数据库写入、消息内容一致 | 自动 + 人工抽查 |
核心数值必须精确相等。如果新系统算出来的金额差1分,不要“可接受”,去查为什么——通常是浮点精度或舍入模式差异,而这种差异在规模起来后会变成大问题。
一个必须提前想清楚的问题
旧系统的Bug,新系统要不要保留?
双跑对照时,你会发现旧系统在某些输入下算出明显错误的结果。修还是不修?
我们的建议是:第一轮照抄,第二轮再改。
第一轮目标是“行为完全等价”,任何改动都会让你无法区分“这个差异是我引入的bug还是我修正的旧bug”。先等价,锁定一个可信基线,再在这个基线上做修正,每次修正都有可测的差异。
这个纪律能让迁移从“永远说不清有没有问题”变成“差异清单可穷举”。
成本预期
一个 20 万行的遗留系统,用这套方法迁移,团队实测大约 6~10 人周(不含验收)。相比传统评估的六个月,差距主要来自两处:
- AI 读代码替代了人工考古;
- 行为快照替代了不可靠的“需求文档”。
而不变的部分是:理解业务、判断可疑点、验收结果,这些仍然必须由人做。 AI 加速的是阅读和写作,不是判断。
这就是它对遗留系统的真实价值:把“不敢动”,变成“动了能验证”。