商业产业 Hacker News Agent 2026-10-14T08:49 正文 ok 2836 words

Agent 对 Rust 意味着什么,Rust 又能为 Agent 带来什么

英文标题:🔶 What agents mean for Rust (and vice versa)

作者认为,尽管 LLM 正在改变编程方式,人类编程和编程语言设计仍有用武之地,而 Rust 的性能与可靠性特征尤其适合 Agent 开发。David Tolnay 称,Meta 工程师今年迄今编写的第一方 Rust 代码量,已达到此前九年总和的两倍。作者指出,Agent 可以借助性能分析工具优化 Rust 代码,但测试和类型系统各有局限,需要结合形式化证明来验证更复杂的正确性属性。对于 Rust 社区,作者建议增强类型系统和编译器的可扩展性,并以证明所有 unsafe 代码安全为长期目标。
打开原文相关 3 · 机会 1
media354.9 KB media1.3 MB media2.4 MB

中文

谢尔顿对着纸袋呼吸。这是我在冷静评估 LLM 对编程语言设计(及设计者)的影响。

作为一个以编程语言设计为业的人,面对 LLM 的兴起,我确实会时不时产生存在主义式的恐惧。我从小学五年级开始写代码,当时用的是一台运行频率为 5MHz 的 x86 电脑,硬盘大约只有 5MB,内存为 512K。那时的电脑和现在真的非常、非常不同。但说实话,编程却没有那么不同。尽管 IDE、编程语言等都取得了进步,把代码输入文件这一基本行为却一直出奇地稳定——直到几年前,一切突然发生了颠覆。这有时令人兴奋、让人获得新的能力,但也让人恐惧和迷茫。*我的编程技能还重要吗?我的编程语言设计技能(姑且算有的话)又会如何?*这篇博客是我试图回答这些问题的努力。

为了不让大家久等,我先说结论。简而言之,是的,我相信人类在编程中仍有一席之地。而且,是的,我认为编程语言设计仍然重要。当然,我也恰好认为 Rust 非常适合 Agent 开发——但这并不意味着我们不能让它更适合。这正是本文最终想讨论的:Rust 与 Agent 开发为何能够很好地配合,以及我们可以在哪些方面进一步强化这些优势。

这篇文章可以看作是我本周在 SPLASH 旗下 REBASE 会议上所作演讲的博客配套版。你可能也会喜欢我在 IWACO 演讲的幻灯片:《IWACO 与 Rust:隐藏关联揭秘》,那场演讲更偏向回顾(不过幻灯片没有配乐)。总之,这是一场很棒的会议!Jack Huey 介绍了 Rust 愿景文档;令我颇感意外的是,Steve Klabnik 和 Dorian Scheidt 也带来了《LLM 作为语言规范与设计的协作者》,讲述他们构建 Rue 的过程。再次见到 Steve 很开心。此外,尤其是在 IWACO 上,还有大量精彩的研究。我对可达性类型(Reachability Types)和信息借用(Information Borrowing)的研究印象特别深刻。我也很喜欢了解到的 Hylo Lang,特别是它处理投影的方式。既巧妙又酷。

Rust 在 Agent 时代很受欢迎

梗图对话:“我用 Rust 写了这个!”“说实话。”“我说的就是实话!”“是 Agent 写的。”“谢谢。”来自亚马逊最重要的 Slack 频道:#aws-memes。

Rust 现在很受欢迎。非常受欢迎:

在这些快速崛起的语言中,TypeScript 的增长堪称一飞冲天,因而被裁出了图表;目前它较上一年增长了 1200%。[…]

近期增长速度排名第二的是 Rust。Meta 工程师今年迄今编写的第一方 Rust 代码量,是此前九年总和的两倍。

——David Tolnay(加粗为作者所加)

部分原因是 Agent 让尝试新事物变得非常容易。另一个原因是 Rust 以高性能著称:如果选择任何一种语言都同样容易,为什么不选一种能让程序运行得更快的语言呢?

