大规模代码如何用 Claude Code 进行迁移

📅 2026/7/30 14:43:09
大规模代码如何用 Claude Code 进行迁移
前些年生产级代码库的跨语言迁移不仅要花上数年时间编写代码还要长期维护两套并行的语言实现。然而最近一个月借助 Claude Code 和多个 Claude 模型Anthropic 多名研发人员完成了 10 个代码包的语言迁移规模从数万行覆盖到百万行级别。其中比较知名的迁移案例是 Bun 联合创始人、Anthropic 技术团队成员 Jarred Sumner 用了 11 天把 Bun 的约 100 万行代码从 Zig 迁移到 RustBun 既有测试套件的 CI 检查最终合并进主分支。这次重写共引入 19 个已知回归问题目前均已修复。同时 Rust 版 Bun 作为底层运行时用于 6 月 17 日发布的 Claude Code v2.1.181 及后续版本。无独有偶Anthropic Labs 联合负责人 Mike Krieger 利用一个周末把一套 Python 代码库迁移成约 16.5 万行 TypeScript。整个迁移过程中他用了数百个 Agent 分阶段推进迁移前后设置了八次验收关键结果再经过三轮对抗式审查。最后团队逐条运行原有命令对比 Python 与 TypeScript 版本的输出确认迁移后的行为保持一致。基于这些迁移实践Anthropic 总结出了一套由规则、任务队列和机械化验证组成的六步迁移流程。语言迁移的时机与成本一般来说团队决定迁移语言大概率是项目环境发生了变化。早期可以接受的技术取舍逐渐成为瓶颈出现了更合适的实现路径或是原有语言和生态正在收缩。以 Bun 的迁移为例Jarred 最初选择 Zig是因为它兼顾接近 C 的性能和较低的语言复杂度适合在没有大模型协助的情况下一个人快速完成 Bun 的初始版本。但随着 Bun 的规模、用户量和稳定性要求持续上升手动管理内存带来的维护负担也越来越明显。Bun CLI 每月下载量超过千万Claude Code 等工具也将 Bun 作为底层运行时。放在前些年即使重写需求十分的迫切研发团队也很难冻结产品路线图再投入数个季度完成跨语言迁移。现在团队可以先在隔离分支中反复运行整套迁移流程结果不理想时直接丢弃产物、修改规则再从头执行。虽然 AI 明显降低了迁移成本但是技术团队仍然要先回答一个问题这次迁移究竟能带来什么业务价值。毕竟跨语言迁移依然是一项昂贵的工程。百万行级别的项目如今未必要花四年时间投入 300 万至 400 万美元但实际执行成本仍可能达到数万至数十万美元。像是 Bun 的迁移就消耗了 59 亿个未缓存输入 Token 和 6.9 亿个输出 Token按 API 价格估算约为 16.5 万美元Mike 的迁移在主要阶段也消耗了约 2,700 万个 Token。图 1Jarred 提交的百万行迁移 PR虽然成本摆在那里但迁移的理由也不用达到“项目无法继续”的程度。持续一年修复内存问题的记录或是一个长期存在的构建瓶颈都可以支撑起迁移决策。Mike 的项目就是由编译环节推动的内部工具需要以单个二进制文件交付但 Python 工具链大约要花 8 分钟在单个平台的构建上完成所有平台的构建则要等待约 30 分钟。Mike 的项目迁移完成后同一编译过程缩短到约 2 秒二进制启动速度提高到原来的 6 倍团队还停止了一条独立的部署流水线的维护工作。AI 辅助迁移带来的变化主要体现在一次迁移失败要付出的代价上。之前迁移路线一旦出现问题可能要推倒重来大量人工编写的代码和协调投入。现在研发团队可以保留整理好的规则、脚本和验证流程只丢弃这一轮生成的代码修改规则后重新运行。因此团队的评估重点慢慢变成了能否建立一套可以重复执行、并通过自动化检查验证结果的迁移流程。AI 为什么适合大规模代码迁移Claude Fable 5 和 Claude Opus 4.8 这两个新模型擅长把大型目标拆解成多个并行工作流并通过 Subagent 完成委派、执行和验证。这和大规模代码的迁移工作有很多匹配点工作可以**并行**拆分。文件、模块、crate 或子系统都可以成为相对独立的迁移单元方便数十到数千个 Agent 任务同时推进任务。旧代码提供了完整上下文。原实现本身就是一份可执行规格模型可以直接读取类型、控制流、边界条件和现有行为。代码库通常自带裁判。编译器、测试套件、静态检查和输出 diff 都可以用于判断迁移结果是否正确。失败会自动形成任务队列。编译错误、测试失败和行为差异都能直接转化为下一轮 Agent 的输入。规则可以统一边界行为。审查 Agent 会指出每个问题违反了哪条迁移规则重复出现的错误可以回写到规则手册减少后续任务的继续偏离。AI 能够持续推进大型迁移除了需要能批量生成代码的模型之外还依赖一套清晰、可拆分、可验证的任务系统。每项任务都要有明确输入执行单元要彼此独立结果也得能通过编译或测试自动判断。迁移任务队列还可以根据磁盘上的文件状态、编译错误和测试结果重新生成让 Agent 持续领取尚未完成的任务。即使 Agent 的迁移任务运行中断也能从已有进度继续执行。6 步迁移流程在正式开始 6 个迁移步骤前研发团队要先建立一套足够可靠的验收体系也就是整个迁移过程的“裁判”。如果缺少这套体系迁移流程就无法判断何时结束也无法确认新版本是否真的达到了预设的验收标准。搭建这套验收系统一般包括 3 项工作。首先团队要梳理并分类现有测试区分哪些测试能够通过 CLI、API 或其他外部接口直接运行哪些测试依赖旧语言的内部实现迁移后会无法继续使用。其次团队需要把能够验证外部行为的测试改写为同一组断言使这些断言既能用于旧实现也能用于新实现。随后由专门负责挑错的 Agent 审查改写结果确认测试没有在改写过程中降低原有要求。最后团队要先用原有代码运行整套验收体系确认所有检查能够通过。再通过故意破坏部分代码检查这套体系能否准确发现错误。一套无法识别明显问题的测试系统绝对不能承担最终的验收工作。以上面 Bun 的迁移为例Jarred 在迁移的每个阶段都设置了审查和验收关卡。同样的Mike 的整体验收流程和 Jarred 类似但采用了更激进的策略团队先完整执行一轮端到端迁移再根据这一轮暴露的问题修改迁移规则和工作流。如果验收有问题就丢弃这一轮生成的全部代码从头重新执行。前两轮主要用于检验和修正迁移流程直到第三轮团队才保留生成结果并继续完成后续验收。图 2大规模代码迁移六步流程规则手册、依赖图和差距清单正式批量翻译代码前第 1 个阶段要先建立规则手册、依赖图和差距清单。这个 3 个前置准备共同决定了后续任务如何拆分、按什么顺序执行以及 Agent 遇到特殊情况时应该如何处理。规则手册、依赖图和差距清单的建立顺序也很重要团队要先确定通用迁移规则再梳理这些规则无法覆盖的例外情况最后再把规则手册和差距清单放在一起审查确认两者能够完整覆盖整个代码库。图 3规则手册、依赖图和差距清单规则手册的具体形式取决于团队是否准备在迁移过程中调整原有架构。如果新版本基本上保留了原来的代码结构规则手册就会像是一份语言映射表记录两种语言之间的类型转换、惯用写法和语义对应关系。一旦遇到无法直接转换的内容可以交给差距清单单独记录和处理。Jarred 对 Bun 的迁移就采用了这种方式。如果新版本调整了架构规则手册就要承担更多设计工作。除了语言之间的转换规则它还要明确新系统的模块边界、接口定义和目标结构让 Agent 知道每段旧代码在新架构中应该放在哪。Mike 的项目就采用了这条路线因此他的规则手册会更像一份完整的架构设计文档。Bun 的迁移是通过与 Claude 持续对话逐步补全迁移规则并为每个存在歧义的领域确定统一处理方式。Jarred 还为迁移设计了八个专门的 Subagent让它们分别检查八类常见的迁移错误。要判断某个问题是否应该写进规则手册时可以采用一个很直接的标准只要两个 Agent 面对同一个转换问题时可能给出不同答案团队就应该提前确定唯一方案并把它写进规则手册避免后续任务反复作出不同判断。依赖图负责确定文件的迁移顺序和**并行**批次。迁移系统需要提前知道哪些文件必须先处理哪些文件可以放在同一批并行执行以及哪些位置可能形成循环依赖。Claude Code 可以调度 Agent 编写确定性脚本直接扫描代码并生成依赖关系。能够通过脚本计算的结果应尽量交给脚本处理避免模型仅凭文件名称或代码语义猜测依赖关系。依赖分析不能只停留在文件层面。研发团队要检查目标语言中的包、模块或 crate 之间如何组织的。即使文件级依赖图看起来没有问题合并进更大的包级结构后仍然有可能会出现大量循环依赖和编译错误。因此文件粒度和模块粒度的依赖关系都要在正式迁移前确认。差距清单记录的是两种语言之间无法通过通用规则直接转换的信息。源语言可能允许某些知识隐藏在运行时行为、动态类型或内存管理方式中目标语言则要求开发者把这些信息明确写出来。Zig 迁移到 Rust 时差距主要集中在所有权、生命周期和内存释放方式Python 迁移到 TypeScript 时重点则落在接口定义、返回值类型和对象结构约束上。下面用一个示例来看下这类差距在实际代码中如何出现的fn loadConfig(allocator: std.mem.Allocator) ![]u8 { const data try allocator.alloc(u8, 1024); // 填充数据 return data; // 调用方需要记得释放 }fn load_config() - Vecu8 { let data vec![0u8; 1024]; // 填充数据 data // 所有权转移离开作用域后自动释放 }在 Zig 示例中调用方遗漏释放逻辑时仍可能成功编译问题通常要到运行时才暴露Rust 会通过所有权和类型系统提前限制重复释放、移动后继续使用等情况。差距清单需要把这类隐含知识转化成可搜索的条目供实现 Agent 在处理具体文件时查询。Jarred 选择在迁移前建立清单Mike 则先完成翻译再通过审计补齐清单实际项目中可能需要同时使用两种方式。规则的压力测试图 4规则压力测试Bun 的迁移在压力测试环节安排了 3 条独立路线第一个 Agent 严格依据规则手册翻译 3 个文件第二个 Agent 以“资深 Rust 工程师”的方式独立翻译同样的文件第三个 Agent 负责比较两组结果并根据 diff 补充迁移规则。这个小规模测试提前发现了两个关键问题由此判断如果直接把迁移任务扩展到全部 1,448 个文件同类错误就会被批量写入迁移后的 Rust 代码中。这种“双翻译再对比”的方法比较适合保留原有结构的迁移因为可以直接对同一个文件的两份实现比较当中的差异点。如果规则手册同时包含架构重构文件之间就难以逐行对应diff 的参考价值就会明显下降。此时更推荐让负责挑错的 Agent 直接审查设计文档再完整跑一轮可随时丢弃的端到端迁移检查这套设计能否真正执行下去。无论采用哪种方式这一阶段生成的代码都不应保留。它的任务是暴露规则和流程中的问题为后续正式迁移校准方向而不是提前积累迁移进度。迁移全部代码图 5多 Agent 批量迁移代码从这个阶段开始后续步骤基本上会沿用同一套多 Agent 循环先实现代码再进行独立审查最后根据审查结果修复问题。高吞吐的实现任务可以交给较小模型大模型则负责审查以及修改规则等会影响其他 Agent 的关键工作。像 Mike 在主要迁移阶段就用 Claude Sonnet 模型并行调度 12 个 Subagent 处理不同批次。迁移任务队列应尽量由脚本自动维护。脚本通过检查目标文件是否存在来判断哪些迁移单元已经完成再把剩余文件划分成新批次交给实现 Agent。由于队列每次都要根据磁盘状态重新生成迁移流程可以随时暂停和恢复。Agent 无法确定如何迁移的部分则统一标记为TODO(port): reason留待后续处理。每个迁移单元由两个上下文独立的审查 Agent 进行检查意见冲突的话就交给第三个 Agent 来裁决。如果同类错误反复出现团队就修改规则手册并重新生成受影响的批次避免围绕错误代码逐个打补丁。在循环中编译器的位置取决于执行成本。TypeScript 的编译只要数秒它就可以在每个单元内运行Rust 工作区编译要数分钟统一留到下一阶段进行。总之秉持一个原则“廉价检查高频运行昂贵检查集中处理”。编译、运行与行为一致性验证图 6编译、运行与行为匹配后面的 3 个阶段会采用相似的循环结构而且随着流程推进需要人类判断的环节会越来越少。第 4 个阶段是编译阶段由编排脚本统一编译整个工作区把编译错误整理成机器可读的任务队列再交给多个修复 Agent 并行处理。Agent 完成修复后编排脚本会重新构建整个工作区生成下一轮错误队列如此循环直到编译通过。要定期审查错误队列如果存在大量的重复错误说明迁移流程本身有问题。Jarred 在处理了 Zig 延迟编译机制能够容忍、但 Rust 无法接受的循环导入后遇到了数千个 Rust 模块错误。因此Bun 团队调整了迁移流程加入依赖分类逻辑来判断每条依赖应该删除、移动还是通过重新划分模块边界解决。第 5 个阶段的烟雾测试沿用同样的思路先按根因归类崩溃和失败再交给对抗式 Subagent 复核。第 6 个阶段用来比较新旧代码库的外部行为。到这一步迁移后的代码已经完成全部的翻译工作并通过了编译和基础运行检查接下来就是交由前期建立的测试体系继续验证。每个失败测试都会分配给一个修复 Agent由它同时检查新旧实现定位行为差异并提交补丁再由对抗式审查 Agent 复核修复结果。迁移工具包还设有构建守护进程只有它可以重新构建二进制文件。修复 Agent 只负责提交补丁守护进程负责汇总变更、统一构建、重新运行受影响的测试再把结果写回迁移任务队列。这样可以将最昂贵的构建操作串行执行避免多个 Agent 重复构建并相互干扰。由于很多项目缺少完整、可直接沿用的测试套件Mike 采用了另一种验证方式。他先让 Claude 编写一个小型脚本在新旧代码库中分别运行 7 个真实使用场景并对比两边的输出。每个未通过的场景都会交给独立的修复 Agent直到 7 个场景全部通过。随后Claude 又自行设计了一套端到端测试并连续 4 个夜晚运行测试、修复问题和重新验证进一步发现预设场景没有覆盖的问题。缺少现成测试不会让语言迁移无法推进但研发团队还是得补建一套能够验证外部行为的“裁判”。旧代码库可以继续当可执行规格用来对比新版本的输出、报错、退出码、文件变化和性能边界。团队要先确认这套裁判能够准确识别差异再根据它发现的问题持续生成修复任务。大规模迁移的实践原则每次迁移都会暴露新的问题但 Anthropic 在多个项目中逐渐总结出 5 个相对稳妥的做法先根据代码库制定迁移方案。上面的 6 步迁移流程可以作为起点但正式投入前仍要让 Claude 分析源语言与目标语言的差距、架构目标、测试条件和验证成本。评估结果也要允许团队得出“暂时不迁移”的结论。优先处理重复出现的问题。单个失败可以交给修复 Agent人类则应把时间集中在反复出现的错误、规则缺口和任务队列设计上。结合对抗式审查与机械化验证。审查 Agent 应在独立上下文中主动寻找问题最终结果要尽量交给编译器、测试套件、静态检查和输出 diff 判断。根据任务分配模型。较小模型适合承担大量实现工作更强模型则用于审查、规则设计以及处理会影响其他 Agent 的关键决策。把人类判断集中在前期。规则手册和压力测试需要投入最多人工判断后续阶段主要围绕编译、运行和测试生成的任务队列持续推进。这些做法也形成了一套更清晰的工程分工人类负责划定边界、设计验收体系、识别系统性偏差并调整流程Agent 则承担大规模、重复性的实现和修复任务。随着迁移推进人类的注意力会逐渐从单个文件转向整个流程迁移规则是否仍然有效验证结果是否可信以及流水线是否还在批量复制同类错误。用可测量结果评估迁移质量已经进入生产环境的 Bun Rust 迁移中有些取舍。例如约 4% 的 Rust 代码位于unsafe块中其中大部分用于处理与 C/C 边界交互时的单行指针操作。同时新代码库在内存占用、二进制体积和运行性能等多项指标上取得了可测量的改善。现有工具能够检测到的内存泄漏已经全部修复。在一项连续执行 2,000 次构建的基准测试中内存占用从 6,745 MB 降至 609 MBLinux 和 Windows 平台的二进制体积缩小了 19%经过跨语言优化HTTP 服务以及next build、tsc等真实工作负载的运行速度提升了约 2% 至 5%。这些结果表明迁移质量最终要通过行为一致性、稳定性、资源消耗和性能数据来衡量生成了多少行代码只能说明迁移规模。这套方法把大型迁移变成了一套可以反复运行、持续修正的工程流程规则手册统一实现依赖图安排顺序差距清单记录例外任务队列、独立审查和编译测试负责推进与校验。每一轮都会生成新的代码最终质量取决于规则是否完善、验证是否可靠以及反馈能否及时修正偏差。