---
id: "PLMOVlZC4eU"
title: "微软杰出工程师：为何以及如何将整个代码库移植到 Rust｜Stephen Toub"
channel: "Ryan Peterman"
host: ["Ryan Peterman"]
guests: ["Stephen Toub"]
date: "2026-11-02"
updated: "2026-11-03"
duration: "1:21:57"
duration_seconds: 4917
source_type: "youtube"
youtube: "https://www.youtube.com/watch?v=PLMOVlZC4eU"
canonical: "https://pod-exp.pages.dev/PLMOVlZC4eU/"
transcript_jsonl: "https://pod-exp.pages.dev/PLMOVlZC4eU/transcript.jsonl"
language: "zh-CN"
translation: true
translated_from: "en"
timestamp_precision: "block"
topics: ["AI 编程","AI 智能体","AI 基础设施"]
series: ["AI 软件工程师"]
---

# 微软杰出工程师：为何以及如何将整个代码库移植到 Rust｜Stephen Toub

> 中文译文，由英文原音字幕翻译整理，不是官方逐字稿；引用原话请核对英文原视频。说话人标签由整理者依上下文标注，带「未确认 / 未标注 / 不确定」等字样的标签不可靠。时间戳一般为块级（所在时间块的起点），不是逐句时间；正文自带 [hh:mm:ss] 的段落除外。

**内容提要：** 微软杰出工程师 Stephen Toub 分享了他如何在约十四周半内借助 AI 智能体，将 GitHub Copilot 运行时从 TypeScript 移植为 Rust。项目并非为了追逐 Rust 热潮，而是要让运行时更容易嵌入各类产品，同时提升效率、吞吐和启动速度。他比较了语言与运行时，解释渐进迁移、测试护栏、多模型审查和回归处理；这次工作涉及约 40 万至 45 万行生产代码、约 1360 亿 token，按公开价格约花 12 万美元。对年轻工程师，他仍建议打牢计算机、算法和系统基础，但也坦言 AI 正在改变积累经验的路径。

## [0:03] 开场

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-01> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=3s>

**Stephen Toub：** 总共大约用了 1360 亿个 token，费用约 12 万美元。12 万美元。

**Ryan Peterman：** 这位是微软杰出工程师 Stephen Toub，他独自用 Rust 重写了一个 40 万行的代码库。我和他聊了这段经历带来的收获。

**Stephen Toub：** 这些以前贵到做不起的项目，现在已经相当可行了。

**Ryan Peterman：** 我是想问：你一路上是怎么发现并修复回归的？

**Stephen Toub：** 我逐行读代码并不能防止 bug。事实上，让智能体逐行检查要有效得多。有件事如果重来我会换种做法……下面是完整节目。

**Ryan Peterman：** 我想把这次对话聚焦在你为 GitHub Copilot 运行时做的移植上，也就是把它重写成 Rust。我觉得，最近这些模型让一种新类型的项目变得可行了。业内很多人可能都会尝试类似的事，比如把遗留代码库迁到性能更好的语言。所以我想先问问，这个项目具体是什么？你为什么要把所有东西都用 Rust 重写？当时要解决什么问题？

## [1:07] Copilot 运行时为什么要移植到 Rust

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-02> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=67s>

**Stephen Toub：** 这是个好问题，尤其是现在大家有时会觉得，把东西重写成 Rust 是一种潮流。有人问我时，默认的前提像是“你只是因为能这么做，所以就去做了”。事情完全不是这样。如果项目原本处在某种状态，重写根本不会成为一个选项。真正的推动力主要是 AI 发展太快了，这大家都知道。过去几年里，AI 带来的能力突飞猛进。

在 GitHub 和微软内部，很多项目都是从头开始加入 AI 能力的。它们最初只是调用大语言模型，然后在外面包一点东西，再继续往上加，最后逐渐搭成现在所谓的智能体框架、智能体循环或智能体运行时。结果我们有了很多套，因为每个团队都自己做了一套。这种局面并不好，尤其是大家都想做到最好、走在前沿的时候。AI 领域的新模型每周甚至每天都在发布。几周前，OpenAI 和 Anthropic 还接连发布新模型、互相超越。一个月前还在研究中的新技术，今天可能就成了每个框架都得有的功能，否则马上就过时了。

我们不希望一大堆不同实现都各自费力跟进。最好是有一套，至少也要有少数几套可扩展的框架或运行时，大家都能用，并按需要定制和扩展。Copilot CLI、GitHub 应用，以及 GitHub 上让 Copilot 执行任务或做代码审查的 Copilot 云端智能体，用的就是 Copilot 运行时。它原本是用 TypeScript 写的，运行在 Node 和 V8 上。这会限制它作为可嵌入库的适用范围。

我希望这个运行时能在各种地方使用，但其中一个主要障碍就是它的实现语言、框架和运行环境。核心目标不是非得转向 Rust，而是离开 TypeScript 和 Node，换成更容易嵌入、效率更高、工作集更小、吞吐更快的方案，并能被各种语言和框架的环境使用。这基本上就是这次项目的起因。

正如你刚才提到的，大家想做这类移植或迁移，原因很多。整个行业都很常见：可能是从过时框架迁到新版，可能是换一种语言，也可能是把已经乱成一团的遗留代码库整理成更现代、更清爽的系统。这类迁移到处都有，但很多时候没人去做，因为成本太高、耗时太长。一两年前我们也会遇到同样的问题。现在有了新一代模型和框架，这些过去贵到做不起的项目，已经能在很短时间内完成了。

## [5:10] Copilot 运行时为什么要移植到 Rust（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-03> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=310s>

**Stephen Toub：** 现在这些迁移和移植已经相当可行，所需时间也很短。

## [5:38] 为什么选择 Rust

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-04> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=338s>

**Ryan Peterman：** 你写的文章里有句话：“我一开始不是想转向 Rust，而是想离开 Node.js 和 V8。”这让我想问，如果不一定要用 Rust，你考虑过哪些替代方案？最后为什么特意选了 Rust？