**但我认为 Rust 受欢迎还有另一个原因:它恰好非常适合 Agent 编程。**当然,我会这么想,不是吗?本文的目的,一是论证为什么如此,二是讨论我们可以对 Rust 做哪些改进,让它发挥得更好。

使用 Agent 构建基础软件

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

  • *设计:*弄清楚并明确规定代码应该做什么。
  • *构建:*编写完成预定任务的代码。
  • *优化:*优化代码,使其高效运行。

这三方面都还没有得到彻底解决,但有些方面的进展比另一些更大。

Rust 与优化:默认快速,需要时也有调优手段

Rust 的设计目标是提供“默认的良好性能”,让符合惯用写法的代码通常也是最快的代码。但 Rust 的另一个关键特点是,你可以在需要时通过各种调节手段进一步挤出性能。你可以控制何时在栈上或堆上分配内存,以及在何处进行指针间接访问。如果愿意,你可以强制指定结构体的布局方式,或决定在异步栈帧的哪些位置引入装箱。极端情况下,你还可以嵌入内联汇编。

过去,学习如何“调节性能旋钮”多少有点像一门秘术;但 Agent 正在让这件事容易得多。事实证明,Agent 非常擅长对现有代码进行性能微调。例如,从事超高性能密码算法开发的人过去会手工调优汇编代码,但他们告诉我,现在他们正转而用 Agent 完成同样的工作。更常见的例子是,许多构建网络服务的人发现,借助 dial9 这样的性能分析器,Agent 可以相当有效地诊断异步性能陷阱,例如耗时过长的轮询或阻塞。

因此,我认为 Rust 的任务很明确:继续追求“足够底层,能写内核;足够高层,能写 GUI”的目标。如果要说有什么变化,我认为 Agent 带来的转变意味着,我们可以多容忍一点显式调用 clone() 或 share() 所产生的“噪声”——但也不能太多,因为我们仍希望代码的“正常路径”清晰明了,同时呈现特定场景下重要的细节,例如精确追踪通道端点有多少个克隆。配合性能分析器,你就能形成一个有效的反馈循环,让代码运行得更快:

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

一如既往,可靠性至上

不过,和往常一样,虽然良好性能的声誉吸引人们来到 Rust,让他们想要留下的却是使用 Rust“似乎就是更可靠”的感觉。其基本观点是,Rust 的类型系统和保护机制有助于让 Agent 沿着正确的轨道前进:

我认为这有一定道理:Rust、OCaml 或 Haskell 这样的语言都有一种“只要能编译,就能正常工作”的感觉,我认为 Agent 会从中受益。

仅靠测试不够,类型系统能提供帮助

测试可以表明错误的存在,但不能表明错误不存在。

——Edsger W. Dijkstra,1970 年

一名女子展示一个歪歪扭扭的蛋糕,画面上写着“完美搞定!”。Agent 展示自己的工作成果。

编写测试从来不足以证明程序正确;而在使用 Agent 时,测试的作用离证明正确性更是差得远。我经常遇到这样的情况:最初几个测试看起来很棒,接下来一个却彻底出了岔子。通常这种错误离谱到让我根本想象不出它是怎么产生的。然后我深入调查,才发现 Agent 完全没理解我想表达的逻辑。

这正是类型系统大显身手的地方,尤其是 Rust 这样先进的类型系统。类型系统提供了一些保护机制,让 Agent 不至于偏离轨道。在 Rust 中,这些保护机制超越了“所有字段的名称是否正确”之类的简单检查,还涵盖了不必手动关闭 socket等事项。

类型系统也不够

类型系统可以表明错误不存在,但不能表明正确性的存在。

——我,2026 年,试图造出一句同样精妙的格言,但失败了

所以,没错,类型系统很有帮助!但它们也有固有的局限。类型系统是一套简单的规则:如果遵守它们,就能确保避开某些类型的错误。但它们不能告诉你是否做了正确的事——只能告诉你没有做某些类型的错事。如果想更进一步,就需要证明系统:它能让你证明更丰富的性质确实成立,而不仅仅是证明你避开了错误。

