花 12 万美元让 AI 重写 43 万行代码:微软那篇长文里最值钱的不是倍数
TL;DR 速览
- 规模:43 万行 TypeScript → 80 万行 Rust,跨135 个 release、14.5 周,平均每天1.3 个迁移 PR
- 成本:token 约12 万美元+ 人工3 周;官方对纯手工工作量的估计是「几年、几百万美元」
- 收益:单轮会话生命周期吞吐7.55/秒 → 120/秒;同时挂 10 个客户端 agents 时内存1383MB → 126MB
- 最难的一个文件:
session.ts3 万多行,迁移花25 小时,其中读文档 56 分钟、122 次工具调用澄清需求,随后 spawn15 个子会话各带独立 worktree- 最有价值的一句:官方原话——如果编译通过就等于正确,那这话只能当个笑话用
微软杰出工程师 Stephen Toub 发布的长文记录了 Copilot 运行时从 TypeScript 重写到 Rust 的全过程:43 万行 TS 变成 80 万行 Rust,跨135 个 release、14.5 周完成,平均每天1.3 个迁移 PR。token 成本约12 万美元,另外投入 3 周人工;官方对纯手工完成同样工作的估计是「几年、几百万美元」。这段时间里跨模型分工也在用:主力是 GPT-5.6 Sol 与 Claude Opus 4.8。
这件事被大量转述成"AI 编码能力的又一枚里程碑",但长文里真正能复用的东西不是那些倍数,而是验收环节被推翻的一个默认假设:把"编译通过"当成"迁移正确"。这篇文章拆它的成本结构、收益口径,以及那套验收方法。
一、先拆成本:12 万美元到底买了什么
12 万美元这个数字最容易被误读成"AI 干完活的价钱"。实际结构是两块:
| 成本项 | 量级 | 说明 |
|---|---|---|
| token | 约12 万美元 | 覆盖跨 135 个 release 的全部模型调用,按当前主流编码模型定价折算 |
| 人工 | 3 周 | 不是"监工"性质——是设计迁移顺序、审每一批 diff、定位回归 |
| 纯手工对照 | 「几年、几百万美元」 | 官方给出的估计值,与上两项做对比 |
折算下来真正值得盯的是这三个比率:
- 每行成本:12 万美元 / 43 万行 ≈0.28 美元/行。这个数只有当"每行代码的语义复杂度可控"时才成立。
- 每 release 成本:12 万 / 135 ≈890 美元/release。也就是说这批钱不是一次性押注,是分 135 次小步支付的。
- 人工与模型的比例:模型跑 14.5 周,人工只跟 3 周。人工被压缩到了"设计 + 验收"两个环节,中间的执行几乎全自动化。
这里有一条容易被忽略的前提:本次迁移只做逐模块替换,没有重构结构。TS 里是什么形状,Rust 里就是什么形状。这个约束把任务从"重新设计"降级成"等价翻译",才有了 0.28 美元/行这个量级。一旦允许顺手重构,成本立刻不可控——因为"等价"这个判据消失了。
二、session.ts那 25 小时:AI 是怎么被喂饱需求的
长文里最硬的一段,是单个文件session.ts(3 万多行)的迁移过程。它值得逐步看清,因为流程暴露了一个反直觉的事实:最贵的不是写代码,是澄清需求。
| 阶段 | 耗时 / 动作 | 关键点 |
|---|---|---|
| 读文档 | 56 分钟 | 迁移前先把模块间约定读进去,不是直接改代码 |
| 提问澄清 | 122 次工具调用 | 用工具调用去验证假设,不是问人 |
| 实际改写 | 剩下一大半时间 | 分组作业,每组独立 |
| 并行拆分 | spawn15 个子会话 | 每个子会话带自己的worktree,彼此可通信 |
122 次工具调用这个数字最值得琢磨。它说明模型不是"读一遍代码就动手",而是把"这个函数在别处怎么被调用"“这个类型有没有等价物”"这个边界条件在测试里怎么覆盖"逐条查证。工具调用次数在这里等价于需求澄清轮次——它花的是 token,省的是返工。
15 个子会话各带 worktree 的设计也值得抄。3 万行的文件不可能一个会话从头改到尾,但简单拆成 15 个会话会互相踩。给每个子会话一份独立的 git worktree,等于给每个执行体一个私有工作区,冲突推迟到合并时才暴露——把"写时的冲突"换成"合并时的冲突",后者可回滚、可仲裁,前者只能靠人盯。
这条经验可以直接搬到自己的项目上:要迁移一个大文件,先问"这个文件能不能按职责切成 5–15 段、每段有没有独立的调用方",如果答案是"切不开",那它就不适合交给并行迁移。
三、收益侧:两个数字,但含金量不同
| 指标 | 迁移前 | 迁移后 | 口径 |
|---|---|---|---|
| 单轮会话生命周期吞吐 | 7.55 /秒 | 120 /秒 | 约15.9× |
| 10 个客户端 agents 的内存占用 | 1383 MB | 126 MB | 约91% 降幅 |
这两个数字的性质完全不一样,别混着用:
吞吐那 15.9 倍,主要来自语言与运行时特性的重写——Rust 没有 JS 的 GC 停顿和事件循环争抢,单机并发上去了。
内存那 91%,真正的原因是架构改了:全程进程内,不再拉后台子进程。也就是说这部分收益不是"Rust 比 TS 省内存",而是"顺手把进程模型改了"。把这两件事归到"换语言"名下,下次照做会失望。
这也是评估任何"AI 重写"项目的通用判据:收益里有多少来自语言,有多少来自顺手改掉的架构?前者可预期,后者是意外收获,不能写进预算。
我评估迁移收益时有个固定习惯:把"语言带来的"和"顺手改架构带来的"分成两栏记,因为后者不可复现——换个技术负责人,架构未必会一起改。我的分栏模板和判断清单攒在 墨衍 里,跟选题素材放一起,下次做迁移预算直接调出来对。
四、验收账:编译通过为什么不能等于正确
这是全文最该被记住的部分。迁移过程中出现了数十个回归,官方给出的总结是那句广为流传的话——如果编译通过就等于正确,那这话只能当个笑话用。
编译器检查不了的东西,恰好是这类迁移最容易出错的地方:
- 函数调用顺序:类型全对、编译全过,但两个函数的调用先后错了,行为就变了。
- 并发假设:TS 里靠事件循环隐式串行的部分,搬到 Rust 里如果换成真线程,编译不报错,但共享状态不再安全。
- 错误传播路径:异常改
Result之后,"出错时谁来兜"这条链路肉眼看不出来。 - 单次任务成本可不可接受:这个最容易被跳过——功能对、性能对,但每次调用的成本模型变了。
所以一套能用的迁移验收,至少要有三层:
- 编译——只当入场券,不当结论。
- 行为对照——同一批输入跑新旧两版,逐项比对输出。这也是为什么"先有测试再迁移"是硬前提。
- 顺序与并发假设清单——把"谁必须先于谁""哪些状态原本靠单线程隐式保护"逐条写下来人工过一遍,编译器不会替你做。
对照案例把这条讲得更清楚。同期 Bun 把53.5 万行 Zig 移植到 Rust,token 花销16.5 万美元,通过现有测试的比例是99.8%——看起来比 43 万行那批更漂亮。但 Zig 作者仍然称其结果是「没人审过的垃圾」。99.8% 通过意味着 0.2% 没通过,而那 0.2% 里藏的是什么,只有人去看了才知道。
这两个案例合起来给出的结论是一致的:AI 能把"翻译"这一步的边际成本压到接近零,但不能把"确认翻译正确"这一步也压下去。
五、什么规模的重构适合交给 AI
把上面的账综合成一张可操作的判据表:
| 判据 | 适合交给 AI | 不适合 |
|---|---|---|
| 目标形状 | 等价翻译,一进一出 | 顺手重构,边迁边重新设计 |
| 语义可判据 | 有能跑的测试集,或输出可逐项比对 | 只有"看起来对" |
| 模块边界 | 能按职责切成 5–15 个独立段 | 高度耦合、切不开 |
| 失败代价 | 可回滚、可回退到旧实现 | 不可逆,或涉及数据迁移 |
| 验收预算 | 留出人工审 diff 的时间(本例是 3 周) | 打算"编译过了就发" |
最该注意的取舍是"逐模块替换 vs 顺手重构"。前者牺牲的是代码质量(Rust 里写的还是 TS 的结构),换来的是可控性;后者看着更划算,但会让"等价"这个验证判据失效,回归无处可查。本次选择的路线是先等价、后优化,把结构优化留到下一步单独做——这是一个非常克制、也非常工程化的取舍。
六、这件事真正的边界
三个容易被忽略的限制:
第一,12 万美元是一次性的,但维护不是。80 万行 Rust 之后要有人读、有人改。代码产出速度提升之后,承接它的团队容量会成为新的瓶颈——这也是为什么原文强调了那 3 周人工投入。
第二,"AI 写的代码"在组织里有隐性成本。审 diff 的人需要能看懂 Rust 而不是只懂 TS,否则"人工审"是假的。
第三,这套方法高度依赖"任务可翻译"这个前提。TS→Rust 有类型系统互相对应,是最理想的一类迁移;换成"老 Java 单体拆微服务"这种语义与架构同时变化的任务,同一套流程的成本会成倍上浮。
所以把这件事读成"AI 能替代工程师",和读成"AI 只是又一个编译期工具",都是误读。它准确的定位是:把大工程的执行边际成本压到接近零,同时把风险全部前移到了"定义什么叫正确"和"验收"这两个环节。这两个环节上的能力,才是团队真正需要提前备好的东西。而准备的第一步,是先承认编译器不会替你判断函数顺序对不对。