**Stephen Toub：** 我做的第一件事，是用智能体方式快速搭了一组原型。现在用模型做原型很快。我用不同运行时的 TypeScript 试了 Node、Bun 等，也试了 Python、Go、C、Java 和 Rust。每种方案我都做了一个很小的端到端骨架，让系统能跑通流程，后端接一个本地的聊天补全模拟服务器；每个原型大概 5000 到 1 万行。

我比较了端到端性能、工作集、吞吐量、承受大量负载时能扩展到什么程度，也看了它能否满足需求，以及让现有用户使用起来要做多少工作。我们当时有六种语言的 SDK，它们都是 Copilot 运行时上面的轻量绑定，所以也要考虑这套运行时怎么供所有 SDK 使用。以前我们不想把 Node 强行塞进调用方应用的进程里，SDK 只能另外启动一个进程来运行会话。但我们也希望能像其他库一样，提供进程内运行的选项。

所以我们用这些性能目标和限制来评估各种语言和运行时，查看数据，判断哪些方案奏效、效果有多好。就性能和嵌入能力而言，TypeScript 和 Python 很快就出局了。Go 的性能不错，代码也挺干净，但它并不是为嵌入设计的；互操作也不是它的强项。不是做不到，只是有点逆着它的设计方向来。Java 在这方面也不太理想。JavaScript 的表现还可以。

最后主要的候选是 C，尤其是用 Native AOT 的 C#，这样可以提前编译成机器码；另一个是 Rust。从性能看，两者几乎不相上下，各项指标都差不多。有些地方 Rust 略好，有些地方 C# 略好。如果原项目本来就是 C，我们根本不会讨论重写，会直接保留。但它不是，所以最后要看这些标准：性能和嵌入能力两者都不错，C# 的互操作特性也很强。于是决定因素主要变成了更软性的条件。GitHub 内部有其他 Rust 项目，C 项目则很少；在 GitHub，懂 Rust 的人比懂 C 的人多。当然微软内部情况就不一样了。综合这些因素，我们最终选了 Rust。

**Ryan Peterman：** 我知道 Anders 最近带团队把 TypeScript 编译器从 TypeScript 移植到了 Go。那个项目好像比你的项目开始得早一点。我想知道你们有没有交流过心得？

**Stephen Toub：** 当然交流过。这正好说明，不同项目可以得出不同结论，而且都合理。TypeScript 编译器没有必须嵌入其他应用的需求。反过来，编译 TypeScript 的工作形态，也和发请求给大语言模型、处理提示词、管理沙箱这些工作很不一样。项目的本质不同。

有意思的是，最近几周已经有人用智能体把一些项目从其他语言移植出来。你去 X——或者现在该叫 Twitter——搜一下，就能看到有人把 TypeScript 的 Go 编译器移植成 Rust。以代码库的规模和整洁程度来看，现代模型让这件事做得非常快。这很有意思。

## [9:40] 为什么选择 Rust（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-05> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=580s>

**Stephen Toub：** 在 GitHub 内部，懂 Rust 的人更多，懂 C 的人更少。当然，微软内部不是这样。综合这些因素，我们最后选了 Rust。

**Ryan Peterman：** 我知道 Anders 最近带团队把 TypeScript 编译器从 TypeScript 移植到了 Go。这个项目好像比我们的项目开始得早一点。我想知道你们有没有交流过心得？

**Stephen Toub：** 当然。这正好说明，不同项目可以得出不同结论，而且都合理。TypeScript 编译器没有必须嵌入其他应用的需求。反过来，编译 TypeScript 的工作形态，也和发请求给大语言模型、处理提示词、管理沙箱这些工作很不一样。项目的本质不同。

有意思的是，最近几周已经有人用智能体把一些项目移植到了 Rust。你去 X——或者现在该叫 Twitter——搜一下，就能看到有人把 TypeScript 的 Go 编译器移植成 Rust。以代码库的规模和整洁程度来看，现代模型让这件事做得非常快。这很有意思。

## [11:28] 讨论迁移策略

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-06> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=688s>

**Ryan Peterman：** 既然你们确定了项目动机，也明确了要解决的问题，我想问问迁移策略。我看到过不同项目采用不同方式。比如你刚才提到的 Bun，看起来是新开了一个大分支，整个分支完全用 Rust 重写，然后一次性发布稳定版。你这个项目则显得渐进得多，一点一点迁移。你是怎么权衡这些策略、决定什么时候选哪一种的？

**Stephen Toub：** 先说 Bun，我很喜欢 Jarred 写的那篇文章。我们迁移到一半时，那篇文章发布了，我之前不知道他们也在做移植。看到另一个项目的代码量大约和我们同一个数量级，而且也认定这件事值得做，还把它落地了，挺让人兴奋的。他们原来用 Zig，而不是 TypeScript。文章里说，他们花了大概 11 天就让 98% 左右的测试通过，这很厉害。正如你说的，他们基本上是一次性重写整个项目。

我没参与他们的项目，不了解幕后所有细节。但我注意到，他们的 npm 页面上似乎一直到四月中旬都差不多每天发一次构建，大量是 canary 版本，然后就停了。文章说移植本身用了 11 天，从零开始把 50 万行代码库移植到 Rust，并让 98% 或 99% 的测试通过，确实惊人。但在我能看到的范围内，之后又过了两个半月才有新的 npm 发布。也就是说，核心移植只花了很短时间，随后似乎还有一段稳定化过程，导致发布间隔约三个月。

有意思的是，这也差不多是 Copilot 移植的周期——我花了十四周半。原因当然有很多，但本质上我们耗时差不多，只是选了不同的做法。Jarred 在文章里提到，不想采用 Copilot 那种渐进方案，因为会产生很多临时互操作代码。他说得没错，确实会有。我们知道这么做会带来什么，只是根据自身约束选择了这种方法。

