NYSE 总裁 Lynn Martin 谈 AI(赞助内容)

AI 正快速发展,从实验走向能够自主行动的智能体。很少有人比 NYSE Group 总裁 Lynn Martin 更能看清这种转变对商业意味着什么。在 12 月 9 日的 Agentic Data Summit 上,Lynn 将与 Redpanda 创始人兼 CEO Alex Gallego 对话,讨论在可靠性至关重要的场景中采用 AI 需要什么、AI 正如何出现在即将上市的公司中,以及当智能体开始实时行动时,为什么及时、可信的数据比以往任何时候都更重要。太平洋时间上午 9:19 收听。本次峰会免费且为线上活动,时间为太平洋时间上午 8:30 至下午 2:00。
预留席位
GitHub 最近重写了多个 Copilot 产品背后的软件引擎。他们将代码库从 TypeScript 移植到 Rust。接近 80 万行代码。而最棒的是,这一切都是用 GitHub Copilot 应用本身完成的。
这次移植的起因是现有设计消耗了大量资源。将 Copilot 嵌入其他应用也变得越来越困难。
然而,这种规模的项目原本需要一支庞大的开发者团队和几年时间才能完成。但通过使用 GitHub Copilot 应用、Copilot CLI 和 AI 智能体,一名开发者就能在几个月内完成整个项目。本文将介绍这次移植是如何完成的,以及过程中的经验教训。我们将涵盖以下内容:
- 移植 Copilot 运行时的必要性
- 移植策略
- 移植工作如何开始
- 智能体集群的作用
- 新代码如何被审查
- 遇到了哪些问题
- 性能影响
- 移植成本与经验教训
免责声明:本文基于来自多个来源的公开分享细节。参考文献见文末。如果你发现任何不准确之处,请留言评论。
移植 Copilot 运行时的必要性
你可以把 GitHub 的 Copilot 运行时看作共享软件引擎,它负责多个产品中的 AI 智能体行为。由于这个运行时,所有这些产品都能复用相同能力,而不需要维护自己的实现。

最初,GitHub 工程团队使用运行在 Node 和 V8 JavaScript 引擎上的 TypeScript 构建了这个运行时。虽然这支持了快速开发,但运行时与命令行应用的用户界面紧密耦合。当 GitHub 需要一个 SDK 来让其他应用与 Copilot 通信时,它把这个 SDK 构建
Rust 是这类需求的理想选择。它开销低,资源使用可预测。早期估计显示,大约有 130K 行生产 TypeScript 代码需要移植。但额外的逻辑从接口层移到了运行时。此外,还有其他开发者在添加新功能。最终,430K 行生产 TypeScript 代码经历了这次迁移。

你每周有多少时间花在回答问题上?(赞助)

新员工、支持人员、产品经理以及你的编码代理都需要了解产品如何运作以及为何如此运作。如今,你是那个为他们指明正确方向的人。
Unblocked 会在你的代码、PR、工单、Slack 和生产数据中梳理出当前且相关的内容,因此:
- 每个人都能在 Slack 中获得带引用的答案,而无需拉工程师进来
- 当答案变成修复时,云代理会起草 PR
- 你的代理生成的代码会遵循过去的决策,无需人工引导
了解其工作原理
移植策略
GitHub 使用了增量式、就地移植策略。
在这种策略中,即使产品处于活跃开发中,你也可以一次替换运行时的一个部分。开发团队可以在整个迁移过程中继续添加新功能并发布更新。

GitHub 工程团队没有选择完全重写后再进行一次大规模切换。这种做法会把所有风险集中到一次发布中。替代实现将需要不断追赶接踵而至的变更。通过更小的替换,他们能够让每项变更更容易审查、测试和调查。
这个过程以逐步方式推进。一个组件的 TypeScript 实现会在单个拉取请求中被 Rust 替换,从而将变更分组以便审查。任何依赖该组件的 TypeScript 代码都通过一个薄封装调用新的 Rust 实现。你可以把这个封装看作两种语言之间的临时桥梁。旧实现会在同一变更中删除,因此团队只需维护该组件的一个活跃版本。随着越来越多内容迁移到 Rust,这些临时桥梁也被移除。

