Anthropic官方近期发布了一篇博客,详细介绍了团队内部如何利用Claude Code进行大规模代码迁移。这篇文章的含金量极高,其中两个案例尤为震撼。
第一个案例,前端领域热门的工具Bun的创始人Jarred Sumner(目前也是Anthropic的技术员工),借助Claude Code将Bun从Zig语言重写为Rust。整整53万行代码,仅用11天便完成,且100%测试通过后顺利合并上线。
第二个案例,Anthropic Labs的联合负责人Mike Krieger仅用一个周末,将一个Python项目迁移为16.5万行TypeScript,全平台构建时间从30分钟骤降至约2秒。
一个周末,重构16.5万行代码,这是什么概念?
以往这种量级的工程,再顶尖的团队也需要耗费一两年,且未必能实现100%兼容。如今,一个人加上AI,短短几天就能完成。
大家一定很好奇,他们究竟是如何做到的?背后有哪些方法和技巧?下面结合官方博文内容、Bun官方的技术博客以及一些AI编程的实战经验,带来一份完整的深度中文解读。掌握这套方法后,数万行代码的项目重构、技术栈升级、老旧项目翻新,都能用同样的思路高效推进。
AI迁移代码的核心思路
用AI进行代码迁移时,你的工作不是修改代码,而是在设置「产出代码的流程」。
传统的代码迁移,大家习惯一个文件一个文件地翻译,翻译完逐个检查,发现问题逐个修复。这种方式在只有几十个文件时还行得通,但一旦文件数量成百上千,基本就不可行了。
正确的思路是把注意力放在流程上。当你发现AI在某类翻译中反复出现同样的错误,不要逐个去修正那些错误的代码,而是去完善规则手册,让所有后续翻译都不会再犯这类错误。随着规则越来越完善,需要人工干预的次数会越来越少。
刚开始使用AI编程时,常常是一个个手动修复Bug。AI犯了一个错,纠正一次,下次又犯同样的错,再纠正一次,反反复复,效率极低。后来,我开始把踩过的坑写进CLAUDE.md / AGENTS.md 或者 Rules 文件里,每次纠正AI的错误都顺手沉淀为规则。
举个例子,发现AI生成Spring Boot接口时总是忘记加参数校验注解,就加了一条规则:
所有Controller层的请求参数必须使用 @Valid + DTO 校验,禁止在Service层手动if判空
从此,这个问题再也没出现过。
因此,无论是百万行代码迁移,还是日常的Vibe Coding项目,都应具备这个意识:出了问题不要只盯着问题本身,要去修复产出问题的源头。
六步迁移法
Anthropic总结了一套完整的大规模代码迁移流程,共六步。
开局一张图,这套方法论的大致轮廓就清晰了。
0、搞定验证机制
在动手迁移之前,必须有一个可靠的验证机制。没有验证机制,你根本不知道什么时候可以收工。
最理想的情况是像Bun一样,已经有一套完整的测试套件,且测试是用第三方语言写的(Bun的测试用的是TypeScript),不依赖被迁移的语言本身。
但如果你的测试与源代码是同一种语言呢?建议先把测试分类。哪些测试是通过外部接口验证行为的?哪些是依赖内部实现细节的?外部接口的测试可以直接复用,内部实现的测试需要重写成与语言无关的形式。
开头提到的例子中,Mike的项目没有现成的测试套件,他的做法是让Claude创建一个对比脚本,跑7个真实场景,将Python版本和TypeScript版本的输出做diff,任何行为差异都算Bug。
这个思路对小型项目也完全适用。哪怕只是把一个Python脚本迁移到TypeScript,也可以让AI帮忙准备几组真实的输入输出样本,迁移完成后跑一遍,看看结果是否一致。
1、制定规则手册和依赖图
这一步是整个流程中人工投入最多的阶段。
Bun创始人Jarred光是跟Claude讨论如何将Zig的模式映射到Rust就花了3个小时,最终产出了一份576行的规则手册,里面详细规定了每种类型如何映射、每种惯用法如何转换。
规则手册的内容取决于一个关键策略:新代码是保持原有架构逐行翻译,还是完全重新设计?
Jarred选择的是保持架构不变的机械翻译,所以他的规则手册主要是一个对照表。他还让Claude运行了一个工作流,分析代码库里每个struct字段的生命周期,输出成一个LIFETIMES.tsv文件供后续翻译参考。
而Mike选择的是重新设计架构,所以他的规则手册更像是一份设计文档,描述新系统应该是什么样子。
除了规则手册,依赖图也很重要。你需要知道哪些文件依赖哪些文件,这样才能决定迁移的顺序、哪些文件可以放在同一批处理。对于像Python这类依赖关系不显式声明的语言,可以让Claude写一个脚本去分析和生成依赖图。Anthropic还开源了一个代码迁移工具包,里面就包含了现成的依赖分析脚本,拿来直接用即可。
此外,还要做一份「差异清单」,列出源语言和目标语言之间那些不能简单翻译的地方。例如,Zig到Rust的核心差异是手动内存管理变成了所有权系统,Python到TypeScript的核心差异是动态类型变成了需要显式声明接口。这些差异点是AI最容易犯错的地方,必须在规则手册里重点标注。
2、小范围试跑
规则手册写好之后,不要急着全量执行,先拿3个文件试试水。
Bun创始人Jarred的做法很巧妙。他让一个Claude实例按照规则手册翻译3个文件,同时让另一个Claude实例以「高级Rust工程师」的身份翻译同样的3个文件。然后再开一个全新的Claude对话,专门用来对比两个版本的差异,从差异中提取新的翻译规则。
这一步他发现了2个关键问题,如果直接铺开到全部1448个文件,后果不堪设想。
对于重新设计架构的项目,做法不太一样。Mike是让多个Claude实例从不同角度挑设计文档的毛病,看看有没有逻辑漏洞或考虑不周的地方。然后跑一次完整的端到端翻译,看看设计在实际执行中有没有问题,发现了问题就改规则、重跑。
有趣的是,他实际上跑了三次完整迁移,前两次都丢弃产出,只保留对规则的改进,直到第三次才正式保留结果。
看到这里,第一反应是:前两次直接丢弃,这不是浪费Token吗?但事实上,对于复杂的项目来说,这么做是合理的。试跑阶段的目标就是打磨规则,试跑出来的代码未必正确可用,如果直接应用这些代码,搞不好会影响整个项目迁移。
这点对普通开发者也很有启发。很多人用AI做项目时,总想一步到位。其实不妨先让AI做一个粗糙的版本,看看哪里不对,完善好提示词和规则之后再正式开始,磨刀不误砍柴工。
3、全量翻译
规则经过试跑验证之后,就可以全量执行了。
这一步的核心架构可以理解为一个流水线,分为3个角色:负责翻译的Agent、负责找茬的Agent、负责修复的Agent。
每个翻译好的文件由2个独立的「找茬Agent」来检查,它们的唯一任务就是挑毛病。发现问题后交给「修复Agent」来处理。
这里的找茬Agent就是前面提到的「对抗性审查」。为什么叫对抗性呢?因为审查者被明确要求「假设这段代码是有Bug的,你的任务是找出Bug在哪」。这种心态跟人做代码审查是一个道理,审查者不能先入为主觉得「他写的应该没问题吧」,而是要带着怀疑的态度去看,才能发现问题。
听起来很简单,但实操有几个细节需要注意。
1)工作队列要机械化。比如什么文件翻译了、什么文件没翻译,可以通过检查磁盘上有没有目标文件来判断。这样整个流程天然可恢复,中断了重启就行,不需要维护什么状态。
2)翻译Agent和审查Agent的对话必须隔离。写代码的AI总是倾向于认为自己的代码没问题,所以审查者必须在一个全新的独立对话里工作,只看翻译结果,不看翻译过程中的推理。
3)模型要分层使用,不需要所有步骤都用最强的。实现翻译这种高并发的工作可以用相对便宜的模型(比如Claude Sonnet),而审查和规则制定用最强的模型(比如Claude Fable、Claude Opus)。Mike在全量翻译阶段就是用12个Sonnet子代里并行工作的。
翻译时如果有拿不准的地方,直接标上// TODO(port): <原因>,不要在这一步纠结,后面编译器和测试会告诉你到底对不对。
4 ~ 6、编译 + 运行 + 对齐行为
接下来的3步套路都一样:先跑一遍得到错误列表,然后让一批修复Agent并行处理这些错误,修完了再跑一遍,循环往复直到没有错误为止。人工介入的程度越来越低。
1)编译阶段,把编译器报出的所有错误整理成一份待修复清单,然后让AI按照这份清单逐个修复。
Jarred的做法是让编排脚本对整个工作区跑一次编译器,把错误按模块分组输出到文件,然后64个「修复Agent」并行处理错误列表。每个修复Agent有2个对抗性审查者盯着。修复完再编译,反复循环。
这一步他遇到了一个大问题。原来的Zig代码是一整坨放在一起编译的,他想把Rust代码拆成100个独立模块来加快编译速度,但这引入了大量循环依赖问题。于是,他跑了一个专门的工作流来分类哪些代码该挪到哪里,修复循环依赖之后暴露出约16000个编译错误。16000个错误对人来说是天文数字,但对64个并行的Claude来说,也就是几个小时的事。
2)冒烟测试阶段,把所有崩溃信息整理成待修复清单。编译通过之后,先让各个子命令跑起来,把每个崩溃的报错信息和对应的子命令保存到文件,用同样的「修复 + 审查」循环处理。
3)行为对齐阶段,把所有失败的测试整理成待修复清单。把测试套件分片跑,每个失败的测试交给一个修复Agent,修复之后由对抗性审查者检查。
Jarred还有一个巧妙的设计,只允许一个专门的构建守护进程来编译整个项目。修复Agent只提交代码,守护进程定期把所有补丁批量编译、跑受影响的测试、把结果反馈回去。这样避免了多个Agent各自触发编译导致的资源冲突和重复工作。
整个过程中,Bun的CI从972个测试文件失败到全部通过,花了大约4天。Linux最先变绿,Windows是最后一个。合并之后一共出现了19个回归Bug,全部已修复。
其实Airbnb之前也做过类似的事情。他们用AI把3500个React组件测试从Enzyme迁移到React Testing Library,原本估计要一年半,最终6周就完成了,用的也是类似的方法。
几点感受
看完Anthropic这套六步迁移法,有几个比较有感触的点。
首先是对抗性审查这件事,大家日常用AI编程时完全可以做。比如让一个Agent写完代码之后,开一个新的对话让另一个Agent做code review。在Claude Code里面可以直接用内置的/code-review命令,或者用Subagent来做审查。哪怕不做代码迁移,这个习惯也值得养成。
然后是AI的成本问题。Bun的迁移花了16.5万美元的API费用!
这个数字乍一听很吓人,但对比3个高级工程师干一年的薪资加机会成本,便宜太多了。对于个人开发者来说,一个几万行的项目迁移用Pro或者Max的订阅额度基本就够了。至于这个钱花得值不值,自己用人力成本算一笔账就好。
不过不要盲目跟风迁移。如果现有代码跑得好好的、也不难维护,就没必要折腾了。迁移的前提是你确实有一个持续的痛点需要解决。
还有很关键的一点,人的判断力仍然不可替代。Jarred在整个迁移过程中,每天都在监控工作流的输出、手动检查AI的行为、发现系统性问题后调整流程。虽然AI执行力很强,但决策权还是在人这边。AI能节省成本,但不代表完全不需要人。
总结
最后帮大家总结一下文中提到的方法,可以立刻用起来:
1)做任何稍大的重构或迁移之前,先跟AI聊出一份规则文档,把「什么该怎么改」定义清楚,别上来就动手。
2)先拿3个文件试跑一轮,看看AI会犯什么错。发现的问题不要逐个修代码,而是补到规则文档里,然后重新生成。
3)写代码的AI和审查代码的AI一定要分开。可以用Claude Code的/code-review命令,或者开一个新对话做独立审查。
4)善用「错误即清单」的思路。编译报错、测试失败、Lint警告,这些都是天然的任务列表,让AI按清单逐个修复就好。
想想看,连几十万行、上百万行代码都能用AI完成迁移了,平时几千行、几万行的项目重构,还有什么不敢动的呢?关键不在于AI有多聪明,现在模型的能力已经足够了,更多的要看你给AI设计的流程够不够好。