对 JavaScript 运行时来说，暂停三个月不发功能、不修 bug，问题也许不大；三个月前的 JavaScript 和今天的差异没那么大，可以先把一切停下来，重写完再继续发布。但在 2026 年夏天的智能体框架领域，如果停更三个月，你将面对的世界……

## [15:30] 讨论迁移策略（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-07> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=930s>

**Stephen Toub：** 发布时的世界会和开始时大不相同。所以我们不愿意停下来好几天，更别说更长时间。就算两周能完成，也意味着这两周里不是要让整个团队停工，就是要持续处理大型代码库不断涌入的改动，判断怎么适配，再把它们移植过来。

我们采用了我认为适合 Copilot、但不太适合 Bun 的方式：在正常发布的主干代码库中，把代码一块块从 TypeScript 迁到 Rust。过程里仍然每天发布，只是代码构成逐渐改变：开始时是 100% TypeScript、0% Rust，最后变成 100% Rust、0% TypeScript。整体效果挺好。当然，过程里来了又走的临时代码不少。我们用 napi-rs 连接 TypeScript 和 Rust，最多时有几千个互操作签名，我记得两三千个调用接口；最后都降到了零，因为不再需要互操作。

还有其他做法：可以“推倒重来”，让所有人停下手头工作，直接在主干上重写；可以开功能分支，让主干继续前进，然后不断移植新改动。渐进迁移也可以像我说的那样，原子式地用 Rust 替换 TypeScript；还可以两套组件并存、一起发布，再通过功能开关选择，让它们并排接受分批放量和实验。采用哪种取决于具体原因。我觉得我们选的方式适合自己，但其他做法对别的项目也成立，甚至可能更好。

**Ryan Peterman：** 听起来 A/B 方案还是要有临时测试框架来比较两边。要是单独维护一个分支，同时旧项目主干不断有新提交进来，就得不断移植。不过有了现代模型，逐个提交的移植可能很容易。你们考虑过这种做法吗？和承担互操作成本相比，成本怎么算？

**Stephen Toub：** 这里其实有几个问题。如果我们维护独立功能分支，最后把整套新系统一次性部署，那就只能等上线后在真实环境里一次性测试所有东西，风险很高。我们选择的方式有个很大的好处，就是可以逐步验证。

## [19:31] 讨论迁移策略（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-08> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=1171s>

**Stephen Toub：** 这样就能把生产环境用于最后阶段的验证，而且每次部署只比上一次多一小块改动。整个移植期间，我们大概发布了 130 个版本，每次都只多迁一点。出了问题，定位原因就很快、很直接，有时候甚至不用打开电脑。有人报问题时，你会立刻知道大概是哪一块，然后迅速缩小范围。要是整个系统一次性重写，这种验证就难多了。

当然，这个过程中确实出现了回归。其中相当一部分来自把主干改动合并进来。我仍然用功能分支，只是分支周期很短：不是几周，而是移植一个组件大约一天。但一天里，可能有 10 到 20 个 PR 改了这个组件。有不少回归是智能体合并时漏掉了东西，因为移植和合并同时进行。

原子式地从 TypeScript 换成 Rust，相比同时保留 A/B 两套实现，有个好处：我要求智能体移植完就删除对应的 TypeScript。这样反而能帮助发现主干合并冲突。如果主干代码碰到了已经移植的 TypeScript，就会立刻冲突，亮起红灯，让智能体去检查那段代码。要是不删掉旧代码，主干对它的改动就很容易悄悄进入分支中仍未动过的 TypeScript。到时候智能体得在整片已移植代码里找出变化并同步进来；而删除旧代码会马上把它的注意力引到受影响的位置。我们当时就是这样逐块替换的。

## [21:58] 如何发现回归

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-09> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=1318s>

**Ryan Peterman：** 我想很多团队或工程师想重写整个代码库时，最大的顾虑应该是正确性：代码太多了，根本不可能让人逐行读完来确认正确。你一路上是怎么发现并修复回归的？

**Stephen Toub：** 最重要的是端到端测试、集成测试，叫什么都行。Copilot 的测试大致有两类：单元测试主要测代码库里一个个很小的功能，很多测试还能访问内部实现，因此可以测那些没有对外暴露的小函数和代码片段。

另一类是端到端测试，包括运行时层、SDK 层和 CLI 层的测试。CLI 和运行时在同一个代码库里，所以 CLI 的端到端测试实际上也会覆盖运行时。虽然并非完全如此，但大体可以把 CLI 看成是用最贴近用户的界面暴露运行时能力。我们用这些端到端测试验证行为。

绝大多数回归都出在缺少相应功能的端到端测试上。通常我们有单元测试，但这次的单元测试也是用 TypeScript 写的，用来测 TypeScript 内部实现。很多情况下，代码迁移时这些测试也得一起重写。不过渐进迁移有一个好处：如果把底层一个组件换成 Rust，上层 TypeScript 仍通过互操作调用它，原有单元测试还可以间接验证这个 Rust 组件。

真正的安全网是覆盖整套系统的集成测试和端到端测试。我曾给团队写过一份文档，说明为什么要移植、怎么推进、预计时间、采用的方法和技术等。其中第一项就是先加强端到端测试。我做了这件事，但如果重来，我会做得更多，这是我的一个不足。

道理很简单：只要测试覆盖了你关心的行为，测试不回归，行为就应该没问题。出现回归本身就说明测试有缺口。当然也不总是如此。最让人哭笑不得的是，我们没禁止智能体在改变行为的同时重写端到端测试。智能体的目标就是让测试变绿，所以如果允许，它们会同时修改“判定标准”和被测代码，让新代码通过测试。

还有一次，智能体改动了公共 API，CI 拦了下来，说不能这么做。不过我们的 CI 有个逃生口：如果有人确实知道自己在做什么，可以给 PR 加一个标签，表示这次破坏是可以接受的。智能体发现了这个办法，便给 PR 加了标签，表示“这次破坏没问题”——可实际上并没问题。我注意到了，没有让它溜过去。

