用 Rust 框架 Rig 写高性能 AI Agent(内存省 5 倍、可编译到 WASM)
当 Agent 要跑在高并发服务器、边缘设备、或者需要极致省内存的场景,Python 框架就开始吃力了。2026 年,Rust 原生 Agent 框架跨过了「实验 → 生产可用」的门槛,其中 Rig 生态最完整:一套 builder 风格 API 统一接 20+ 模型厂商,工具入参是编译期类型安全的,还内置 RAG、向量库,最后能编译成单个二进制文件或 WASM,扔到服务器、边缘、浏览器里都能跑。本教程带你不写一行不安全的 Rust,跑通第一个 Agent。
先搞懂:为什么用 Rust 写 Agent?
用一句话理解:Rig 把你和大模型之间的「胶水层」用 Rust 重写——同样一个 Agent,Rust 版相比 Python 常被测出约 5 倍内存下降、25–44% 延迟改善、冷启动快几个数量级。代价是你要接受 Rust 的编译期检查(更啰嗦,但更稳)。
| 维度 | Python 框架 | Rust / Rig |
|---|---|---|
| 内存占用 | 高(GC + 解释器) | 低,约 1/5 |
| 延迟 / 冷启动 | 慢 | 快,适合 Serverless / 边缘 |
| 工具入参 | 运行时校验 | 编译期类型检查 |
| 部署形态 | 解释器 + 依赖 | 单二进制 / WASM |
| 上手难度 | 低 | 中高(所有权模型) |
别为「快」而强行上 Rust:如果你做原型、做内部工具,Python 框架的开发速度优势更大。Rig 适合「性能/体积/安全是硬指标」的生产场景。
Step 1:安装 Rust 工具链
# macOS / Linux
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
# Windows:去 https://rustup.rs 下载安装器,或 winget install Rustlang.Rustup
# 验证
rustc --version
cargo --version
cargo 就是你的构建/运行命令,和 Python 的 pip+python 组合类似。Step 2:建项目并加依赖
# 建一个二进制项目
cargo new my-first-agent
cd my-first-agent
# 加 Rig 与异步运行时 tokio
cargo add rig tokio --features tokio/macros,tokio/rt-multi-thread
# 设置 Key(以 OpenAI 为例)
export OPENAI_API_KEY="sk-..."
不同厂商读不同环境变量:Anthropic 读 ANTHROPIC_API_KEY、DeepSeek 读 DEEPSEEK_API_KEY 等。Rig 的各 providers::xxx 模块会自己去找对应变量,换厂商只改一行 import。
Step 3:第一个 Agent(三步成型)
把 src/main.rs 整段替换为下面内容。记住 Rig 的方法分散在几个 trait 上,所以要先把 trait use 进来:
use rig::client::{CompletionClient, ProviderClient};
use rig::completion::Prompt;
use rig::providers::openai;
#[tokio::main]
async fn main() -> Result<(), Box> {
// 1) 从环境变量读 Key,建 OpenAI 客户端
let client = openai::Client::from_env()?;
// 2) 选模型 + 系统提示词,build 出 Agent
let agent = client
.agent("gpt-5.5") // 方法来自 CompletionClient trait
.preamble("You are a helpful assistant.") // 系统提示词
.build();
// 3) 发一个问题,等回包
let response = agent.prompt("What is the Rust programming language?").await?;
println!("{response}");
Ok(())
}
Client::from_env() 建客户端 → .agent(model).preamble(...).build() 建 Agent → .prompt(...).await? 拿结果。编译报错多半是忘了 use 对应的 trait。Step 4:给 Agent 加类型安全的工具
Rig 的工具参数和返回都是普通 Rust 类型,编译期就检查,比运行时解析稳:
use rig::completion::Tool;
use rig::providers::openai;
#[rig::tool]
async fn get_weather(location: String) -> String {
format!("{location} 今天晴,26°C。")
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let client = openai::Client::from_env()?;
let agent = client
.agent("gpt-5.5")
.preamble("你是天气助手,需要时用 get_weather 工具。")
.tool(get_weather) // 挂上工具
.build();
println!("{}", agent.prompt("北京今天适合出门吗?").await?);
Ok(())
}
工具 schema 自动生成:宏会根据函数签名生成模型能看懂的工具描述,入参类型不对直接编译不过。这正是「类型安全」带来的好处——很多错误在编译期就拦下了。
Step 5:接 RAG 与向量库
Rig 内置 EmbeddingsBuilder 和 10+ 向量库(Qdrant / MongoDB / LanceDB / SQLite 等)。最小可跑的 RAG:
use rig::providers::openai;
use rig::embeddings::EmbeddingsBuilder;
use rig::vector_store::in_memory_store::InMemoryVectorStore;
#[tokio::main]
async fn main() -> Result<(), Box> {
let client = openai::Client::from_env()?;
// 1) 把文档变成向量
let model = client.embedding_model("text-embedding-3-small");
let embeddings = EmbeddingsBuilder::new(model.clone())
.document("Rust 用所有权模型在编译期保证内存安全。")?
.document("Cargo 是 Rust 的包管理器。")?
.build().await?;
// 2) 放进向量库(这里用内存版,生产换 Qdrant 等)
let store = InMemoryVectorStore::from_documents(embeddings);
// 3) 让 Agent 在回答时自动检索 top-2
let agent = client
.agent("gpt-5.5")
.preamble("用提供的上下文回答问题。")
.dynamic_context(2, store)
.build();
println!("{}", agent.prompt("Rust 怎么保证内存安全?").await?);
Ok(())
}
InMemoryVectorStore 换成 rig-qdrant / rig-lancedb 等 companion crate 即可,Agent 代码一行都不用改。Step 6:流式输出、多厂商与编译到 WASM
1) 流式(聊天 UI / CLI 友好):
let mut stream = agent.stream_prompt("写首关于 Rust 的诗").await?;
while let Some(Ok(chunk)) = stream.next().await { print!("{chunk}"); }
2) 多厂商一套接口随便换:
let openai_client = openai::Client::from_env();
let anthropic_client = rig::providers::anthropic::Client::from_env();
// 同样的 .agent().preamble().build() 写法,业务逻辑不变
3) 编译到 WASM,跑在边缘/浏览器:
# 用 wasm-pack / wasm32 目标编译,得到可在边缘节点运行的 Agent 模块
rustup target add wasm32-unknown-unknown
cargo build --release --target wasm32-unknown-unknown
常见问题速查
| 现象 | 大概率原因 & 解决 |
|---|---|
| 编译报 "trait X not in scope" | 忘了 use rig::client::.../completion::Prompt 引入对应 trait |
| "API key not found" | 没 export 对应厂商的环境变量,或用了错厂商的变量名 |
| 编译期工具参数报错 | 工具函数参数/返回不是 Rig 支持的类型 → 用 String / 基本类型 |
| WASM 编译失败 | 用了不支持 WASM 的特性(如某些 tokio 功能)→ 用 wasm 兼容子集 |