开局:一个原本以为要好几年才能干完的活

GitHub 在 9 月 16 日贴出了一篇署名 Stephen Toub(Microsoft Distinguished Engineer)的超长博客,讲了一个只有"1 名工程师 + 一群 AI 智能体"的项目:把 GitHub Copilot 的整个 agent runtime,从 TypeScript + Node.js + V8,完整重写成 100% Rust。

这个 runtime 不是个不起眼的小工具。它是 GitHub Copilot CLI、Copilot app、Copilot SDK 共同的底座,同时还支撑 VS Code、Visual Studio、Copilot Cloud Agent、Copilot Code Review、Copilot Cowork、Copilot Studio,以及 Excel、Outlook、PowerPoint、Word 里的 Copilot 功能。简单说,微软和 GitHub 现在所有带"AI 智能体"色彩的产品,都接在这一个 runtime 上。

按工程团队的最初估算,这事大概需要一个完整的开发团队干上一两年。最终结果:主要靠 1 个工程师、几百次 pull request、128 个端口 PR,在 14.5 周内完成。

为什么非要换 Rust

TypeScript + Node.js 对终端应用本身没什么问题,启动快、开发快、性能对 CLI 来说够用。但 runtime 嵌入到其他产品里后,问题就出现了:每个 Copilot SDK 消费者(C#、TypeScript、Python、Rust、Go、Java 六个语言版本)都要背一个 V8,光工作集就多 100 MB;每次函数调用都要跨进程边界;Node 崩了,整个 session 跟着崩。

换成 Rust 的核心动机就三个:可以走 C ABI 在进程内嵌入、稳态资源占用可控、能给六个语言的 SDK 提供一致的 FFI 体验。

工程团队因此给每个 SDK 消费者省去了"自带一个 V8"的代价,也把跨进程通信压到了零。

跑起来到底有多快

官方给了一组对比:在 100 个并发 pipeline 上跑 1000 个 one-turn session lifecycle,TypeScript 版本每秒只能跑完 7.55 个,Rust 版本能跑 120 个,提速 15.9 倍。内存方面,10 个 client 的 agent 批次,占用从 1,383 MB 降到 126 MB,将近 11 倍。

关键架构差异:TypeScript 版本必须 spawn 外部后台进程完成任务,Rust 版本直接在进程内搞定。

怎么干的:128 个 PR、in-place 替换

策略不是"大爆炸重写",而是 in-place 端口。每个 PR 把一个 TypeScript 模块原子地替换成对应的 Rust 实现 + 一个 thin shim,然后删掉旧代码。main 分支始终可发布。

14.5 周里,一共:

  • 合了 128 个 port pull requests 到 main
  • 发布了 135 个版本(100 个 pre-release + 35 个 stable)
  • 平均每天 1.3 个 PR、1.3 次 release

最棘手的部分是 session.ts —— 一个 ~30,000 行的 TypeScript 文件,横跨整个 runtime,坐落在状态、事件、工具、模型、钩子、持久化、入口点的中心。负责这个文件的端口 session,前 56 分钟全在读代码、122 次工具调用后才开始动手;整个端口跑了 25 小时,中间又派生出 15 个 child session 和 5 个 subagent。

谁在干活:多模型混编

Stephen Toub 把主线程的模型选择权和每个 subagent 的模型选择权分开了。主线程他用 GPT-5.6 Sol + Claude Opus 4.8,按 slice 切模型;子智能体里出现频率最高的是 Claude Opus 4.8、GPT-5.6 Sol、Claude Haiku 4.5、GPT-5.5,后面跟着 Gemini 3.1 Pro 和 Claude Opus 5。一些 agent 定义还把模型固定下来:explore 和 task 默认 Claude Haiku,research 默认 Claude Sonnet。

按工具调用量统计,整个端口过程里:powershell 跑了 63 万多次,view 跑了 59 万次,rg 跑了 28 万次,grep 跑了 12.6 万次,而 edit 只有 4 万次。探索调用是修改调用的 10 倍 —— Stephen 直说,这张表里最反直觉的事是:AI 写代码的活,绝大多数时间花在"读"而不是"写"上。

Rust 编译器不是银弹

有个常见说法:"AI 生成代码最适合往 Rust 里塞,因为 Rust 编译器严。"Stephen 用数据回应了这个 meme:8,678 次 rustc 错误里,84% 是名字/导入解析、缺方法/字段、类型不匹配、trait bound 不满足 —— 全是静态类型系统的"机械错",Go/Java/C# 编译器一样抓得住,还抓得更快。ownership/borrow/lifetime 这类"真正 Rust 特有"的错误加一块,只占 1.7%。Rust 编译器确实在干活,但它不是 AI 的"最后审判者",真正的裁判还是人 + 测试。

意外的故事:两个 session 互相抢代码

最有意思的小事故是 entrypoints session 和 session.ts session 抢对方的改动。Stephen 启动 entrypoints session 时,以为它会乖乖停在 session.ts 边界外。结果它 4 分钟就读懂了代码重叠,主动调用了内置的 orchestrate skill 找其他 session 协调;session.ts session 拒绝合并 4 次后,entrypoints session 直接绕过它,把对方的 760 文件 diff 拉到自己的分支上。

Stephen 总结根因不在 agent,在他自己 —— 他既自顶向下又自底向上切了同一块工作,两边在中间那个连接点撞上了。

所以呢:这个案例给我们什么

两件事值得记下。第一,大型代码迁移的成本结构正在被改写:这个项目 14.5 周完成,以前是要"几年 + 几百万美元"的量级 —— 前提是有一个会用 agent 的工程师做架构和风险判断。第二,"编译器兜底"的神话要破:Rust 编译器抓的是机械错,语义正确性还是要靠人 review。Stephen 的角色没被替代,他选了目标架构、定了语义边界、判定了模糊地带、手动 review 了高风险区 —— agent 只是把他能 supervise 的代码量提升了一个数量级。

GitHub 的这个项目不是"AI 自己写了 Copilot",而是"Copilot 让一个工程师写了一整个新的 Copilot"。后者是更值得被记住的那句话。