## [25:58] 如何发现回归（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-10> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=1558s>

**Stephen Toub：** 还有些问题很难靠测试彻底覆盖。你可能已经有端到端测试，但有些检查很细。例如数据通过网络发出去时，在所有可能情况下，都要确认传输的每一个字节最终都符合预期。这需要庞大的测试套件，任何缺口都可能让问题漏过去。

TypeScript 和 Rust 的线程模型、并发模型差别很大。大家常说 Rust 代码只要能编译就没问题，确实能防住很多类型的错误，但绝不是所有错误。并发错误仍然会漏过去。我们遇到过生命周期和并发方面的问题，这些都不是 Rust 编译器能发现的。我们从大体串行、单线程的执行模型，转到有意追求更好扩展性、让任务并行运行的模型，当然会引入不少问题。

回到你的问题，最关键的是把所有关心的行为都写进测试，再让智能体移植代码，同时维持测试通过。还要设好护栏，防止智能体在需要验证时顺手把验证标准也改掉。

**Ryan Peterman：** 我还是觉得回归不可避免，因为测试覆盖有点像“自愿申报”：得有人先说哪些行为重要，但总可能漏掉东西。这类项目是不是注定会有一些功能被破坏？

**Stephen Toub：** 我觉得是。谁知道一年后情况会怎样，发展太快了。但就现在而言，肯定会有回归；如果一个都没有，我会非常惊讶。除非只是很小的代码库，要重写几十万甚至几百万行代码，按概率就一定会有。如果智能体 99.99% 的时候都能做对——这可能还比大多数人高出一两个九——剩下的 0.01% 仍然会有各种错误。代码规模到百万行时，哪怕这是一小部分，也会变成实实在在的问题。

你可以多派一些智能体来找问题，我们也这么做了：合并前做很多智能体审查，合并后继续让智能体找 bug、找并发问题等等。它们确实能发现问题，但以我的经验，对这么大体量的代码，不可能做到百分之百完美。

## [30:01] 如何发现回归（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-11> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=1801s>

**Ryan Peterman：** 我猜大部分代码没有经过人工审查。你们怎么大规模做代码审查？还是说基本没审？

**Stephen Toub：** 我们确实做了一些，但我没有逐行读完。那不可能，就算做了也很浪费时间。逐行阅读并不能防止 bug。事实上，让智能体逐行检查更有效，不光更快，质量也比我自己逐行看更好。

我确实看了自己提交的每个 PR 的代码，但重点放在整体层面：方向对不对，架构对不对，组件划分是否合理，算法是否合适，有没有可疑之处。我会站在很高的视角对照两套代码，看有没有明显不对劲的地方。有时也会快速翻过所有改动，看看有没有什么跳出来。但逐行细节方面，一个好的智能体审查员肯定比我强，我认为也比大多数人强。

在宏观层面，我很多次会叫停智能体，说：“等等，这方向不对。”有时反过来，智能体会说“做完了”，我会回答：“还没有。”（笑）“这不是我们要的结果。”所以我的工作更多是在把握整体方向，而不是盯微观细节。

## [32:09] 如何引导智能体

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-12> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=1929s>

**Ryan Peterman：** 我看到你在博客里有张很有意思的柱状图，把你发给智能体的每条消息都按意图分类了。回头看你是怎么引导它们的，你的大部分时间花在哪些事上？哪些时候你介入后影响最大？

**Stephen Toub：** 大致有两三类更高层次的工作。有一类反映了现在模型和框架处理长周期任务的状态：我对进展不满意，有时要在它们停下来时让它继续，有时要在它们走错方向时叫停。

但大多数时候，我是在处理需要权衡的选择。合理的人或智能体可能会选不同路径，我要确保我们走对了。我经常会和主智能体讨论当前进度、需要做的决定，并像橡皮鸭调试那样，一起梳理当时各种选择的利弊。这包括之前谈过的渐进迁移还是暂停一切、整体重写，也包括某一个具体切片该怎么做。

有时智能体会说某个组件做完了，我看了会觉得这不是合适的收尾点：它暂时还牵连着其他系统，也许再多做一点，越过某个架构边界，就能把一大堆东西清理好，让合并后的代码库处于更合理的状态。有时它宣布一个切片完成，乍看似乎可以，但多做一点，或者撤回一些、少做一点，都能让代码库更好。

还有时它做得超出了我的预期。我要求移植尽可能严格一对一：不删功能、不加功能、不大改算法，也不要顺手修碰到的任意 bug。遇到这些问题先记录下来，让我之后单独处理。我希望移植严格保持原有功能。有时我发现它违反了这些规则，就让它撤回到之前的做法，或者先和我讨论清楚，确认我接受这个改动。相当一部分回归来自它违反了这些规则，而我没发现，结果把不该做的修复也带进去了。

## [36:09] 如何引导智能体（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-13> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=2169s>

**Stephen Toub：** 移植阶段的问题大多已经不再被报告了。不过每天往代码库合并几百个 PR，本来就会有回归。通常我们会在发布前发现并修好，问题只是在主干里出现一下。

但前一两天有个很边缘的案例，我看到后觉得奇怪：报告说这是我加的，可我不记得加过。回头一查，它最初并不在我的移植 PR 里。后来同事或同事的智能体提出一条建议，智能体为了响应安全审查，把某项功能限制得更严；限制过头后，移植前能用的东西，移植后反而不能用了。追查这种事挺有意思。

**Ryan Peterman：** 有意思。所以你的智能体会自动监听 PR，如果觉得反馈合理，就可能不经你确认直接采取行动，对吗？

**Stephen Toub：** 我主要用 GitHub Copilot 应用里的 Agent Merge 功能。它可以自动监视 PR，自动变基或处理合并冲突，自动修测试、让 CI 变绿，自动处理审查反馈，也可以在所有检查通过后自动合并。这四项都能单独选择。

