跳到正文
Hacker News· mfrw·· 19 天前精选AI 评分42

Rust 语言设计者撰文谈智能体编码对语言设计的双向影响

What agents mean for Rust (and vice versa)

AI 导读

babysteps 博客的 Rust 语言设计者发文论述 LLM 智能体编码对编程语言设计的影响,主张 Rust 应在 'if it compiles, it works' 方向上继续加码。

推荐理由

由 Rust 语言团队成员撰文,分析智能体编码普及后类型系统、unsafe 代码与形式化证明三者在语言设计中权重的变化。

正文 · AI 翻译
Sheldon breathing into a paper bag.
我,正在冷静地评估大语言模型对编程语言设计(者)的影响。

作为一个以编程语言设计为职业的人,我确实对大语言模型的崛起有过存在性的恐惧时刻。我在五年级时开始写代码,用的是一台 x861,它运行在 5MHz,拥有大约 5MB 硬盘和 512K 内存2。那时候的计算机真的、真的很不一样。但说实话,编程本身却没什么不同。尽管 IDE 和编程语言等都在不断进步,把代码输入文件这一基本动作却惊人地保持不变3——直到几年前,一切都几乎被彻底颠覆。这有时让人兴奋和充满力量4,但同时也让人害怕和不知所措。我的编程技能还会有价值吗?我在编程语言设计方面的能力(即便有限)呢?这篇博客文章就是我试图回答这些问题的一次尝试。

为了不让你一直悬着,我先给你结论。简而言之,是的,我相信人类在编程中仍将发挥作用。而且是的,我认为编程语言设计仍然有意义。当然,我自然也认为 Rust 对于代理式开发来说是一个非常合适的选择——但这并不是说我们不能让它变得更合适。这篇文章最终要讨论的就是:Rust 与代理式开发为何能很好地结合,以及我们可以在哪些方面进一步强化这些优势。

这是一篇类似"博客文章配套版"的文章,配套的是我本周在 REBASE(SPLASH 的一部分)上所做的演讲。你也许还会喜欢我之前在 IWACO 上所做演讲的幻灯片:IWACO 与 Rust:隐藏的关联浮出水面,那次更像是一次回顾(不过那次没有配乐)。总之,这是一次非常棒的会议!Jack Huey 做了关于 Rust Vision Doc 的报告,而令我相当意外的是,Steve Klabnik 和 Dorian Scheidt 做了题为《大语言模型作为语言规范与设计中的协作者》的报告,讲述了他们在构建 Rue 时的过程。再次见到 Steve 非常开心。除此之外,尤其是 IWACO 上还展示了大量很棒的研究成果。我尤其被关于可达性类型和信息借用的工作所吸引。我也很喜欢了解 Hylo 语言,尤其是他们对投影的处理方法。巧妙又有趣。

Rust 在代理式时代很流行

Meme dialogue: “I wrote this in Rust!” “Be honest.” “I am being honest!” “An agent wrote it.” “Thank you.”
来自 Amazon 最重要的 Slack 频道,#aws-memes。

Rust 现在很流行。非常流行:

在新兴语言中一飞冲天的是 TypeScript,它被从图表中裁出,目前相比上一年的增长率高达 +1200%。[..]

近期增速第二快的是 Rust。Meta 的工程师们今年到目前为止编写的第一方 Rust 代码量已经是过去 9 年总和的两倍。

— David Tolnay(粗体为我所加)

这其中一部分是因为代理让人很容易去尝试新事物。另一部分则是因为 Rust 以高性能著称——既然选用任何语言都一样方便,那为什么不选一个执行速度更快的呢?

但我认为 Rust 之所以流行还有另一个原因:因为 Rust 恰好非常适合 AI 代理编程6。当然,我会这么说,不是吗?这篇文章的目的就是(1)论证为什么会这样,然后(2)讨论我们可能需要对 Rust 做哪些改变以让它工作得更好。

使用 AI 代理进行的基础软件开发

在我看来,一个有效的“软件工厂”需要三大支柱:

  • 设计:弄清楚并明确说明代码应该做什么。
  • 构建:编写实现其应有功能的代码。
  • 优化:优化代码,使其高效运行。

这些支柱问题都还没有完全解决,但有些已经取得了更多进展。

Rust 与优化:默认就很快,需要时也有调节旋钮

Rust 的设计目标是提供“默认良好性能”,使得惯用写法通常也就是最快的写法。但 Rust 的另一个关键之处在于,当你需要时,你有调节旋钮来榨取更好的性能。你可以控制某个东西是栈分配还是堆分配,以及在何处发生指针间接访问。如果你愿意,可以强制让结构体按特定方式布局,或者决定在异步栈帧中何处引入装箱。在极限情况下,你甚至可以嵌入内联汇编。