就任务而言,工作从小的、独立的辅助函数开始,这些辅助函数已经有强大的测试套件,并且不管理共享状态。这些早期变更还有助于测试构建设置、打包以及语言间通信。一旦他们让该方法变得具体可行,迁移就转向系统中更加相互连接的部分。
在整个过程中,关键目标是保持现有行为和算法。更广泛的重设计被推迟到迁移之后。每一步都进行了验证。他们有现有的端到端测试,用于检查完整工作流在实现变化时是否表现正常。如果出现测试失败,变更就不会被合并。此外,就用户而言,移植后的组件通过增量发布触达用户。它们通常先出现在预发布版本中,然后才进入稳定版本。
移植工作如何开始
GitHub 先从几个小型、可运行的示例开始试水,然后再处理更大的组件。
第一批 PR 处理了基础的 Rust 搭建工作,比如构建工具、自动化检查和编码指令。它们还引入了运行时库,以及让 TypeScript 与 Rust 相互通信的机制。
第一个主要的移植改动让三个独立的辅助函数走完了完整流程。你可以把这些早期工作理解为在检验翻译后的代码是否运行良好。团队还测试了 Rust 代码将如何组织、构建、打包,以及与现有代码集成。这为团队积累了贯穿整个流程的实践经验。
其余工作按依赖关系排序。例如,先处理小型辅助函数和支撑性工具,随后是管理状态的组件,再往后是工具、模型客户端和其他集成。
会话编排本应管理大部分运行时,却被留到了最后。这是因为较大的子系统往往需要经过多轮工作。
Agent 集群的作用
Agent 集群在把迁移工作分派给多个同时运行的 AI agent 方面发挥了关键作用。你可以让一个协调 agent 调研一个大组件,把工作拆成更小的任务,并创建其他 agent 来处理这些任务。Copilot 应用使得检查这些会话、在会话之间切换成为可能,也让它们能在工作推进过程中交换消息。
团队从这些 agent 那里获得了两种不同类型的协助。第一种是在父会话工作区内工作、并把发现结果返回给父会话的子 agent。这类子 agent 擅长调研代码和回答具体问题。第二种是拥有自己的 Git 分支和独立仓库工作副本的子会话,这让它们能够独立做出改动。这种隔离使多个 agent 能够毫无风险地处理实现的不同部分。

一个例子是约 30K 行的 session[dot].ts 文件,它与运行时的许多部分相连。协调 agent 花了一小时阅读和检查,之后才开始创建任何东西。分析完成后,它把工作分派给 15 个子会话,并为每个任务选定模型。父会话与这些会话沟通,从头到尾跟踪它们的进度。最后,它把完成的改动合并进自己的分支。
尽管有这些优势,同时运行这么多 agent 也带来了一些限制。当全部 15 个会话同时尝试构建和测试代码时,它们把开发者的笔记本电脑压垮了。工作流因此做了调整,让子 agent 避开昂贵的构建和测试,这些工作全部留给父会话。另有一个单独的聊天会话负责为每个移植会话提供构建访问权限,它一次只允许一个构建。
Agent 集群的许多活动都涉及阅读代码、检查依赖、测试和审查结果。它们的角色并不局限于编写 Rust 代码,还帮助理解现有系统,并检查替代实现是否保持了相同的行为。在这一切过程中,人工监督始终至关重要。
新代码是如何审查的
开发者不断在改动仓库,因此代码审查既要检查翻译本身,也要检查移植是否包含了最新的改动。团队使用一条名为 “rust-rebase-review” 的可复用指令来完成这一流程。

