用 AI 把 COBOL 迁移到 Java,结果连 50 年前的 Bug 都原样搬过来了
最近在处理老旧系统迁移时,我发现一个很扎心的事实:很多人把大模型当成“系统升级工具”,但实际上它目前更像是一个“高级翻译机”。如果你直接把一段 COBOL 代码丢给 AI,让它翻译成 Java,你得到的绝不是一个优化后的现代系统,而是一个用 Java 语法写成的、带着几十年前陈旧逻辑的“僵尸系统”。
最典型的问题在于,AI 在做代码迁移时,本质上是在执行语义映射,而不是在进行架构重新设计。它无法分辨哪些是核心业务逻辑,哪些是当年为了应对硬件限制而打的临时补丁。我之前分析过一个账务模块的迁移案例,结果令人啼笑皆非:原 COBOL 程序里有一个关于闰年计算的逻辑缺陷,导致特定日期会多算一天利息;结果 AI 在生成 Java 代码时,不仅完美保留了这个 Bug,甚至连 Y2K(千年虫)时代为了兼容日期而写的那些古怪补丁,都被它当成“关键业务逻辑”原封不动地复刻到了新代码里。
更离谱的是,很多 COBOL 程序中存在大量已经失效的死代码路径(Dead Code),在现代业务场景下根本不会被触发。但 AI 为了追求所谓的“逻辑等价”,会将这些毫无意义的代码分支全部搬到 Java 里。这意味着你以为在做数字化转型,实际上是在给五十年前的程序员写的 Bug 续命。
这其实揭示了目前 AI 迁移方案的一个核心风险点:大模型无法区分“业务逻辑”与“历史包袱”。当你要求 AI “保持逻辑一致”时,它会忠实地搬运所有缺陷;而当你要求它“清理代码”时,它又极有可能把那些没有注释、但实际上在运行中起关键作用的隐式约定给删掉。这种两难境地让很多全量迁移的项目最后变成了巨大的调试噩梦。
在这种背景下,我认为人在迁移流程中的角色必须转变。你不能把自己定位成“审核员”,在 AI 翻译完之后去检查对不对,因为面对几万行复杂的旧代码,你根本查不出所有潜伏的坑。正确做法应该是:在 AI 介入之前,先定义好“什么是 Bug,什么是 Feature”。
我在实际操作中采用的是“逐模块带约束移植”策略,而不是宏大的全量迁移。具体流程是先将遗留的 COBOL 程序拆分成细粒度的模块,由人工标注出已知的缺陷区域,并在注释中明确标出。随后,我将每个模块单独喂给 Claude Code,并在 Prompt 中加入极其严格的约束指令,例如:
以下函数包含已知缺陷(见注释),迁移到Java时:
1. 保留业务语义,不修正已知缺陷(除非明确要求)
2. 识别并标记疑似死代码,不自动删除
3. 对日期计算逻辑单独输出警告
通过这种方式,我把 AI 的职责从“猜测逻辑”变成了“执行指令”。这样即使 AI 翻错了,或者原代码本身就有问题,我也能通过它输出的警告信息快速定位。在这种模式下,AI 成了我的探测器,而我才是那个决定代码去留的裁判。只有把迁移过程从“黑盒翻译”变成“受控移植”,才能真正摆脱历史包袱的纠缠。
把 50 年前的 Bug 原封不动搬过来也太离谱了,AI 这次是把老古董给‘完整复刻’了啊!