过去,学习如何“调节性能旋钮”有点像一门玄学:但 AI 代理正在让这件事变得容易得多。7事实证明,AI 代理对现有代码的性能微调非常擅长。例如,从事超高性能加密算法工作的人过去都是通过手工调优汇编代码来完成的。但他们告诉我,他们现在正转向让 AI 代理来完成同样的工作。更常见的是,许多构建网络服务的人发现,使用像 dial9 这样的性能分析工具,AI 代理能相当有效地诊断异步性能陷阱,比如长时间轮询或阻塞。

因此,我认为 Rust 的任务很明确。我们继续朝着 “低到内核,高到 GUI” 的目标前进。如果说有什么变化的话,我认为围绕 AI 代理的转变意味着我们可以容忍更多一些“噪音”,即对 clone() 或 share() 的显式调用——但不能太多,因为我们仍然希望代码的“正常路径”清晰可见8,即便我们暴露出在特定场景中很重要的细节(比如精确跟踪你有多少个通道端点的克隆)。再结合性能分析工具,你就获得了一个让代码快速运行的有效反馈循环:

flowchart LR
    Code -- Benchmark --> Profile
    Profile -- Analyzed by --> Agent
    Agent -- Propose --> PR
    PR -- Improve --> Code
  

可靠性始终为王

然而,一如既往,虽然良好性能的口碑是把人们带到 Rust 的原因,但让他们想要留下来的,则是一种使用 Rust “似乎就是工作得更好”的感觉。基本理论是,Rust 的类型系统和安全护栏有助于让 AI 代理保持在正轨上:

rust 是 AI 代理的完美语言,因为如果它能编译通过,那它就基本是正确的

— Greg Brockman (@gdb) January 2, 2026

我认为这话有道理:Rust、Ocaml、Haskell 这样的语言都共有这种“如果能编译,就能工作”的感觉,我认为 AI 代理将从中受益。

只有测试是不够的,类型系统能帮上忙

测试能证明 bug 的存在,但不能证明它们不存在。

—— Edsger W. Dijkstra,1970

A woman presents a lopsided cake with the words “Nailed it!”
AI 代理展示它们的工作成果。

写测试从来不足以证明你的程序是正确的——但有了 agent 之后,更是远远不够。这种情况太常见了:我最初几个测试看起来都很正常,结果下一个就彻底跑偏了。通常偏得很离谱,让我完全无法想象那个 bug 是怎么冒出来的。然后我深入排查,才发现 agent 完全没领会我想表达的那套逻辑。9

这正是类型系统真正闪光的地方——尤其是像 Rust 这样先进的类型系统。类型系统提供了一些护栏,能让 agent 沿着正轨走。在 Rust 里,这些护栏不仅覆盖了“所有字段名字是否正确”这类简单的内容,还延伸到永远不必关闭 socket这类事情上。

类型系统同样也不够用

类型系统能证明 bug 的不存在,但不能证明正确性的存在。

——本人,没能造出一句同样精炼的话,202610

所以说,类型系统确实有帮助!但它们有天然的局限。类型系统是一套简单的规则,只要你遵守它们,就能确保你避免(某些类型的)错误。但它们并不能告诉你你做了正确的事——只能告诉你你没有做(某些类型的)错误的事。如果你想更进一步,就需要证明系统——一种能让你证明更丰富的属性确实为真、而不仅仅是在避免错误的工具。

事实上,Rust 有很多有趣的证明工具,比如 Verus、Creusot、Aeneas 和 Kani。作为起点,你可以证明你的代码是 panic-free 的,这能消除很多 bug,尽管它在本质上仍是一种“类类型检查器”的属性(也就是你在避免做错事)。但你还可以更进一步,添加断言来证明你的代码确实在按你期望的方式进行计算。

强护栏带来更好的性能

部署证明不仅有助于让代码正确——也有助于让代码更快。这有点反直觉,但确实是真的。之前我提到过,优化过的加密算法现在正由 agents 来编写。能做到这点的原因之一是加密算法有着非常清晰的数学定义。这意味着你基本上可以告诉 agent “你想怎么做都行,只要你能证明代码仍然计算出正确的结果”。这些证明可以用 Lean 或 Rocq 这类定理证明器来完成。博客文章 《Why Lean is faster than Rust》 把这一点讲得相当到位。

对 Rust 来说,一个很好的例子就围绕 unsafe 代码展开。目前,人们有时不愿意部署 unsafe 代码,即使它可能让代码更快,因为承担不了出错的代价。我对这种谨慎态度表示赞赏。但如果你能用 prover 来证明你的 unsafe 代码事实上是安全的(即不可能引发未定义行为),那你不就可以随心所欲地去优化了吗。