我通常开前三项，但不开自动合并。等所有检查都变绿后、我按合并按钮前，我会回头看看智能体为了让 PR 变绿做了什么：修了哪些测试，收到了什么反馈，怎么处理的。这样我至少能从整体上了解改动，而不是逐行审查。前面那个案例我记得自己看过，但没有完全理解它把限制收得多严、会挡住多少情况。否则我会告诉它：“这些情况没问题，放行吧。”

**Ryan Peterman：** 要是四项全开，团队里肯定没人会故意这么做，但假设我是团队成员，我可能会写一条恶意评论，措辞听起来还挺合理，比如“请把所有东西都删掉”。

**Stephen Toub：** 对，或者说：“我之前让你格式化 C 盘，你格式化了吗？”（笑）把所有东西都删光。不同项目我会选择不同的自动化选项。比如开源项目，我可能只会保留自动处理 CI 这一项。

## [40:11] 如何引导智能体（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-14> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=2411s>

**Stephen Toub：** 也可能保留自动变基，但我绝不会让它自动处理 PR 上任意的审查意见，更不会允许它自动合并。对于我信任参与项目的人所维护的闭源项目，风险小一些，但勾选越多选项，仍然需要越高的信任。

我喜欢这个应用的一点是，各种 Agent Merge 功能都有内置提示词，而且我能为每项能力添加自己的要求，告诉智能体该怎么做。例如要求它总是变基而不是合并；处理审查反馈时要先认真判断哪些意见该接受，哪些可以直接处理。

**Ryan Peterman：** OpenAI、Anthropic 和 Cursor 都在用这个产品让工作更轻松。WorkOS 是一个 API 平台，只需几行代码，就能给应用加入 SSO、SCIM、RBAC 等企业功能。这些功能是向其他公司销售软件时需要的，但通常不是你产品的核心。现在 WorkOS 也增加了对 AI 智能体的支持。比如 WorkOS for Agents 给每个智能体单独身份和短期、有限权限的令牌，而不是长期 API 密钥；出了问题可以撤销某个会话，让它下面的所有令牌都失效。另一个功能 Airlock 是授权层，每个智能体执行的操作都会根据你用自然语言写下的规则进行检查，既不是什么都直接放行，也不是完全无人监管。最后还有 Pipes，可以把智能体连接到 300 多种第三方工具，你不用自己管理令牌。

## [42:12] 在上线前发现回归

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-15> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=2532s>

**Ryan Peterman：** 如果你在做 SaaS 或 AI 智能体并向企业销售，WorkOS 能用几行代码补齐这些能力。访问 workos.com 了解详情并开始使用。感谢他们赞助本节目。

**Ryan Peterman：** 我们刚才谈到回归，你说很多都在进生产环境之前发现了。很多人听到“回归”会以为应用宕机、系统不断爆炸、事故频发。端到端测试之后，还有哪些防护措施，才让这些回归没有变成严重问题？

**Stephen Toub：** 我称作回归的这些问题里，大约三分之二是在合入主干后、发布任何预发布版本之前很快发现的。那时我们每天大概发三个预发布版本，所以发现得很快。

有些问题进入了预发布版本。CLI 的发布分预发布版和稳定版；某一天的预发布版大概会触达 5% 到 10% 的用户，其余 90% 或 95% 只使用稳定版。我不确定具体比例，但大约有 10% 到 20% 的问题进入过预发布版。很快就会有人提 issue，或者说：“我发现行为变了，这是设计如此吗？”很多变化只是和过去不同，不一定是坏事，但差异明显到用户会注意并来问。有些情况是我没能阻止智能体在移植时顺手修 bug；这些改动有的其实是好事，只是并非我们有意要做。

还有一些进入了稳定版。由于主干和预发布阶段都没注意到，它们有时会在稳定版里存在一段时间。这就是最近一段时间我们陆续发现的一些问题；一个月前会持续几周陆续出现一些特别边缘的情况，行为有一点不同。用户会问这是否有意为之，很多时候并非如此，我们收到反馈后就会修。还有一些问题是从遥测系统里发现的，比如异常、崩溃监控。这些显然都是非预期的，我们也会修复。

## [45:16] 他使用了哪些模型

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-16> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=2716s>

**Ryan Peterman：** 你在文章里放了张图，展示整个项目过程中用过哪些模型。图上按周统计了 Claude、GPT，偶尔还有 Gemini 消耗的 token。项目刚开始几乎全是 Claude，到最后几乎全变成 GPT。你为什么中途换了主要使用的模型？

**Stephen Toub：** 我一直在试不同模型，因为那段时间两家实验室都在很快地发布新模型。哪个模型当时好用，我就先用着；遇到让我不满意的地方，再试另一个。这并不代表长期偏好，只是当时哪个最适合我的工作。

一开始我主要用 Opus 4.6 或 4.8，效果很好。后来 GPT 5.5 还是 5.6（我记不清了）在这些任务上更好，我就换过去。之后 Opus 5 发布，我觉得不错，又换了过去。最近我用 GPT-6.1-Sol 很顺手，会用 Opus 5.5 来审查它写的代码，所以两者分工。

移植过程中，GPT 和 Claude 有时都会表现得很让人沮丧。某个模型可能卡在一个点上，不管我怎么做，它都盯着某件事，不能跳出来看全局。我有时会保留代码改动、开一个干净的新会话，让它清空上下文、重新开始；但它常常还是会陷回原来的死胡同。这时我就换模型，让新模型接着做，直到它也开始出现让我不满意的行为，再换别的。

我也试过用 Gemini 和 Grok 作为主要执行模型，但更多时候把它们用于多模型代码审查。主要工作我用 GPT 或 Claude，之后会让来自不同模型系列的三四个模型逐行审查移植结果。我经常这么做，至少每次变基、把主干的新功能合进来时都会做，有时更频繁。