恰好,Rust 有很多有趣的证明工具,例如 Verus、Creusot、Aeneas 和 Kani。作为起点,你可以证明代码不会发生 panic,从而消除许多错误,尽管这从根本上说仍是一种“类似类型检查器”的性质,即避免做错事。但你也可以更进一步,加入断言,证明代码确实计算出了预期结果。

更强的保护机制带来更好的性能

使用证明不仅有助于让代码正确,还有助于让代码快速。这多少有些违反直觉,但确实如此。前面我提到过,现在优化过的密码算法正由 Agent 编写。之所以能够做到这一点,部分原因是密码算法有非常清晰的数学定义。这意味着你基本上可以告诉 Agent:“你想怎么做都行,只要能证明代码仍然计算出正确结果。”这些证明可以用 Lean 或 Rocq 等定理证明器完成。博客文章《为什么 Lean 比 Rust 快》很好地阐述了这一点。

对 Rust 来说,一个很好的例子是 unsafe 代码。目前,即使 unsafe 代码可能让程序更快,人们有时仍不愿采用它,因为出错的风险不值得承担。我赞赏这种谨慎。但如果你能用证明器证明 unsafe 代码实际上是安全的,也就是说不可能导致未定义行为呢?那么你就可以尽情优化了。

如果要进行证明,我们还需要类型系统吗?

你可能会问:如果我们要对代码使用证明系统,还需要类型系统吗?我认为答案肯定是需要。类型系统使用起来简单得多,这也是它们更受欢迎的原因。使用类型系统可以排除各种恼人的错误,让你能够只把“证明精力”集中在重要的事情上。

举一个简单的例子,看看下面的 Java 代码:

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

如果看不到更多代码,就无法证明这个断言是否为真!这是因为可能有任意数量的其他线程正在修改 this。相比之下,下面 Rust 代码中的断言必然为真——至少,只要 Bar 的 Eq 运算符具有自反性:

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

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

这实际上正是 Verus 的工作方式。它信任 Rust 的借用检查器来跟踪唯一性等属性,从而简化 SMT 求解器的工作,使证明检查比否则可能达到的水平快得多,也可靠得多。

我认为 Rust 应如何提升可靠性

因此,我的看法是,Rust 应该进一步强化“只要能编译,就能正常工作”。尽管 Rust 的类型系统表现力很强,仍有大量它无法表达的东西。这既包括相当常见的情况,例如某个方法只读取一个特定字段或内部引用,也包括“不得记录可识别个人身份的信息”这样的高级要求。我们应该努力突破这些限制,为 Agent 证明更复杂的性质提供空间。

我们还需要朝着可扩展编译器的方向努力,改善集成证明工具的体验。现有的 Rust 证明工具固然很酷,但使用体验还不够顺畅,需要处理恼人的宏和固定版本的编译器。我们可以做得更好。

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

我想为 Rust 提出一个北极星目标:不再有不安全代码。我的意思并不是永远不再使用 unsafe 关键字,而是我们有能力证明自己编写的所有 unsafe 代码都是正确的,不会导致未定义行为。不要误解我的意思:确切知道哪些代码需要审查,已经是巨大的进步;让库通过安全的 API 边界保护用户免受未定义行为影响,并使之成为共识,同样是巨大的进步。但鉴于 Agent 能够发现漏洞,如果我们想阻止源源不断出现的 CVE,我认为就必须提高标准。

设计仍是一个尚未解决的问题

但在着手证明或优化之前,你需要有一个清晰的……

(原文在此处截断。)

English / 原文

Sheldon breathing into a paper bag.Me, calmly assessing the implications of LLMs for programming language design(ers).