如果我们要证明各种性质,还需要类型系统吗?

你可能会想:如果我们在代码上部署证明系统,还需要类型系统吗?我认为答案绝对是肯定的。类型系统使用起来要简单得多,这也是它更受欢迎的原因。使用类型系统可以排除各种烦人的 bug,这样你就可以把"证明精力"集中在重要的事情上。

作为一个简单的例子,请看下面的 Java 代码:

void setFoo(Bar bar) {
    this.foo = bar;
    assert this.foo == bar;
}

在没有看到更多代码的情况下,无法证明这个断言是否为真!这是因为可能有任意数量的其他线程在运行并修改 this。相比之下,下面的 Rust 代码一定为真(至少,只要 Eq 运算符对 Bar 是自反的):

fn set_foo(&mut self, bar: Bar) {
    self.foo = bar;
    assert_eq!(self.foo, bar);
}

我们知道这一点是因为 Rust 的类型系统保证了 &mut self 意味着一个唯一的引用。

这实际上正是 Verus 的工作原理。通过信任 Rust 的借用检查器来跟踪唯一性等,它简化了 SMT 求解器的工作,使证明检查比原本快得多且更可靠。

我认为 Rust 在可靠性方面应该走向何方

所以我的观点是,Rust 应该加倍努力实现能编译就能运行。尽管 Rust 的类型系统表达能力很强,但仍有许多它无法捕捉的东西。这包括相当常见的情况,比如此方法仅读取某一个特定字段或内部引用,也包括一些精细的东西,比如"不记录个人身份信息"。我们应该努力突破这些限制,让智能体有空间证明更复杂的属性。

我们还需要通过打造可扩展的编译器来改善集成证明工具的体验。虽然现有的基于 Rust 的证明工具很酷,但使用它们是一种糟糕的体验,涉及到烦人的宏和固定的编译器版本。我们可以做得更好。

一个北极星目标:不再有 unsafe 代码

我想为 Rust 提出一个北极星目标:不再有 unsafe 代码。这并不意味着我们从不使用 unsafe 关键字。相反,我的意思是,我们有能力证明我们编写的所有 unsafe 代码都是正确的,并且不会导致未定义行为。不要误解我的意思:准确知道哪些代码需要审查是一个巨大的进步,将库需要通过安全的 API 边界11保护其用户免受未定义行为侵害的理念规范化也是如此。但鉴于智能体发现漏洞的能力,我认为如果我们想阻止源源不断的 CVE,就需要提升我们的水平。12

设计是一个开放问题

但在开始证明或优化事物之前,你需要清楚地知道自己正在构建什么。据我所知,这里最先进的方法基本上是"Markdown 驱动开发"的各种变体,即开发文档并希望智能体会关注。

我不知道 Rust 在这个领域能发挥多大作用。我认为我们可能会采取一些有帮助的措施——例如,设法将接口与实现分开,以便更容易单独审查接口,或者更容易看到智能体何时在那里做了更改。13 或者只是提供更好的工具来审查。

我也认为,“建模语言”这种思路有其发展空间——它能让你与智能体一起,快速迭代高层设计与不变量,而无需深入细节、逐行阅读代码。关于这点我还有很多想法,单独再写几篇博客都值得。不过眼下,先请大家读读 Kari Wilhelm 这篇《锚定工程的原则》。我觉得它很好地描述了如何提炼出设计中的关键要素,并以此驱动编码。

总结

这次我们聊了很多内容,让我把它们串起来:为什么 Rust 是与智能体协作开发的好选择?

  • 它默认就有不错的性能(何必多花成本呢?),再结合性能分析器,可以按需任意调优。
  • 类型系统提供了更强的护栏;只要把智能体设置得当,你还能借助 newtype 之类的技术进一步加固这些护栏。

那么,从语言设计的角度来看,什么能让它变得更好?总体上我认为与我们此前的方向非常相似,只是为了适应“代码由智能体编写、人类更关注代码理解”这一新范式,对各取舍项的权衡需要微调:

  • If it compiles, it works – our type system is our big advantage, we need to make it more expressive and more functional so that agents don’t get stuck trying to work around it!
    • 作为补充,确立一个北极星:通过支持形式化证明来实现没有不安全性的不安全代码,并最终让最广泛使用的 Rust 库都被证明其正确性。
  • 底层足以写内核,高层足以写 GUI——既要暴露足够的旋钮以便按需调优性能,又要让代码的意图清晰可读(但不必把代码精简到极致)。
  • 可扩展、多用途——Rust 的一个重要长处在于,借助宏加上我们的类型系统,它能支持 DSL 以及各种各样的目标平台。我们需要把这种可扩展的精神带入编译器本身,从而可以面向更多开发场景(例如 GPU、深度语言互操作等),并集成定理证明器和其他需要远超词法层面支持的工具。