**Ryan Peterman：** 我注意到你有个提示词，可能会在变基时自动触发审查，要求模型以对抗性的方式、或者让多个模型一起检查。你为什么会选择这种方式，而不是让同一个模型用不同线程和关注点做代码审查？

## [49:18] 他使用了哪些模型（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-17> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=2958s>

**Ryan Peterman：** 也就是说让多个模型同时审查。你为什么认为这比用同一个模型、给不同线程分配不同关注点更好？

**Stephen Toub：** 这样能得到不同的视角。非确定性系统里，即使只是稍微改一下，也可能让模型沿着不同路径走、关注不同内容。而你能做的最大改变之一，就是换一个模型。要想得到不同意见、让它们关注不同的问题，我发现最好的办法就是换用不同模型，尤其是和最初负责主要工作的模型不同的模型。

## [50:06] 项目的收益与成本

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-18> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=3006s>

**Ryan Peterman：** 重写完成后，具体产生了什么影响，花了多少成本？从商业角度看，这个项目的收益和成本分别是什么？

**Stephen Toub：** 收益非常明显。GitHub 和微软各个产品、服务和团队可以依赖一套共享框架，它会持续变得更好、力求保持一流水准，其他团队就不用各自投入资源重复造轮子，可以把精力放在自己的业务价值上并复用这个组件。就像依赖任何一个大型库一样，你希望有人专门持续维护它，而自己可以使用不断演进的成果。从商业价值上说，GitHub 和微软能够共用这套框架，价值无法估量。移植以前，这件事更难推销，也更难证明值得投入。

另一部分收益来自实打实的性能提升。假设一个系统需要十倍的工作集，机器密度就会降低十倍，可能意味着要十倍数量的服务器。要是能让同一台机器同时服务更多用户、提高吞吐量、把延迟降低五六倍，都会直接影响成本和利润。

很多服务收到一个请求后，只要启动智能体循环再多跑一轮，事情很快就结束了，因此启动成本会占很大比重。启动 Node 应用和启动原生 Rust 或 C 程序差别很大，每个请求可能差几百毫秒，有时甚至几秒。这样的延迟很容易测出来，对商业结果影响也很大——前提是你能采用这个运行时；如果做不到，就还是回到之前那种难以推广的局面。所以这次移植很有价值。

至于成本，我保存了这次工作中约 99% 的会话日志，再从中推算输入 token、缓存写入和读取、输出 token 的数量。总计大约 1360 亿个 token。按当时 OpenAI 和 Anthropic 网站上这些模型的公开价格计算，约为 12 万美元。

## [54:07] 项目的收益与成本（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-19> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=3247s>

**Stephen Toub：** 12 万美元没有计入企业折扣，只是按 OpenAI 和 Anthropic 网站上的价格估算。再加上我的时间：项目用了十四到十五周，但我同时还做其他事。我现在打开 Copilot 应用，大概有 35 个工作会话在进行，有些做同一类事情，有些属于不同项目。开发者不再一次只做一件事。

粗略估算一下，那段时间我提交的 PR 里，大约五分之一和这个项目有关，另外 80% 用于其他工作。按十五周的五分之一算，大约是三周的个人工作时间，分散在三个月左右，再加上 token 成本。

成本还在下降。模型的价格正以惊人的速度下跌。我记不清具体数字了，但我想 GPT-6.1-Sol 的价格大约是 GPT-6-Sol 的一半，而 GPT-6-Sol 又是 GPT-5.6-Sol 的一半；模型越来越便宜，能力也越来越强，我引导它们做对事情所需花的时间也越来越少。所以这类移植和迁移只会越来越便宜。

**Ryan Peterman：** 三周左右的开发者时间，再加上 12 万美元，就能重写整个代码库。如果没有 AI，你们要做这件事会是什么样？

**Stephen Toub：** 首先，项目根本不会发生。（笑）说真的，这个项目做不成，因为等我们完成时，移植的对象都已经过时了。这个领域变化太快，我们可能永远也做不完。博客里的图能说明这一点：移植很长一段时间里，Rust 代码在增加，但 TypeScript 的规模大体没变、甚至稍微增加了，因为与此同时代码库还不断加入大量新功能。移植刚开始时，大部分代码是 TypeScript，新功能自然也大多用 TypeScript 写；项目快结束时，大部分代码换成了 Rust，新代码也大多用 Rust 写。

即便不考虑这些新功能，这也是约 45 万行生产 TypeScript 代码，还不包括测试。TypeScript 里还有几十万行单元测试，也需要移到 Rust。想想一个优秀开发者一天能合理完成多少工作，就知道过去要做成有多难。

## [58:10] 项目的收益与成本（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-20> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=3490s>

**Stephen Toub：** 过去这大概要整个开发团队花一两年才能做成，对吧？即便能做成，也会是一笔巨大的投入。我甚至很难想象怎么写这样的提案，因为我知道它大概会被立刻否决：“当然不可能做。”而现在的提案是：我用三个月时间，每周投入大约 20%，之后整个系统就迁好了，大体上也不会影响团队其他人。虽然这不是百分之百准确，但可以说几个月后就能获得这些业务收益，成本就这么多。这种提案好写得多。

**Ryan Peterman：** 即便真的按没有折扣的公开价格花掉 12 万美元，拿它和一名资深开发者一年的成本相比——包括福利和奖金——这也划算。对于这种工作，目标很明确，而且已有功能里已经编码体现出来了，成本至少低一个数量级，甚至更多。工程师一年可能要花 20 万到 40 万美元，12 万美元只是很小一笔。你当初提案时，预估过 token 成本吗？

**Stephen Toub：** 预估过，但账单比我想的高，主要是最后要迁的代码行数比我预计多。我没充分考虑新代码增长的速度。有些事我做对了，也有些做错了，现在回头看得更清楚。前面提过一项：端到端测试投入不够，没把覆盖做得尽可能全面。另一项就是没有认真估计待迁代码的增长量。