As someone who has made a career of programming language design, I definitely have moments of existential dread about the rise of LLMs. I started coding in 5th grade on an x86 that ran at 5MHz, had something like a 5MB hard-disk and 512K of RAM. Computers were really, really different back then. But honestly, programming wasn’t. For all the advances in IDEs and programming languages and so forth, the basic act of entering code into a file has remained surprisingly constant – right up until a few years ago, when everything kinda turned on its head. That’s been exciting and empowering at times but also scary and disorienting. Will my skills in programming matter? What about my skills in programming languagedesign (such as they are)? This blog post is my attempt to answer those questions.

So as not to keep you in suspense, let me just give you the conclusion. In short, yes, I believe there will still be a role for humans in programming. And yes, I think that programming language design is still relevant. And, naturally, I also happen to think Rust is a really good fit for agentic development – but that’s not to say we can’t make it a better fit. And that’s what this post is ultimately about: what makes Rust and agentic development work well, and where we could double down on those strengths.

This is a kind of “blog post companion version” of atalk I gave this week at REBASE, part of SPLASH. You might also enjoy the slides from the talk I gave at IWACO, IWACO and Rust: hidden links revealed, which was a bit more of a retrospective (no soundtrack for those, though). In any case, this turned out to be a great conference! Jack Huey presented on the Rust Vision Doc and, quite to my surprise, Steve Klabnik and Dorian Scheidt presented “LLMs as Collaborators in Language Specification and Design”, talking about their process in building out Rue. It was fun to see Steve again. On top of that, there was a ton of great research presented at IWACO in particular. I was particularly taken by the work on Reachability Types and Information Borrowing. I also really liked learning about Hylo Lang, particularly their approach to projections. Clever and cool.

Rust is popular in the agentic era

Meme dialogue: “I wrote this in Rust!” “Be honest.” “I am being honest!” “An agent wrote it.” “Thank you.”From the most important Slack channel at Amazon, #aws-memes.

Rust is popular right now. Very popular:

Stratospheric among the breakout languages is TypeScript, cropped from the chart and sitting currently at +1200% growth from the prior year. [..]

The second most rapid recent growth is in Rust. Meta engineers have written twice as much first-party Rust code so far this year than in the previous 9 years combined.

— David Tolnay (emphasis mine)

Some of that is because agents make it very easy to try out new things. And some of that is because Rust has a reputation for being performant and, if it’s just as easy to pick any language, why not pick one that will yield faster execution times?

But I think Rust is popular for another reason: because Rust happens to be a really good fit for agentic coding. Of course, I would, wouldn’t I? The point of this post is (1) to argue for why that is and then (2) to discuss what we might change about Rust to make it work even better.

Foundational Software construction with agents

It seems to me that an effective “software factory” will have three pillars:

  • Design: figure out and specify clearly what the code is supposed to do.
  • Construction: author code that does what it is supposed to do.
  • Optimization: optimize the code so that it runs efficiently.

None of these pillars are solved, but some have made more progress than others.

Rust and optimization: fast by default, knobs when you need ’em

Rust is designed to give “good performance by default”, making the idiomatic thing typically also be the fastest thing. But another key part of Rust is that you have the knobs to eke out better performance when you need it. You control when something is stack- or heap-allocated and where pointer indirection occurs. If you want to, you can force the layout of your structs to be done in a particular way, or decide where to introduce boxing into your async stack frames. In the limit, you can put in inline assembly.

In the past, learning how to “tune the performance knobs” could be a bit of a black art: but agents are making that much easier. It turns out that agents are really good at fine-tuning the performance of existing code. For example, people who work on super high-performance cryptographic algorithms used to do so by hand-tuning assembly code. But those people tell me that they are now turning to agents for that same job. More prosaicly, a lot of people building network services are finding that, using a profiler like dial9, agents can quite effectively diagnose async performance pitfalls, like long polls or blocking.

Therefore, I think the task for Rust is clear. We keep on with our goal of “low-level enough for a kernel, high level enough for a GUI”. If anything, I think the shift around agents means we can tolerate a bit more “noise” in the form of explicit calls to clone() or share() – but not too much, since we still want the “happy path” of the code to be clear and evident, even as we surface details that are important in specific scenarios (like tracking precisely how many clones you have of a channel endpoint). Combined with a profiler, you get an effective feedback loop to get your code running fast:

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

