开源GitHub官方博客·原文 2026年9月17日

GitHub用Copilot把Copilot运行时整体重写为 80 万行Rust

GitHub官方博客披露:Copilot agent runtime已 100% 迁移到Rust,832,378 行生产代码经 128 个PR增量落地;主要工作由一名开发者借助AI代理在约 14 周内完成。

AI解读:GitHub把支撑Copilot CLI、Copilot应用和各类SDK的agent runtime从TypeScript/Node.js完全重写为Rust,最终生产代码 832,378 行、Rust单元测试 468,689 行。作者Stephen Toub说,这个规模在代理出现前“负担不起”,如今主要由一名开发者用几个月做完。

原来的架构给非TUI场景带来真实成本:SDK调用要另起一个Node/V8子进程,每种语言(C#、Python、Go、Java、Rust)的客户端都背上约 100 MB起步的工作集,进程边界还让每次事件、消息和文件读写都要跨进程。重写要解决的就是把runtime做成可进程内嵌入的库。

对用Copilot SDK的开发者来说,变化是调用栈更短、资源占用和崩溃面更小;对GitHub和微软自家产品(VS Code、Visual Studio、CCA、Copilot Code Review、Copilot Studio及Office系列等)来说,是共享同一个runtime后,一处修复能同时生效。不过文章说明CLI目前仍在若干位置直接调用runtime内部接口,完全改走SDK公共面还在进行中。

GitHub官方博客披露,支撑GitHub Copilot CLI、GitHub Copilot应用和GitHub Copilot SDK的Copilot agent runtime,已从TypeScript/Node.js完全重写为Rust。作者Stephen Toub称,重写后的runtime为 100% 生产Rust,共 832,378 行生产代码、468,689 行Rust单元测试,另有 174,675 行端到端TypeScript测试。

这次迁移由AI代理写下了大部分代码,跨越 128 个合入主干的pull request,并采用增量发布而非最后一次性切换。GitHub称runtime性能“提升了数个数量级”,项目主要由一名开发者用几个月完成,而此前这类工作预计需要一整支团队花一到两年。

迁移范围与数字:128 个PR、14 周、832,378 行Rust

文章称迁移在早期 2026 年 5 月启动,初始估算runtime约 130,000 行TypeScript,但这个数字随后被证明“既相当准确,也具有严重误导性”。原因包括:原本裹在TUI层里的代码被不断下推到runtime;最初估算忽略的组件和代码后来被纳入迁移范围;同期还有大量新增TypeScript进入仓库。综合计算,大约 430,000 行生产TypeScript经历了这次迁移。

迁移期间,runtime接收了约 300,000 行生产TypeScript、移除了约 430,000 行;同时有约 1,200,000 行生产Rust进入、约 365,000 行离开。到 8 月 21 日,runtime已是 100% 生产Rust。

整个迁移窗口约 14 周半,主干共发布 135 个版本,包括 100 个预发布版本和 35 个稳定版本,平均每天约 1.3 个版本;迁移PR平均每天约开 1.3 个,使每个版本只包含少量且已知的已迁移组件。GitHub称在截至该时段的一个 7 天npm样本中,预发布版本仅占下载量的 10.5%,说明早期暴露范围相对有限。

为什么要换语言:SDK调用要另起Node/V8子进程,每种语言客户端至少约 100 MB工作集

文章解释,Copilot agent runtime不只是CLI引擎,还支撑微软、GitHub和生态中越来越多的产品,包括VS Code、Visual Studio、CCA、Copilot Code Review、Copilot Cowork、Copilot Studio以及Excel、Outlook、PowerPoint、Word等。每个产品在架构上都是同一runtime外壳加各自定制,而不应各自实现一整套生产级agent harness。

原文描述旧结构:CLI逻辑上是终端UI叠加agent loop,整个技术栈用TypeScript,Node.js作框架、V8作执行引擎,Ink和React做UI。这对TUI应用是合理选择,但放到其他环境、面对快速启动和低内存开销的服务器密度要求时就不合理了。

更具体的问题在SDK层。原文称由于TUI和runtime没有清晰分层,SDK被叠加在CLI之上;外部程序要新建CopilotClient时,会以子进程方式启动CLI来托管agent loop,通过JSON-RPC跨进程调用函数。这意味着每个SDK消费者、每种语言(C#、Python、Go、Java、Rust)都带着Node.js或内嵌V8的二进制,每个客户端至少约 100 MB工作集;每个事件、消息和抽象出来的会话文件系统读写都要穿过进程边界,Node崩溃会带走会话,部署方至少要监督、监控和调试两个进程。

为什么选Rust,以及为什么不用大爆炸式切换

文章列出对目标runtime的要求:不包含TUI,是可被TUI和其他应用正确分层的库;依赖少、开销小;可干净地进程内嵌入,而非被迫进程外;性能、可扩展性和可靠性出色;语言互操作性好,能被六种Copilot SDK语言版本(C#、TypeScript、Python、Rust、Go、Java)通过FFI使用;工具链安全姿态更现代、供应链风险更低、对构造即正确代码支持更好。出于这些原因加团队经验和行业方向,GitHub选择了Rust。

文章强调这并非主张所有大型TypeScript程序都应改成Rust,目标语言因应用而异;Rust让上述目标成为可能,代价是必须显式表达生命周期和共享状态,后文提到的生命周期回归就体现了这一点。

迁移采用“就地”策略,增量逐组件重写,每个PR原子地把现有TypeScript实现替换成调用Rust的薄垫片并删除旧代码,而不是大爆炸式整体切换或并行长期维护两套实现。GitHub称这样没人停工、主干始终可发布、每个变更范围小可审查、全部端到端测试在每一步都跑新Rust代码,测试失败就不合入。文章也解释了不并行维护两版本的原因:每周数百个PR、代码库快速演化,同时维护两种语言两套依赖会带来巨大复杂性;而最需要谨慎并行切换的子系统(如会话编排)恰恰最难并行,它拥有可变状态、双向驱动回调、贯穿几乎所有其他子系统。

先试点再铺开,会话编排放在最后

文章称在全面铺开前,先用两个PR建立Rust工作区、工具链、lint规则、CI、构建流水线和编码说明,引入runtime crate、代码生成和互操作模式,并迁移一组特意挑选的无I/O、无共享状态、已有强测试的纯逻辑原语。只有这些落地后,第一个主要迁移PR才把三个无副作用的helper走完整流程。

迁移顺序由叶子向内:纯helper、内容排除、shell工具、会话文件系统操作先建立翻译和测试模式,然后是有状态子系统,接着是工具、hooks、模型客户端和MCP,最后才是耦合最紧、最不易并行的会话编排。文章举例MCP支持经过 7 个专门PR,工具经过 6 部分系列后还需额外工作来迁移编排并退役剩余TypeScript;hooks、auth、telemetry、plugins、settings和持久化也走了类似路径。

文章称实际有用的迁移单元并不总是“一个组件”,而往往是一波相关行为:先搬纯逻辑,再搬状态所有权,再搬编排,再移除回退,最后在临时互操作消失后简化Rust。

信息来源

GitHub官方博客原始来源