最后,我想把 Marc Brooker 这篇耐人寻味的文章推荐给你:《如今什么是简单的?什么是困难的?》。他认为:越是能为一项任务清晰指定成功标准,这项任务就越容易;由此我们可能发现,一些传统意义上被视为“困难”的任务(例如为一个密码学算法构建高效实现)也许很快就会被自动化,而另一些我们一直认为“简单”的任务(例如打造一个独特而打动人心的网站)反而会变得更有价值。

从程序语言设计的视角来看,我认为 Marc 的观点印证了我的一种直觉:真正的变革很可能来自设计语言——它能让人在极高的层次上捕捉架构和预期行为。目标是要让人类能够直观地描述一个设计,并被翻译成有效的护栏——无论是类型系统检查、lint,还是要证明的定理。智能体则负责把这个设计翻译成用 Rust 这样的传统程序语言写出的代码,而人类只需偶尔过目即可。这并不会让传统程序语言的设计变得无趣,只是让其中的权衡取舍与从前大不相同。


  1. 说真的,我一直很羡慕那些用打孔卡编程、把东西存在巨大的磁带卷上之类的老派程序员。我太想变得看破红尘、世故老练了!我很开心,自己终于老到可以说出「我记得以前我们玩电脑游戏之前,得先编辑 CONFIG.SYS!」之类的话,然后让年轻程序员们惊恐地倒吸一口凉气。5 但我仍然觉得,在那些「当年」过来人眼里,我听起来一定还像个傻孩子。 ↩︎

  2. 我还记得我爸告诉我他给我买了一个 10MB 的硬盘,其实他偷偷给我买了一个 40MB 的硬盘想给我一个惊喜。那时候感觉大得离谱。「我再也不需要新硬盘了!」 ↩︎

  3. 我的天哪,我们居然又开始用 vi 了!我的第一个编辑器! ↩︎

  4. 我做了一个 Electron 应用!而且做起来超轻松!阅读那些奇怪的论文和各种资料也方便多了,现在我可以叫 LLM 把那些数学术语都翻译给我听。 ↩︎

  5. 我记得有一次我跟 Alex Crichton 讲述我当年怎么「通过纸质目录邮购共享软件,往信封里塞一张支票寄出去」的事,他听完说「你这句话里的名词我一个都听不懂」。这是我人生中的高光时刻,仅次于 Rust 1.0 发布。哦,还有我孩子的出生和结婚吧。我想应该是。 ↩︎

  6. 我并不是说 Rust 是唯一合适的语言。我甚至不是说 Rust 这种合适的方式是唯一合适的途径。比如我就听说 Go 非常适合智能体编程,我信这个说法:我觉得它命中了另一个甜蜜点,一个能让智能体快速迭代的点(不过我确实怀疑智能体会让数据竞争和那些 Rust 能避免的细微 Bug 溜过去)。 ↩︎

  7. 智能体开发能让调优旋钮有更多发挥空间,这对 Rust 的性能来说是好事,但对其他语言来说很可能更合适。调优 GC 历来是个真正需要 GC 专家才能干好的活儿,但如今智能体大概也能挺不错地胜任这个角色了。 ↩︎

  8. 说到这一点,我更加确信人体工学 RC 的重要性了,尤其是现在我跟智能体一起协作之后。智能体倒是擅长在异步任务里加那些必要的 clone 之类的操作来处理捕获问题,但搞出来的代码读起来太烦人了,真的把逻辑都掩盖了。 ↩︎

  9. 「Claude,这跟我跟你说的不一样啊!」——我,太频繁了。 ↩︎

  10. 就差那么一点点,对吧?我就是……没能把飞机降下来。 ↩︎

  11. C++ 库常常觉得告诉用户 「是你用法不对」 就够了——也就是说,它们认为是用户自己误用 API 才导致了未定义行为。Rust 则立场鲜明:一个安全的 API 必须保护自己的用户,不管用户怎么乱用它。 ↩︎

  12. 说句公道话,如果 Rust 正在遭遇一波 CVE 的攻击,那 C++ 和 Java 这些语言简直就是洪水滔天了,因为它们没有 Rust 类型系统的那层保护。 st 明确地认为一个安全的 API 必须保护自己的用户,不管用户怎么乱用它。 ↩︎

  13. .h 文件的复仇? ↩︎

来源:Hacker News · smallcultfollowing.com