Reliability is king, as always

As usual though, while a reputation for good performance is what brings people to Rust, what makes them want to stay is a sense that using Rust “just seems to work better”. The basic theory is that Rust’s type system and guardrails help keep agents on track:

I think there’s truth in that: languages like Rust, Ocaml, or Haskell all share this “if it compiles, it works” feeling, and I think that agents will benefit from that.

Testing is not enough, type systems help

Testing can show the presence of bugs, but not their absence.

— Edsger W. Dijkstra, 1970

A woman presents a lopsided cake with the words “Nailed it!”Agents presenting their work.

Writing tests has never been enough to show that your program is correct – but, with agents, it’s not even close. It happens so often that my first few tests seem great and then the next one goes completely bonkers. Usually bonkers in a way where I cannot even imagine how that bug could have come about. Then I dig in and I realize the agent completely missed the boat on the logic I was trying to express.

This is where a type systems really shines – particularly an advanced one like Rust. Type systems give you some guardrails that keep the agent on track. In Rust, those guardrails extend beyond simple stuff like “do all fields have the correct names” and to stuff like never having to close a socket.

Type systems are not enough either

Type systems can show the absence of bugs, but not the presence of correctness.

— Me, failing to coin a phrase of equal eloquence, 2026

So yeah, type systems are helpful! But they have inherent limits. A type system is a simple set of rules that, if you follow them, make sure that you avoid (certain kinds of) mistakes. But they don’t tell you that you do the right thing – only that you don’t do (certain kinds of) wrong things. If you want to go further, you need a proof system – something that will let you show that richer properties are actively true, not just that you’re avoiding bugs.

As it happens, there are a lot of interesting proof tools for Rust, like Verus, Creusot, Aeneas, and Kani. As a starting point, you can prove that your code is panic-free, which will eliminate a lot of bugs, though it is still fundamentally a “type-checker-like” property (i.e., you avoid doing things wrong). But you can also go further and add assertions that show your code is computing the results you expect.

Strong guardrails give better performance

Deplying proofs is not just good for getting code right – it’s good for getting code fast. This is somewhat counterintuitive, but it’s true. Earlier I mentioned how optimized cryptographic algorithms were now being written by agents. Part of what makes that possible is that cryptographic algorithms have a very clear mathematical definition. This means that you can basically tell the agent “do whatever you want, as long as you can prove that the code still computes the correct result”. These proofs can be done with theorem provers like Lean or Rocq. The blog post “Why Lean is faster than Rust” makes the point quite well.

For Rust, a good example of this would be around unsafe code. Right now, people are sometimes reluctant to deploy unsafe code even if it might make their code faster because it’s not worth the risk of getting it wrong. And I applaud that effort. But what if you could use a prover to show that your unsafe code is, in fact, safe (i.e., incapable of causing undefined behavior)? Then you’d be free to optimize to your heart’s content.

If we are going to prove things, do we need type systems?

You might wonder: if we’re deploying a proof system on our code, do we still need type systems? I think the answer is definitely yes. Type systems are infinitely simpler to work with, which is why they are much more popular. Using a type system lets you rule out all kinds of annoying bugs so that you can focus your “proof energy” only on the important stuff.

As a simple example of this, consider the following Java code:

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

Without seeing more code, it is impossible to prove whether this assertion is true or not! This is because there could be any number of other threads running around mutating this. In contrast, the following Rust code must be true (at least, so long as the Eq operator is reflexive for Bar):

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

We know this because the type system of Rust guarantees that &mut self implies a unique reference.

This is in fact exactly how Verus works. By trusting the Rust borrow checker to track uniqueness etc, it simplifies the job of the SMT solver, making proof checking must faster and more reliable than it would be otherwise.

Where I think Rust should go on reliability

