搜 索

AI时代为什么我们需要Rust

  • 2阅读
  • 2026年06月13日
  • 0评论
首页 / 编程 / 正文

〇、先承认一个尴尬的事实

两年前我对 Rust 的态度是:一门为了让你在编译期就崩溃、从而避免你在运行期崩溃的语言。学了三天,写了个 CLI,被 borrow checker 教育了十七次,默默关掉了编辑器——典型的"从入门到放弃"。

今年我改主意了。不是因为 Rust 变简单了(它没有),而是因为我写代码的方式变了

现在我一天能让 AI 生成两千行代码,但我一天最多认真 review 两百行。剩下的一千八百行,谁来把关?

这篇文章想聊的就是:当代码的生产成本趋近于零时,代码的验证成本就变成了唯一的瓶颈。而 Rust,恰好是目前把"验证"这件事外包给机器做得最彻底的主流语言。


一、瓶颈转移:从"写不出来"到"不敢合并"

传统开发的时间分布是这样的:想清楚 → 写出来 → 调通 → 上线。写代码本身占大头。

AI 辅助开发之后,这条曲线被压扁了,但压扁的只有中间那一段:

flowchart LR subgraph A["传统开发"] A1["设计"] --> A2["手写代码
慢"] --> A3["调试"] --> A4["Review
人看人写的"] --> A5["上线"] end subgraph B["AI 辅助开发"] B1["设计"] --> B2["生成代码
快到离谱"] --> B3["验证
新瓶颈"] --> B4["Review
人看机器写的"] --> B5["上线"] end B3 -.->|"看不完 / 看不懂 / 不敢改"| B3

问题在于,人类 review 机器代码,和人类 review 人类代码,认知负担完全不同。

同事写的代码,你知道他的习惯、他的思路、他昨天踩过什么坑,你能"猜"到哪里危险。AI 写的代码,平均质量往往不差,语法漂亮、命名规范、注释齐全——但它出错的地方是随机的,而且常常出在"看起来非常正常"的地方。

我在支付系统里遇到过最惊悚的一类:AI 生成的并发代码,逻辑完全正确,压测也过了,只在特定的线程交错下才丢一笔账。这种东西靠肉眼 review 是抓不到的,靠测试也很难稳定复现。

所以真正的问题不是"AI 会不会写错",而是:错了以后,谁在什么时候能发现?


二、编译器是唯一愿意 7x24 陪 AI 加班的 Reviewer

Rust 最被低估的价值,不是"内存安全",而是它把大量运行时才能暴露的问题,搬到了编译期

同一个并发 bug,在 Python/Java 里是一个"运行几百万次可能遇到一次"的概率事件,在 Rust 里是一个"你今天下午下班前必须解决的编译错误"。

举个最朴素的例子。下面这段 Python,AI 写得出来,你也 review 不出问题:

class Counter:
    def __init__(self):
        self.value = 0

    def incr(self):
        self.value += 1   # 多线程下这行是三个操作

同样的意图在 Rust 里,你根本没机会写错:

struct Counter { value: i32 }

// 试图在多线程里共享 &mut Counter —— 编译不过
// 编译器会直接告诉你:要么加锁,要么用原子类型
use std::sync::atomic::{AtomicI32, Ordering};

struct Counter { value: AtomicI32 }

impl Counter {
    fn incr(&self) {
        self.value.fetch_add(1, Ordering::Relaxed);
    }
}

Send / Sync 这两个 trait 的存在,意味着"这个类型能不能跨线程"是一个类型系统里的事实,而不是一句写在 Wiki 上、三个月后没人记得的注释。

同样的还有:

  • Option<T> 让"这里可能是空"变成必须显式处理的分支,而不是凌晨三点的 NPE 告警;
  • Result<T, E> 让"这里可能失败"无法被静默吞掉(#[must_use] 会追着你骂);
  • 所有权让"这块内存归谁"成为编译期就确定的契约,而不是一个靠团队默契维持的口头约定。

而这一切,对 AI 来说恰好是最理想的反馈信号:

sequenceDiagram participant A as "AI Agent" participant C as "cargo check" participant H as "人类" A->>C: 生成代码 C-->>A: "error[E0502]: cannot borrow as mutable" Note over A,C: 确定性 / 可复现 / 机器可读 A->>C: 自我修正 C-->>A: "error[E0308]: mismatched types" A->>C: 再次修正 C-->>A: "Finished dev profile" A->>H: 交付 Note over H: 人类只需 review "意图"
而非"内存与并发的正确性"

这一点非常关键:编译器的报错是确定性的、可复现的、结构化的(cargo check --message-format=json 直接吐 JSON)。Agent 可以在没有人类参与的情况下,拿到高质量的负反馈并自己收敛。

而在动态语言里,agent 的反馈来源是什么?是测试。测试覆盖不到的地方,它就是在裸奔——而且它自己写的测试,恰好最容易覆盖它自己想到的那些情况。

一句话总结:在 AI 写代码的时代,类型系统不是负担,是免费的、不会累的、不讲情面的 code reviewer。


三、顺便说一句:AI 基础设施本来就在被 Rust 悄悄重写

如果你只用 Python 调 API,可能没注意到一件事:你 pip install 下来的那些东西,底下越来越多是 Rust。

flowchart TD subgraph L1["应用层 / 实验层"] P1["Python 脚本"] P2["Notebook"] P3["Agent 编排"] end subgraph L2["框架层"] F1["PyTorch / JAX"] F2["LangChain 等编排框架"] end subgraph L3["高性能内核层 —— Rust 的主战场"] R1["tokenizers / safetensors"] R2["向量库
Qdrant / LanceDB"] R3["数据处理
Polars / Arrow"] R4["工具链
ruff / uv"] R5["推理与运行时
candle / burn"] end subgraph L4["系统层"] S1["CUDA / 内核 / 虚拟化"] end L1 --> L2 --> L3 --> L4

为什么是 Rust 而不是继续用 C++?我的理解有三条:

第一,尾延迟。 推理服务的痛点从来不是平均延迟,是 P99。有 GC 的语言在高吞吐下总会有那么几毫秒到几百毫秒的停顿,而 Rust 没有 GC,延迟曲线是可预测的。做过支付网关的人对这件事有生理性的敏感——我们的 SLA 从来不写平均值。

第二,FFI 成本极低。 Rust 可以编译成 C ABI 的动态库,PyO3 让 Python 侧几乎零感知。这意味着"上层 Python 保持灵活,下层 Rust 保证性能与安全"是一个可以渐进落地的方案,而不是要求团队全面重写。

第三,交付形态干净。 单个静态二进制,没有 runtime、没有 JVM、没有 node_modules、没有 glibc 版本地狱。在容器里,这意味着几 MB 的镜像和秒级冷启动——对需要弹性扩缩容的推理网关来说,这是真金白银。

顺带一提,uvruff 这两个 Rust 写的 Python 工具,把 Python 生态的体验提升了一个量级。这件事本身就挺有讽刺意味的:拯救 Python 开发体验的,是 Rust。


四、Agent 需要沙箱,而沙箱需要一门没有 UB 的语言

这是我觉得最被忽视的一点。

当我们开始让 AI 执行代码——不只是生成,而是真的跑起来、连数据库、调 API、写文件——安全模型就从"人类不会故意作恶"变成了"这段代码是一个概率模型吐出来的,我不知道它会干什么"。

传统的信任边界完全失效了。你需要的是能力控制(capability-based security):这个 agent 只能访问这三个目录、只能连这两个域名、最多用 512MB 内存、最多跑 30 秒。

flowchart TB U["用户意图"] --> AG["Agent 规划"] AG --> CODE["生成的代码
不可信"] CODE --> SB subgraph SB["WASM 沙箱 —— wasmtime / WasmEdge"] direction TB EX["执行"] CAP["能力白名单
文件 / 网络 / 时间 / 内存"] EX --- CAP end SB -->|"仅允许的系统调用"| HOST["宿主资源"] SB -.->|"越权即拒绝"| DENY["拒绝并记录"] style CODE fill:#ffe0e0,stroke:#c00 style DENY fill:#ffe0e0,stroke:#c00

而 WASM 生态的事实标准工具链,基本都是 Rust 写的,Rust 也是编译到 WASM 体验最好的语言。再往下一层,Firecracker 这类微虚拟机同样是 Rust。

逻辑其实很朴素:你用来隔离不可信代码的那层东西,自己绝对不能有内存安全漏洞。用一门存在未定义行为的语言去写沙箱,约等于用纸糊防火墙。


五、从入门到放弃环节:Rust 的代价,一条都没少

吹完了,得说点实话,不然这文章就成软文了。

编译慢。 大型项目改一行等半分钟是常态。在"改代码—看结果"这个循环上,Rust 的体验比 Go 差一个数量级。而 AI 辅助开发恰恰高度依赖快速迭代循环。这是实打实的矛盾。

AI 写 Rust 的水平,不如它写 Python。 训练语料的体量摆在那儿。LLM 写 Rust 时,幻觉出已经废弃的 API、写出过不了 borrow checker 的代码、在 async 生命周期上绕不出来,都是日常。区别在于——这些错误编译器会当场拦下来,而不是上线之后由用户帮你发现。所以它写得更费劲,但你收到的东西更可靠。这笔账怎么算,看你项目的容错空间。

async 生态有割裂感。 运行时选型、Send 约束、生命周期在异步里的传染性,这些是真的劝退。

学习曲线是真陡。 不要跟新人说"Rust 其实不难",那是骗人的。它只是把痛苦从"上线之后"提前到了"编译之前",总量不一定变少,但发生的时间点对你非常有利。

所以我的建议很保守:不要用 Rust 写 CRUD,不要用 Rust 写一次性脚本,不要因为"未来趋势"就把整个团队的技术栈掀了。


六、我的实用结论:分层,而不是站队

我现在的做法是按"这段代码错了会怎样"来分层:

层次选型理由
实验、调研、Prompt 编排Python迭代速度压倒一切,错了重跑就行
业务逻辑、常规服务Java / Go生态成熟,团队上手快,AI 也写得顺
性能热路径(tokenize、向量检索、序列化)Rust无 GC 停顿,P99 可控,PyO3 平滑接入
安全边界(沙箱、网关、加解密、账务核心)Rust这里的 bug 不是 bug,是事故

判断标准其实只有一条:

这段代码出错的成本,是"重跑一次",还是"上报监管"?

前者用最快的语言写,后者用最严的语言写。


尾声

我一直觉得,Rust 在 AI 时代的位置有点像会计里的复式记账法:它逼着你在录入的那一刻就保证两边平衡,过程繁琐、反人性、学起来痛苦,但它让"错误"这件事变得无处可藏

当代码由人一行行敲出来时,这种严格显得像洁癖。当代码由模型批量生成、由 agent 自动执行时,这种严格就是你手上为数不多、还能真正信任的东西。

AI 让写代码变便宜了,但它没有让承担后果变便宜。

所以我又把那本 Rust 的书翻出来了。这次希望不要再放弃了。

评论区
暂无评论
avatar