832,378 行 Rust,14.5 周,128 个 PR。这三组数字属于同一个人:GitHub 工程师 Stephen Toub,任务是把 Copilot agent runtime 从 TypeScript/Node.js 整体搬到 Rust。代码不是他一行行敲出来的,绝大部分由 Copilot 智能体产出。行数是最不重要的部分,真正值得抄的是他给智能体划出来的那条轨道。
先把账本摊开
14.5 周,但人没有钉在键盘上
这个数字容易让人误读。它指的是从动工到收尾的日历跨度,不是一个人连轴转的工时。实际节奏更松散,也更并行:写规格、读 diff、判断设计方向,这些活儿穿插在等待智能体跑任务的时间里。真正被压缩掉的是"敲"这个动作,而不是"想"这个动作。
128 个 PR 才是这次迁移的骨架
一次性生成几十万行再合并,和分 128 次增量合入 main,是完全不同的两种工程行为。后者意味着主干始终可发布,每一步都小到能被人读懂、被 CI 拦住、被回滚。大迁移最怕的就是长命分支上的"大爆炸合并",这次的做法恰好把它拆成了 128 次不会致命的小爆炸。
行数会骗人
83 万行里混着测试、适配层、脚手架和为了保持兼容而写的胶水代码。拿它去类比人类工程师的产出效率,没有意义。有用的信号是:它跑通了原有的行为验证。代码量只能说明智能体的吞吐,跑不跑得对得看别的证据。
让智能体不跑偏的两样东西
规格写在前面
给智能体一份含糊的需求,它会给你一份含糊的代码,而且速度极快地把含糊放大一百倍。Toub 的做法是把接口、数据结构、错误处理策略、边界条件尽量写清楚,让实现空间被约束到足够窄。文档在这里不是交付物,是控制手段。
测试套件成了唯一裁判
原 TypeScript 实现的行为被固化成回归样本,智能体的每一次产出都要在这套样本上过一遍。这等于给模型装了一个不会疲劳、不会讲情的验收方。谁对谁错不再靠人吵,跑一遍就知道。迁移类工作特别适合这么干,因为"旧实现的正确行为"本身就是最完整的规格书。
Rust 编译器送了一份大礼
借用检查器、类型系统、穷尽匹配,这些会在代码落地前就把一大批错误挡回去。智能体得到的是一次即时的、机械的、不掺杂主观判断的反馈——这恰好是它最擅长处理的东西。动态类型语言就没这么幸运,"能跑但不对"的代码会安静地流进主干。
这不是翻译,是重新实现
TypeScript 里那些没写下来的约定
动态类型、隐式异步、运行时校验、结构化的松耦合——这些在 Node.js 世界里靠惯例维持的东西,到了 Rust 里必须一条条显式化。智能体面对的不是语法替换题,而是语义重建题。谁要是把这类迁移当成"换个语言的写法",多半会在中途发现整个模块的抽象都得重画。
并发模型得推倒重来
单线程事件循环里那些"反正不会同时发生"的假设,在 Rust 的多线程与 async 世界里全部作废。Send、Sync、生命周期标注会逼着团队回答一个原本被绕过去的问题:这段状态究竟归谁管。这一步没法自动化,只能靠人先把设计定下来。
一边迁移,一边发布
128 个 PR 增量合入的意义就在这里:系统始终在线,用户感受不到底层换了一台发动机。要做到这点,接口兼容层、灰度开关、新旧实现双跑比对,一样都不能少。迁移的难点从来不在写新代码,而在让新旧两套东西在同一时间和平共处。
人的位置往后挪了一格
瓶颈从打字变成了审阅
代码产出速度被拉高一个数量级之后,卡住流程的不再是写,而是读。每天面对成百上千行待审的 diff,判断哪些是设计问题、哪些只是风格差异,这才是新的稀缺资源。智能体把工程团队的瓶颈从产能端推到了决策端,这个变化比任何效率数字都重要。
成本账:token 便宜,返工不便宜
推理开销和同等规模的人力投入相比,几乎可以忽略。但一个错误的设计决定被智能体忠实执行五万行之后,纠正它要付出的代价一点都不便宜——因为你要先读懂那五万行。真正的成本不在生成,在理解和回退。
哪些项目别这么干
测试覆盖稀薄、模块边界模糊、需求还在剧烈变动的项目,把智能体的吞吐加进来只会让混乱来得更快。它能放大清晰的决策,也能同等地放大模糊的决策。判断标准很朴素:如果连人都说不清"做对了是什么样",那就先别交出去。
最后说两件能带走的事
把迁移拆成一百次小迁移
每次改动小到可以被完整评审、被 CI 拦住、被安全回滚。这既是给智能体定的规矩,也是给人留的退路。
投资规格,而不是提示词技巧
花在设计文档和回归样本上的时间,会在后续几十个 PR 里连本带利地还回来。提示词是一次性的,规格是可以被反复执行的资产。
这套方法未必适用于所有团队,但它指出了一个方向:当代码的边际成本趋近于零,工程能力会重新定义在"能不能把问题描述清楚"和"能不能判断产出对错"这两件事上。剩下的,交给机器。