So my take is that Rust should double down on if it compiles, it works. As expressive as Rust’s type system is, there are plenty of things that it cannot capture. This includes fairly common things, like this method only reads one particular field or internal references, but also fancy things like “no logging of personally identifiable information”. We should work to lift those limits, giving agents room to prove more complex properties.

We also need to improve the experience of integrating a proof tool by working towards an extensible compiler. As cool as the existing Rust-based proof tools are, using them is a janky experience involing annoying macros and pinned compiler versions. We can do better.

A north star: No more unsafe code

I’d like to propose a north star for Rust: no more unsafe code. By that, I don’t mean that we never use the unsafe keyword. Rather, I mean that we have the power to prove that all the unsafe code we write is correct and cannot cause undefined behavior. Don’t get me wrong: knowing exactly what code needs to be vetted is a huge step forward, as is normalizing the idea that libraries need to be responsible for protecting their users from undefined behavior via safe API boundaries. But given agents’ ability to find vulnerabilities, I think we need to up-our-game if we want to stop the steady stream of CVEs.

Design is an open problem

But before you go about proving things or optimizing them, you need to have a clear idea of what you are building. As far as I can tell the state of the art here is basically variations on “markdown-driven-development”, developing docs and hoping that agents pay attention.

I don’t know how much of a role for Rust there is in this space. I think there are some steps we might wind up taking that could be helpful here – for example, having ways to separate out interface from implementation so that it’s easier to review the interface in isolation or to see when the agent made changes there. Or perhaps just providing betters tools to review that.

I also think there’s space for dedicated “modeling languages”, something that let you iterate quickly with agents on the high-level designs and invariants without having to get into the weeds and read the code. I have more thoughts on this but it merits many blog posts all of its own. For the moment, I’ll settle for pointing you all at this post by Kari Wilhelm, “Principles of Anchor Engineering”, which I think does a nice job of describing what it means to pull out the key elements of a design and drive the coding from there.

Conclusion

We covered a lot of ground here, so let me put this all together. What makes Rust a good choice for developing with agents?

  • It offers good default perf (why pay more?) and, in conjunction with a profiler, can be tuned as much as you want.
  • The type system gives stronger guardrails, and if you setup your agents right, you can strengthen those guardrails through techniques like new types.

And what could make it better, from a language design perspective? Overall, I think it’s very similar to what we were doing, except that the way we weight the tradeoffs is tweaked to account for agents doing the code authoring, and humans focused more on code comprehension:

  • 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!
    • And as an adjunct, establish a North Star: Enable Unsafe code without unsafety by supporting proof, and see the most widely used Rust libraries proven sound.
  • Low-level enough for a kernel, high-level enough for a GUI – make sure we expose the knobs needed to tune for performance, while also making the code’s intent clear (but don’t worry about golfing the code down to an absolute minimum number of characters).
  • Extensible and versatile – one of Rust’s great strengths is that, with macros + our type system, we support DSLs and a wide variety of targets. We need to bring that spirit of extensibility into the compiler so we can target more styles of development (e.g., GPU, deep language interop, etc) and also integrate theorem provers and other tools that require more than just tokens.

As a final close, let me point you at this interesting article by Marc Brooker, “What’s easy now? What’s hard now?”. He posits that the more it is possible to clearly specify success criteria for a task, the easier it is, and that we may find that tasks we traditionally think of as ‘hard’ (e.g., building out an efficient implementation of a cryptographic algorithm) may soon become automated, whereas tasks that we have thoght of as ’easy’ (e.g., making a unique, compelling website) may become more valued.

Looking at it from a PL point-of-view, I think Marc’s point reinforces my sense that the biggest action is going to come from design languages , things that let you capture the architecture and intended behavior at a very high-level. The goal would be to let humans intuitively specify a design that gets translated into effective guardrails, whether that’s type system checks, lints, or theorems to be proven. Agents would then take on the task of translating the design into code written in a traditional PL like Rust, with humans looking at it only rarely. This doesn’t make the design of traditional PLs less interesting, but it definitely makes the tradeoffs very different than they were before.