首先,主 agent 将其工作推送到最新的 main 分支并解决任何冲突。之后,它检查了任何新传入的 TypeScript 更改是否也已移植到 Rust。删除旧的 TypeScript 有助于引起对这些更改的注意。如果另一位开发者修改了已删除的文件,Hit 会标记一个必须处理的冲突。
接下来,你有多个使用不同 AI 模型的审查 agent 逐行比较旧的 TypeScript 和新的 Rust 代码。它们的主要工作是识别行为或兼容性的变化。它们还检查 Rust 实现是否足够高效。还有,过时的 TypeScript 和临时包装器是否已被移除。它们还必须确保现有的端到端测试保持不变,因为它们是预期行为的唯一参考。
代码审查在一个重复的循环中进行。当 agent 发现任何问题时,协调 agent 会检查发现的问题并修复任何有效的问题。这一过程持续到审查变得干净为止。每一轮修复都可以提交并推送,以便自动化检查可以与进一步的审查一起进行。Copilot Code Review 和其他审查机器人还检查了每个提交并在拉取请求上留下反馈。
人类审查者专注于架构、接口契约以及可能被 agent 或测试突出的风险因素。
出现了哪些问题
移植工作也导致了一些回归。你可以将这些回归视为之前有效但在重写后停止按预期工作的行为。团队发现并修复了一系列回归。
一个常见问题是翻译后的代码以微妙的方式改变了现有行为。例如,一些整数值被改为十进制数,导致某些 SDK 出现问题。其他差异涉及空字符串、时区或具有不同错误处理方式的替换库。代码可以成功编译。但结果无法由系统的其他部分处理。
另一大类问题涉及状态管理和操作协调。例如,当一个操作被取消时,它并不总是停止所有相关工作。此外,当资源过早释放时,会话会卡住。还有一些功能丢失。其中一些只被部分迁移。
还有一般的集成和性能问题。例如,Rust 代码有时在 Node 的主线程上执行冗长的工作。这冻结了界面。在 Windows 上,缺少进程启动设置导致出现不需要的控制台窗口。
移植的性能影响
重写降低了运行 Copilot 的 agent 运行时的开销。特别是在时间和内存方面。使用 Rust,无需初始化 Node 和 V8。也无需加载和准备 JavaScript 应用程序。应用程序可以将 Rust 运行时直接加载到自己的进程中。这避免了与单独的运行时进程通信的成本。

GitHub 在他们的详细测试中看到了性能提升。例如,在一个特定的试验中,创建客户端、完成单轮和清理在移植前耗时 5.25 秒,移植后耗时 292 毫秒。这几乎是 18 倍的改进。
他们也有容量提升。在一个许多会话共享一个客户端的测试中,吞吐量从每秒 7.55 个完成的会话生命周期增加到 120。内存消耗也下降了。在一个 10 客户端的测试中,私有内存的峰值增加从 1383 MB 下降到 126 MB。
GitHub 如何利用 AI 将 Copilot 从 TypeScript 移植到 Rust,创下速度纪录
这次重写基本保留了原有的算法。如果围绕 Rust 的内存所有权与并发方式重新设计运行时的部分内容,还可能带来更多改进。
移植成本与经验教训
整个移植工作花费了约 $120K 的 AI token 成本。它们覆盖了大约 136 billion tokens。其中大部分是缓存输入,这降低了反复处理已有上下文的成本。
除此之外,还有投入在这项工作上的开发者时间。除主要开发者外,其他开发者也在集成、打包、构建改进和评审方面做出了贡献。
过程中积累了很多经验教训。
其一,向 AI 工具给出清晰的指令至关重要。最初一些要求移植某个组件的请求,有时会让 agent 只翻译核心逻辑,周边工作仍然留在 TypeScript 中。必须让指令更有效,才能处理这一问题。
另一个教训是,要成功完成这样的迁移,你需要强大的端到端测试。这些测试应检查完整工作流是否保持了原有行为。团队事先提高了测试覆盖率,但更多的覆盖率本可以避免一些回归问题。
测试本身也需要保护。例如,你不会希望 agent 为了让测试变弱而修改实现,或改动预期结果。因此,你需要某种监督机制。
还有一个教训是,对于这类迁移,应当先尝试翻译,而不必操心重新设计。保持既有行为和算法不变更为重要。如果你试图把移植与其他改进合并进行,只会增加问题、时间和 token 成本。
- 使用 Copilot 将 GitHub Copilot 运行时迁移到 Rust