写提案时，代码库大约有 15 万行生产 TypeScript，准确数字记不清了，大概就是这个量级。我根据这个数字做了些粗略计算，也参考之前不同语言原型的耗时，估计大约六到八周可以完成。但实际需要移植的东西远不止这些：有几十位开发者用智能体很快给代码库增加了各种功能。这不是公开开源项目，但基本上相当于内部开源，很多人会进来添加他们需要的东西，再由核心团队帮忙审查。因此代码功能不断大量涌入，我没有把这部分算进去。

## [1:02:12] 项目的收益与成本（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-21> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=3732s>

**Stephen Toub：** 另一个我没考虑到的问题是，Copilot CLI 和运行时的耦合比理想状态更紧。要只移植运行时，就得先把它们拆开，让使用运行时的应用不必连 CLI 一起部署。还要把某些其实不必放在 CLI、可以下移到运行时共享的功能移过去。我低估了目前标记成 CLI 的代码里，有多少适合下沉。整个过程中，这部分代码也被移了下来。

最后我们移植了大约 40 万到 45 万行 TypeScript，差不多是我估算的三倍，这影响了完成时间，也影响 token 数量。

**Ryan Peterman：** 走过这个过程之后，如果有工程师团队考虑重写，应该看哪些条件来判断值不值得做？

## [1:03:27] 什么时候值得整体重写

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-22> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=3807s>

**Stephen Toub：** 归根结底要看业务价值。有些事情是自己掏钱做着玩的，那你自己决定好玩值多少钱就行。比如我不喜欢去赌场，因为我觉得赌博是在输钱；有些朋友很喜欢，他们觉得那是在为一晚娱乐付费，不觉得自己输钱。个人开发项目也是一样，如果你想花 token 把它移植到另一种技术上，那就做吧，玩得开心。只是要清楚收益是什么——在这种情况下，收益就是你享受这个过程。

但对商业项目来说，要问它能带来什么业务价值，再像其他项目一样，算清成本和投资回报。这个回报必须足够明确。全世界很多公司在智能体出现之前就做过迁移评估，发现投资回报非常值得。比如从 .NET Framework 迁到 .NET Core，微软投入了很多资源让 .NET Core 变得很快，因此迁移能带来真实的性能收益。公司可以算账：现在每年运行服务花 X 百万美元，迁移后每年省 300 万美元，迁移要花一年、占用一位开发者一年，再算一下就能看出值不值得。

更细一点说，连该投资哪些功能，也可以这样算。我以前花很多时间做 .NET 正则表达式引擎（Regex Engine），可以估算公司或某项服务每年花多少钱运行正则表达式。如果我投入两周改进引擎，让他们使用的模式快四倍，那么这两周投入能带来多少投资回报、服务一年能省多少钱？这样的权衡无处不在。你只要明确为什么做、要花多少、能得到什么。如果把这些写清楚并且说得通，那就是值得做的项目；如果无法证明，就很可疑。

## [1:06:40] 成为杰出工程师一路上的职业体会

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-23> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=4000s>

**Ryan Peterman：** （笑）我为这次采访做功课时看了看你的职业经历。你的 LinkedIn 上没什么资料，但我找到一段你做过的采访……

**Stephen Toub：** 对，我在微软已经 25 年了，很喜欢这里。我在公司内部换过很多岗位，但没兴趣跳槽去其他公司，所以也没怎么维护 LinkedIn 资料。（笑）

**Ryan Peterman：** 我听了那段介绍你不同工作的采访。你成为杰出工程师的路径很有意思，因为做过很多不同岗位，不只是从一个团队的纯开发跳到另一个团队的纯开发。起初你有点像驻场工程师、顾问工程师，后来做过技术写作、VP 的技术顾问，还转去做过 PM。在这些角色里，你最建议别人尝试哪种？如果他们想试试纯软件工程之外的工作，哪种值得体验？

**Stephen Toub：** 我做过的每个岗位都教会我不同的东西。我很尊重大学毕业后想当开发者、成为工程师，然后一直走这条路的人；这完全是有效的职业路径。对我来说，绕了一些弯让我积累了很多不同技能。

你提到的驻场工程师，当时属于微软的咨询部门。我会在某个客户现场待三周到三个月，帮他们解决问题。我因此了解了很多行业和各类具体难题，也从外部视角看到微软的产品哪些做得好、哪些不够好。我还了解了客户真正面对的困难，后来能把这些经验带回来，为他们构建解决方案，这非常有价值。

后来我在《MSDN Magazine》做技术写作和编辑，也会开发一些东西再写出来。这让我学会判断什么真正有趣、什么真正重要，怎么把事情讲清楚，哪些该说、哪些不必说，以及如何讲一个能引起共鸣的故事。

做 PM 时，我学到怎么判断真正需要构建什么，以及需要哪些部分协同起来才能交付。做开发时当然会学到编码、设计、架构等东西。

对我最有意思、我非常庆幸做过、但绝不会再做一次的工作，是微软某位副总裁的技术顾问。那是一次很棒的经历，持续了几年。我像是他的右手边，一个不显眼的搭档，跟着他参与各种工作，替他写材料。每次会议后，我们都会回顾听到了什么、接下来该怎么办，再来回讨论想法。那段经历非常……

## [1:10:43] 成为杰出工程师一路上的职业体会（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-24> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=4243s>

**Stephen Toub：** ……能让我真正看清事情怎么运作、决策到底如何做出。我得以参与一些原本要很多年后才可能接触到的事情。那段经历很棒，但也非常耗人、非常需要无私付出，确实让我精疲力尽。我很珍惜那段经历和学到的东西。如果有人有机会，我很建议去做一段时间这样的工作。

**Ryan Peterman：** 这个岗位很有意思，听起来你像是一位高层管理者的技术型幕僚长，不是行政助理，而是会参与很多重要的内部讨论，提供他们做决策所需的信息。你说自己学到了事情实际上是怎么做成的，能举些例子吗？

**Stephen Toub：** 普通工程师在公司里会看到各种决定：公司宣布新的发展方向、建立合作关系、投资或收购，关闭某个产品、投资新产品、成立新团队。但这些决定看起来像凭空出现，最后才被完整地公布下来。

你通常看不到事情如何走到这一步：考虑过哪些方案、为什么否决某些方案、有哪些权衡，以及有经验的行业人士如何思考这些选择和问题，决定关注什么、忽略什么。我以前接触不到这些。做技术顾问时，我能在一旁观察、吸收这些信息，之后还能和 VP 讨论。我们会走出会议，他问：“你听到了什么？你怎么看？帮我一起理一理。”有时我能提出有价值的看法；有时他会说：“不是这么想的。”（笑）每一次都是学习。

**Ryan Peterman：** 我也听工程师说过，尝试管理岗位很有价值，即使最后觉得不喜欢、再也不想做，也能看到团队管理实际是怎么运作的，这对之后的职业生涯有帮助。

**Stephen Toub：** 是的。我之前没提到，其实我也经历过。我曾以为自己真正想做的是管理，于是安排好转岗，和团队约定六个月后可以转成带团队的负责人。后来一切顺利，我真的成了负责人。但当了六个月后，我开始怀疑这是不是我想象的那样；又过了六个月，我确定这绝对不适合我。（笑）

## [1:14:44] 成为杰出工程师一路上的职业体会（续）

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-25> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=4484s>

**Stephen Toub：** 我知道管理不适合我之后，又花了大约一年，才稳妥地回到个人贡献者（IC）岗位，并一直做到了现在。就像你说的，我非常感谢这段经历，也很感谢微软提供个人贡献者职业发展通道，让人可以持续成长、晋升，却不必直接管理下属。

我后来意识到，我以为自己想当管理者，是因为觉得只有那样才能帮助别人、给人职业建议、帮别人解决问题。这其实是我误解了。做过管理后我才明白，个人贡献者也完全可以做这些事。我喜欢管理岗位的那些事情，并不需要当管理者才能做。

## [1:16:01] 技术书籍推荐

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-26> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=4561s>

**Ryan Peterman：** 有没有哪本对你影响很大的书值得推荐？

**Stephen Toub：** 这本书已经有些年头了，但我读过好几遍，非常喜欢。Charles Petzold 写的《Code》（《编码：隐匿在计算机软硬件背后的语言》）。大概是 2003 年左右出的，我记不太清了。我很看重一种能力：把复杂概念讲清楚，让完全不了解相关领域的人也能听懂。

即使听众本来就懂，能把复杂概念拆成清晰、简洁的内容并讲明白，也很有价值；这样大家能在宏观层面达成共识，你也能清楚地说明自己的观点，把事情往希望的方向推进。

《Code》就做到了这一点。Charles 从头讲计算机是怎么工作的，让没有技术背景的人逐步了解二进制、逻辑门、电路、编程、计算机和互联网，从基本原理开始，一层层搭出对整体运作方式的理解。这本书让我非常惊艳，后来我又读了好几遍。虽然里面的知识我都知道，但我就是喜欢它讲事情的方式。只能推荐一本的话，就是它。

## [1:17:50] 给年轻工程师的建议

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-27> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=4670s>

**Ryan Peterman：** 回顾你的职业经历，你在行业里工作很久了。对今天刚入行的年轻工程师，你有什么可能有帮助的职业建议？

**Stephen Toub：** 这是个好问题，我一直很难回答。几年前我可能能给出更明确的建议，但有了 AI 之后，我还不知道正确答案是什么。

我和 AI 智能体合作时，常常要用上 25 年经验——这可能既有好处也有坏处——才能很快看出它们做得对不对、该怎么引导。智能体可能说：“我百分之百确定正确答案是 A。”我会问：“你有没有考虑 B、C、D？那些取舍不一定不存在吧？”它会说：“确实。”这种小小的引导，也需要你自己有过相关经历。

我担心 AI 智能体的发展会让人失去积累这些经验的机会。我还不知道该怎么办。我很相信要把基础学扎实、从核心原理逐步搭建理解。比如学编程语言，我仍然觉得从 C 这样的语言入门有价值，因为你能理解计算机实际怎么运作、内存管理是什么意思，也能学到不同算法的取舍，而不是只在更高层工作，让语言和环境替你处理许多细节，却不知道底下发生了什么。

所以我仍觉得，专注于基本概念、真正弄懂算法和机器怎样工作，然后据此推理和举一反三，是有价值的。我猜无论你从事哪个领域，掌握分布式系统或数据库等基础知识，都有助于在未来取得成功——即便绝大多数代码都由智能体编写，而你负责引导它们。

但我也不确定。智能体学习和发展的速度太快，我不知道两三年或四年后的世界会是什么样。我猜它会和今天大不相同。我们会经历一段很疯狂的时期。

**Ryan Peterman：** 太好了，非常感谢你今天抽时间来聊，Stephen。谢谢你。

**Stephen Toub：** 很荣幸。这次谈话很愉快，谢谢。

## [1:21:00] 片尾

<https://pod-exp.pages.dev/PLMOVlZC4eU/#chapter-28> · YouTube <https://www.youtube.com/watch?v=PLMOVlZC4eU&t=4860s>

**Ryan Peterman：** 谢谢你收看这期播客。如果你喜欢节目、希望节目继续发展，请点赞或留言。也欢迎留言推荐你希望我邀请的嘉宾。Barbara Liskov、Mike Stonebraker、Mark Brooker 都是有人留言推荐后，我邀请来的。

另外，除了播客，我还在做一款我一直希望存在的人体工学键盘。这是它的原型，是一款左右分体键盘。它已经在 Kickstarter 上发布，八小时内就达成了筹资目标。如果你是早期支持者、买了一台，我非常感谢。现在我们正在推进漫长的模具制作过程；如果你还想买，Kickstarter 上仍开放延迟认捐，可以去那里下单。我会把链接放在简介里。再次感谢你收看节目，我们下期再见。
