ADK-Rust 深度实战:当 AI Agent 学会「零成本抽象」——从 Trait 驱动架构到图工作流引擎的生产级完全指南(2026)
引言:为什么 Rust 终于等来了自己的 Agent 框架
2026 年的 AI Agent 生态有一个尴尬的现实:Python 统治了一切。LangChain、CrewAI、Google ADK、AutoGen——几乎所有主流 Agent 框架都是 Python 写的。这没什么问题,Python 的生态确实最丰富,上手确实最快。
但当你把 Agent 部署到生产环境,问题就来了:
- 高并发下 GIL 成了瓶颈,一个 Agent 实例跑满一个 CPU 核
- 长运行稳定性堪忧,内存泄漏、异常退出、状态不一致
- 冷启动慢,Python 的导入链动辄几秒
- 类型安全靠测试,运行时才发现 schema 错误,线上炸了才知道
这些问题在原型阶段不是问题,但在生产阶段就是致命伤。
ADK-Rust(zavora-ai/adk-rust)就是在这个背景下诞生的。它不是"又一个 Agent SDK"——它是用 Rust 的类型系统和零成本抽象,把 Agent 开发拉到了系统编程的语言层面。39 个 crate、130K+ 下载、17+ LLM 提供商、v1.0.0 正式版,完成度已经相当高。
本文不是入门教程,而是深入剖析 ADK-Rust 的架构设计哲学、核心机制实现原理,以及生产级实战方案。读完之后,你会理解为什么 Rust 写 Agent 不是"为了炫技",而是真正解决了 Python 生态的系统性问题。
一、核心设计哲学:Trait 驱动的分层架构
1.1 五大核心 Trait
ADK-Rust 的整个架构围绕五个核心 Trait 展开,每一个都对应 Agent 系统的一个关键抽象:
/// Agent — 系统的核心执行单元
#[async_trait]
pub trait Agent: Send + Sync {
fn name(&self) -> &str;
fn description(&self) -> &str;
async fn invoke(&self, context: InvocationContext) -> Result<AsyncStream<Event>>;
}
/// Llm — 大语言模型的统一接口
#[async_trait]
pub trait Llm: Send + Sync {
async fn generate_content(&self, request: LlmRequest) -> Result<AsyncStream<LlmResponse>>;
}
/// Tool — 工具的标准化定义
#[async_trait]
pub trait Tool: Send + Sync {
fn name(&self) -> &str;
fn parameters_schema(&self) -> &serde_json::Value;
async fn execute(&self, args: serde_json::Value) -> Result<ToolOutput>;
}
/// Session — 会话状态管理
#[async_trait]
pub trait Session: Send + Sync {
async fn add(&self, message: Message) -> Result<()>;
async fn messages(&self) -> Result<Vec<Message>>;
async fn state(&self) -> Result<State>;
}
/// Toolset — 工具集合
pub trait Toolset: Send + Sync {
fn tools(&self) -> Vec<Arc<dyn Tool>>;
}
这个设计的精妙之处在于:所有具体实现都通过 Arc<dyn Trait> 做运行时多态,但得益于 Rust 的零成本抽象,性能开销极小。你不需要为多态付出虚函数表的代价——Rust 的 trait object 在编译期就完成了布局优化。
1.2 分层架构详解
ADK-Rust 采用了严格的分层设计,每一层只依赖下一层:
┌─────────────────────────────────────────┐
│ 应用层:CLI、Studio 可视化编辑器 │ adk-cli, adk-studio
├─────────────────────────────────────────┤
│ 执行层:Agent 运行时、上下文管理 │ adk-runner
├─────────────────────────────────────────┤
│ Agent层:LLM Agent、工作流、图、实时 │ adk-agent, adk-graph, adk-realtime
├─────────────────────────────────────────┤
│ 集成层:LLM 提供商、工具、浏览器 │ adk-model, adk-tool, adk-browser
├─────────────────────────────────────────┤
│ 基础设施:Session、Artifact、Memory │ adk-session, adk-artifact, adk-memory
├─────────────────────────────────────────┤
│ 安全层:RBAC、SSO、Guardrail │ adk-auth, adk-guardrail
├─────────────────────────────────────────┤
│ 评估层:Agent 测试和评测 │ adk-eval
├─────────────────────────────────────────┤
│ 核心层:基础 Trait 和类型 │ adk-core
└─────────────────────────────────────────┘
这种分层的核心好处是:每一层都可以独立替换。你不喜欢默认的 Session 实现?换一个。你觉得某个 LLM 提供商的实现有 bug?自己实现 Llm trait 就行。Python 框架通常也支持这种扩展,但 Rust 的 trait 系统会在编译期就检查你的实现是否满足接口契约,而不是等到运行时才报错。
1.3 为什么是 Trait 而不是 Enum
很多 Rust 新手会问:为什么不用 Enum 来表示不同的 Agent/Model/Tool?
答案在于开放封闭原则。Enum 是封闭的——你要支持新的 LLM 提供商,必须修改 enum 定义。而 Trait 是开放的——任何人都可以在自己的 crate 里实现 Llm trait,然后注入到框架中,完全不需要修改上游代码。
这在 Agent 框架里尤其重要,因为 LLM 提供商在不断增长,工具的定义权应该在下层开发者手里,而不是框架核心里。
二、Agent 类型系统:从简单到复杂的渐进式设计
ADK-Rust 提供了四种 Agent 类型,从简单到复杂逐步递进。这不是设计上的冗余,而是刻意的能力分层——简单的场景用简单的 Agent,不要为了 10% 的需求给 90% 的场景增加复杂度。
2.1 LlmAgent:一切的基础
LlmAgent 是最基础的 Agent,本质上就是 一个 LLM + instruction + 工具列表:
use adk_rust::prelude::*;
use std::sync::Arc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let api_key = std::env::var("GEMINI_API_KEY")?;
let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;
let agent = LlmAgentBuilder::new("code_reviewer")
.instruction(r#"
You are a senior code reviewer. For each piece of code:
1. Identify potential bugs and edge cases
2. Suggest performance improvements
3. Check for security vulnerabilities
4. Rate code quality on a 1-10 scale
Format your review as structured markdown.
"#)
.model(Arc::new(model))
.build()?;
let context = InvocationContext::new()
.with_user_message("Review this function: fn add(a: i32, b: i32) -> i32 { a + b }");
let mut stream = agent.invoke(context).await?;
while let Some(event) = stream.next().await {
match event {
Event::Text(text) => print!("{text}"),
Event::ToolCall(call) => println!("\n[Tool: {}]", call.name),
Event::ToolResult(result) => println!("[Result: {}]", result.output),
_ => {}
}
}
Ok(())
}
注意 invoke() 返回的是 AsyncStream<Event>——这意味着 Agent 的输出是实时流式的,你可以逐步渲染给用户,而不是等整个响应生成完。这对 Agent 场景极其重要,因为 Agent 可能需要调用多个工具、执行多步推理,用户不应该盯着空白屏幕等几十秒。
2.2 WorkflowAgent:确定性编排
当单个 Agent 不够用时,你需要编排多个 Agent 协同工作。ADK-Rust 提供了三种确定性编排模式:
SequentialAgent:顺序管道
use adk_rust::prelude::*;
// 三阶段处理:提取 → 分析 → 格式化
let extractor = LlmAgentBuilder::new("extractor")
.instruction("Extract key entities from the text. Output as JSON.")
.model(model.clone())
.build()?;
let analyzer = LlmAgentBuilder::new("analyzer")
.instruction("Analyze the extracted entities. Identify patterns and anomalies.")
.model(model.clone())
.build()?;
let formatter = LlmAgentBuilder::new("formatter")
.instruction("Format the analysis into a professional report with sections.")
.model(model.clone())
.build()?;
let pipeline = SequentialAgent::new(vec![
Arc::new(extractor),
Arc::new(analyzer),
Arc::new(formatter),
]).with_output_key("final_report");
SequentialAgent 的实现原理很简单但很关键:前一个 Agent 的输出自动成为后一个 Agent 的上下文。这不是简单的字符串拼接——框架会将上一个 Agent 的事件流(包括工具调用和结果)序列化为结构化消息,注入到下一个 Agent 的 InvocationContext 中。
ParallelAgent:并行执行
// 同时执行多个独立任务
let sentiment = LlmAgentBuilder::new("sentiment")
.instruction("Analyze sentiment. Return: positive/negative/neutral with confidence.")
.model(model.clone())
.build()?;
let topic = LlmAgentBuilder::new("topic_classifier")
.instruction("Classify the topic. Return: category and subcategory.")
.model(model.clone())
.build()?;
let language = LlmAgentBuilder::new("language_detector")
.instruction("Detect language. Return: language code and confidence.")
.model(model.clone())
.build()?;
let parallel = ParallelAgent::new(vec![
Arc::new(sentiment),
Arc::new(topic),
Arc::new(language),
]).with_shared_state(true); // 结果写入 SharedState
ParallelAgent 使用 Tokio 的 join! 宏实现真正的并行执行——不是协程轮流跑,而是多个 Agent 同时在不同线程上运行。这在 Rust 里很自然,在 Python 里就受限于 GIL。
LoopAgent:循环执行
let refiner = LlmAgentBuilder::new("refiner")
.instruction("Improve the text. Rate your output 1-10. If < 8, explain what needs improvement.")
.model(model.clone())
.build()?;
let loop_agent = LoopAgent::new(Arc::new(refiner))
.max_iterations(5)
.exit_condition(|state: &State| {
// 当 Agent 自评 >= 8 时退出循环
state.get("self_rating")
.and_then(|v| v.as_f64())
.map(|r| r >= 8.0)
.unwrap_or(false)
});
LoopAgent 是实现"自我改进"模式的关键——Agent 循环执行,每轮检查输出质量,达标后自动退出。这在代码生成、文案优化、方案迭代等场景非常有用。
2.3 GraphAgent:复杂有向图工作流
这是 ADK-Rust 最强大的 Agent 类型,灵感来自 LangGraph,但实现上更 Rust——用类型系统保证图的合法性。
use adk_rust::prelude::*;
// 定义一个多语言内容处理管道
let translator = LlmAgentBuilder::new("translator")
.instruction("Translate the input text to English if it's not already.")
.model(model.clone())
.build()?;
let summarizer = LlmAgentBuilder::new("summarizer")
.instruction("Create a concise summary in 3 bullet points.")
.model(model.clone())
.build()?;
let fact_checker = LlmAgentBuilder::new("fact_checker")
.instruction("Check factual claims. Flag any that seem dubious.")
.model(model.clone())
.build()?;
let combiner = LlmAgentBuilder::new("combiner")
.instruction("Combine the summary and fact-check into a final report.")
.model(model.clone())
.build()?;
// 构建图
let graph = GraphAgent::builder("content_processor")
// 声明 channel(节点间通信的管道)
.channels(&["input", "translation", "summary", "fact_check", "output"])
// 添加节点
.node(translator.into_node("translator"))
.node(summarizer.into_node("summarizer"))
.node(fact_checker.into_node("fact_checker"))
.node(combiner.into_node("combiner"))
// 定义边
.edge(START, "translator") // 入口 → 翻译
.edge("translator", "summarizer") // 翻译 → 摘要
.edge("translator", "fact_checker") // 翻译 → 事实核查(并行)
.edge("summarizer", "combiner") // 摘要 → 合并
.edge("fact_checker", "combiner") // 核查 → 合并
.edge("combiner", END) // 合并 → 出口
.build()?;
GraphAgent 的几个核心机制值得深入理解:
并行节点执行(PregelExecutor,BSP 模型):图中的并行节点使用 BSP(Bulk Synchronous Parallel)模型执行——每个超步中,所有就绪节点并行执行,然后同步,再进入下一个超步。这保证了确定性:同样的输入永远产生同样的输出。
条件路由:不是所有情况都走固定路径。你可以定义条件边:
let graph = GraphAgent::builder("smart_router")
.channels(&["input", "category", "output"])
.node(classifier.into_node("classifier"))
.node(tech_handler.into_node("tech"))
.node(biz_handler.into_node("biz"))
.node(fallback.into_node("fallback"))
.edge(START, "classifier")
// 条件路由:根据分类结果走不同路径
.conditional_edge(
"classifier",
Router::by_field("category", |val: &str| {
match val {
"technology" => "tech",
"business" => "biz",
_ => "fallback",
}
})
)
.edge("tech", END)
.edge("biz", END)
.edge("fallback", END)
.build()?;
Checkpointing:图执行过程中的状态可以持久化到 Memory 或 SQLite 后端。如果 Agent 在执行过程中崩溃,可以从最近的 checkpoint 恢复,而不是从头开始。这对长运行的生产 Agent 至关重要。
Human-in-the-Loop:图可以在特定节点中断,等待人工输入后从 checkpoint 恢复执行:
let graph = GraphAgent::builder("approval_flow")
.channels(&["input", "draft", "approved", "output"])
.node(drafter.into_node("drafter"))
.node(publisher.into_node("publisher"))
.edge(START, "drafter")
.interrupt_before("publisher") // 在发布前暂停,等待人工审核
.edge("drafter", "publisher")
.edge("publisher", END)
.build()?;
2.4 RealtimeAgent:实时语音交互
这是 ADK-Rust 最独特的 Agent 类型——支持双向音频流的实时语音交互:
use adk_rust::prelude::*;
let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;
let agent = RealtimeAgent::builder("voice_assistant")
.model(model)
.instruction("You are a helpful voice assistant. Keep responses concise.")
.voice("alloy")
.server_vad() // 服务器端语音活动检测
.turn_detection(0.5) // 静默 500ms 判定一轮结束
.build()?;
// 连接到音频流
agent.connect(audio_stream).await?;
RealtimeAgent 支持 OpenAI Realtime API、Gemini Live API 和 LiveKit WebRTC 桥接三种后端。这意味着你可以根据成本、延迟和部署环境选择最合适的方案,而 Agent 代码不需要改动。
三、工具系统:从宏到 MCP 的全链路
3.1 #[tool] 宏:零样板代码
ADK-Rust 最让我惊喜的设计之一是 #[tool] 宏。定义一个工具只需要:
use adk_rust::tool;
use serde::Deserialize;
use schemars::JsonSchema;
use serde_json::json;
#[derive(Deserialize, JsonSchema)]
struct SearchCodeArgs {
/// The query string to search for
query: String,
/// Maximum number of results to return
#[serde(default = "default_limit")]
limit: usize,
/// File extension filter (e.g., "rs", "py")
extension: Option<String>,
}
fn default_limit() -> usize { 10 }
/// Search code in the repository using semantic search.
#[tool]
async fn search_code(args: SearchCodeArgs) -> Result<serde_json::Value> {
let results = semantic_search(&args.query, args.limit, args.extension.as_deref()).await?;
Ok(json!({
"results": results,
"total": results.len(),
"query": args.query,
}))
}
宏自动完成三件事:
- 从 doc comment 提取工具描述:
/// Search code in the repository...变成工具的description - 从 args 类型推导 JSON Schema:
SearchCodeArgs的字段类型、doc comment、默认值全部反映在 schema 中 - 生成 Tool trait 实现:你不需要手写
fn name(),fn parameters_schema(),fn execute()这些样板代码
这和 Python 的 @tool 装饰器很像,但有一个关键区别:Rust 的宏在编译期展开,如果 schema 生成有问题,编译就过不了。Python 的装饰器只在运行时才生效,如果参数类型注解写错了,得等到 Agent 调用工具时才能发现。
3.2 复杂工具实战:数据库查询 Agent
来看一个更实际的例子——一个能查询 PostgreSQL 的工具:
use adk_rust::tool;
use serde::Deserialize;
use schemars::JsonSchema;
use serde_json::json;
use sqlx::PgPool;
#[derive(Deserialize, JsonSchema)]
struct QueryDatabaseArgs {
/// SQL query to execute. Only SELECT statements are allowed.
query: String,
/// Database connection name from the configured connections
connection: String,
}
/// Execute a read-only SQL query against a configured database.
/// Returns results as JSON array. Only SELECT statements are permitted.
#[tool]
async fn query_database(args: QueryDatabaseArgs) -> Result<serde_json::Value> {
// 安全校验:只允许 SELECT
let normalized = args.query.trim().to_uppercase();
if !normalized.starts_with("SELECT") {
return Ok(json!({
"error": "Only SELECT queries are allowed",
"hint": "Use SELECT statements for data retrieval"
}));
}
// 检查危险操作
let dangerous_keywords = ["DROP", "DELETE", "UPDATE", "INSERT", "ALTER", "CREATE", "TRUNCATE"];
for kw in &dangerous_keywords {
if normalized.contains(kw) {
return Ok(json!({
"error": format!("Forbidden keyword: {kw}"),
"hint": "This tool only supports read-only queries"
}));
}
}
let pool = get_connection_pool(&args.connection).await?;
let rows = sqlx::query(&args.query)
.fetch_all(&pool)
.await
.map_err(|e| anyhow::anyhow!("Query failed: {e}"))?;
let results: Vec<serde_json::Map<String, serde_json::Value>> = rows
.iter()
.map(|row| {
// 将行数据转为 JSON
row.columns()
.iter()
.map(|col| {
let value = row.try_get_raw(col.ordinal())
.ok()
.and_then(|_| row.try_get::<serde_json::Value, _>(col.ordinal()).ok())
.unwrap_or(serde_json::Value::Null);
(col.name().to_string(), value)
})
.collect()
})
.collect();
Ok(json!({
"results": results,
"row_count": results.len(),
"connection": args.connection,
}))
}
3.3 MCP 集成:连接外部工具生态
MCP(Model Context Protocol)是 Agent 工具生态的未来标准。ADK-Rust 的 MCP 集成做得相当完善:
use adk_rust::prelude::*;
// 连接 MCP 服务器
let mcp_tools = McpToolset::builder()
.server("filesystem", "npx -y @modelcontextprotocol/server-filesystem /data")
.server("github", "npx -y @modelcontextprotocol/server-github")
.server("postgres", "npx -y @modelcontextprotocol/server-postgres postgres://localhost/mydb")
.build()
.await?;
// 直接使用 MCP 工具
let agent = LlmAgentBuilder::new("full_stack_agent")
.instruction("You have access to filesystem, GitHub, and database tools. Use them as needed.")
.model(model)
.toolset(mcp_tools) // 一行注入所有 MCP 工具
.build()?;
ADK-Rust 支持 MCP Elicitation——MCP 服务器可以在运行时通过结构化表单或 URL 请求额外用户输入。比如一个支付工具可能在执行前要求用户确认金额,这个交互流程在框架层面就支持了,不需要你自己实现。
3.4 浏览器自动化:46 个 WebDriver 工具
ADK-Rust 内置了 46 个 WebDriver 工具,覆盖导航、点击、填表、截图、JS 执行等操作:
use adk_rust::prelude::*;
let browser = BrowserToolset::new(BrowserConfig::builder()
.headless(true)
.timeout(Duration::from_secs(30))
.build())?;
let agent = LlmAgentBuilder::new("web_scraper")
.instruction("Navigate websites, extract data, and fill forms as instructed.")
.model(model)
.toolset(browser) // 自动注入 navigate, click, type, screenshot 等 46 个工具
.build()?;
四、多提供商支持:一行代码切换模型
4.1 统一的 Llm Trait
ADK-Rust 最实用的特性之一是所有 LLM 提供商实现同一个 Llm trait,切换模型只改一行:
use adk_rust::prelude::*;
// Gemini
let model: Arc<dyn Llm> = Arc::new(GeminiModel::new(&key, "gemini-2.5-flash")?);
// 切换到 OpenAI
// let model: Arc<dyn Llm> = Arc::new(OpenAIClient::new(OpenAIConfig::new(key, "gpt-5-mini"))?);
// 切换到 Anthropic
// let model: Arc<dyn Llm> = Arc::new(AnthropicClient::new(AnthropicConfig::new(key, "claude-sonnet-4-6"))?);
// 切换到 DeepSeek
// let model: Arc<dyn Llm> = Arc::new(DeepSeekClient::chat(key)?);
// 切换到本地 Ollama(无需 API Key)
// let model: Arc<dyn Llm> = Arc::new(OllamaClient::new("http://localhost:11434", "qwen3.6")?);
// Agent 代码完全不需要改
let agent = LlmAgentBuilder::new("assistant")
.instruction("You are a helpful assistant.")
.model(model) // 同一个接口
.build()?;
4.2 提供商特性矩阵
| 提供商 | 代表模型 | 特色能力 |
|---|---|---|
| Gemini | gemini-2.5-flash/pro, gemini-3-flash-preview | 2M context,多模态,代码执行 |
| OpenAI | gpt-5, gpt-5-mini/nano, o3, o4-mini | Responses API 支持 |
| Anthropic | claude-opus-4-8, claude-sonnet-4-6 | Prompt caching, Extended thinking |
| DeepSeek | deepseek-chat, deepseek-reasoner | 思维链模式,上下文缓存 |
| Groq | llama-4-scout, llama-3.3-70b | LPU 加速,最快推理 |
| Ollama | qwen3.6, llama3.2 | 本地推理,无需 API Key |
| mistral.rs | Gemma 4, Qwen 3.5, Voxtral | 原生本地推理,GPU 加速 |
| Bedrock | claude-sonnet-4 等 | AWS 集成 |
| Azure AI | 端点指定模型 | 企业 Azure 部署 |
另外还有 Fireworks、Together、Mistral AI、Perplexity、Cerebras、SambaNova、xAI 等通过 OpenAI 兼容 preset 接入。
4.3 运行时模型路由
生产环境经常需要根据请求特征动态选择模型——简单问题用便宜模型,复杂问题用强模型:
use adk_rust::prelude::*;
struct RouterModel {
fast: Arc<dyn Llm>,
smart: Arc<dyn Llm>,
}
#[async_trait]
impl Llm for RouterModel {
async fn generate_content(&self, request: LlmRequest) -> Result<AsyncStream<LlmResponse>> {
// 根据输入复杂度选择模型
let complexity = estimate_complexity(&request);
let model = if complexity > 0.7 {
&self.smart // 复杂问题 → 用强模型
} else {
&self.fast // 简单问题 → 用快模型
};
model.generate_content(request).await
}
}
fn estimate_complexity(request: &LlmRequest) -> f64 {
let msg = request.last_user_message();
let has_code = msg.contains("```") || msg.contains("fn ") || msg.contains("def ");
let is_long = msg.len() > 500;
let asks_analysis = msg.contains("分析") || msg.contains("explain") || msg.contains("compare");
let mut score = 0.3;
if has_code { score += 0.3; }
if is_long { score += 0.2; }
if asks_analysis { score += 0.2; }
score.min(1.0)
}
因为 Llm 是一个 trait,你可以自由组合——做模型路由、做 fallback 链、做 A/B 测试,框架完全不管。
五、生产级特性:从 Session 到安全
5.1 Session 管理
Session 是 Agent 的"记忆",ADK-Rust 提供两种后端:
use adk_rust::session::{InMemorySession, SqliteSession, SessionConfig};
// 开发环境:内存 Session
let session = InMemorySession::new();
// 生产环境:SQLite 持久化
let session = SqliteSession::new("sqlite:///var/lib/agent/sessions.db").await?
.with_encryption(Aes256Gcm::new(&encryption_key)?) // AES-256-GCM 加密
.with_key_rotation(Duration::from_days(30)) // 密钥轮换
.build()
.await?;
Session 加密和密钥轮换是企业合规的硬需求。ADK-Rust 直接内置了,不需要你自己搞一套加密方案。
5.2 安全体系
RBAC 权限控制
use adk_rust::auth::{RbacPolicy, Role, Permission};
let policy = RbacPolicy::new()
.add_role(Role::new("viewer")
.allow(Permission::Read)
.deny(Permission::ExecuteTool))
.add_role(Role::new("operator")
.allow(Permission::Read)
.allow(Permission::ExecuteTool)
.deny(Permission::ManageAgents)) // deny 优先于 allow
.add_role(Role::new("admin")
.allow(Permission::All));
Guardrail:内容安全护栏
use adk_rust::guardrail::{GuardrailPipeline, PiiFilter, ContentFilter, SchemaValidator};
let guardrail = GuardrailPipeline::new()
.add(PiiFilter::new() // PII 脱敏
.redact_emails()
.redact_phone_numbers()
.redact_credit_cards())
.add(ContentFilter::new() // 内容过滤
.block_harmful_content()
.block_pii_leakage())
.add(SchemaValidator::new(tool_schemas())); // JSON Schema 校验
let agent = LlmAgentBuilder::new("safe_agent")
.model(model)
.guardrail(guardrail)
.build()?;
Guardrail 的执行顺序很关键:PII 脱敏 → 内容过滤 → Schema 校验。脱敏在前面,这样后续的内容过滤和 Schema 校验不会意外泄露 PII。
5.3 可观测性
生产 Agent 必须可观测。ADK-Rust 内置 OpenTelemetry 集成:
use adk_rust::telemetry::TelemetryConfig;
let telemetry = TelemetryConfig::new()
.with_tracing(true) // 分布式追踪
.with_metrics(true) // 性能指标
.with_export(OTLPExporter::new("http://jaeger:4317")) // 导出到 Jaeger
.build()
.await?;
let runner = Runner::new(agent)
.with_telemetry(telemetry)
.build()
.await?;
你可以看到每个 Agent 调用的延迟、Token 消耗、工具调用次数、错误率等指标。这在多 Agent 系统中尤其重要——当系统出问题时,没有可观测性就是盲人摸象。
六、部署实战:从开发到生产
6.1 三种部署模式
CLI 模式(开发调试)
cargo install cargo-adk
cargo adk new my-agent --template tools
cd my-agent
cargo adk run # 交互式 REPL
Server 模式(生产部署)
use adk_rust::server::ServerConfig;
let server = ServerConfig::new()
.host("0.0.0.0")
.port(8080)
.with_sse(true) // Server-Sent Events 流式输出
.with_a2a_protocol(true) // Agent-to-Agent 协议支持
.with_cors(["https://myapp.com"])
.build()
.await?;
server.serve(agent).await?;
Server 模式暴露 REST API,支持 SSE 流式响应和 A2A 协议。A2A 协议让你的 Agent 可以被其他 Agent 发现和调用,这是构建 Agent 生态的基础。
Embedded 模式(库集成)
// 把 Agent 嵌入到更大的应用中
let agent = LlmAgentBuilder::new("chatbot")
.model(model)
.build()?;
// 在你的 Web 框架里调用
async fn handle_chat(msg: String) -> Result<String> {
let context = InvocationContext::new().with_user_message(&msg);
let mut stream = agent.invoke(context).await?;
let mut response = String::new();
while let Some(Event::Text(text)) = stream.next().await {
response.push_str(&text);
}
Ok(response)
}
6.2 生产架构
对于大规模部署,推荐架构如下:
┌──────────────┐
│ Load Balancer │
└──────┬───────┘
│
┌─────────────┼─────────────┐
│ │ │
┌─────┴─────┐ ┌────┴─────┐ ┌────┴─────┐
│ Agent Pod │ │ Agent Pod│ │ Agent Pod│ ← 无状态,水平扩展
└─────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
└─────────────┼─────────────┘
│
┌─────────────┼─────────────┐
│ │ │
┌─────┴──────┐ ┌───┴──────┐ ┌────┴─────┐
│ PostgreSQL │ │ S3/MinIO │ │ Qdrant │
│ (Session) │ │(Artifact)│ │(RAG 向量) │
└────────────┘ └──────────┘ └──────────┘
关键点:Agent Pod 是无状态的,所有状态存储在外部(PostgreSQL for Session, S3 for Artifact, Qdrant for 向量搜索)。这意味着你可以随意扩缩容,Pod 挂了也不丢状态。
6.3 Docker 部署
FROM rust:1.94-slim AS builder
WORKDIR /app
COPY . .
RUN cargo build --release --features standard
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/my-agent /usr/local/bin/
ENV RUST_LOG=info
ENV ADK_SESSION_BACKEND=sqlite
EXPOSE 8080
CMD ["my-agent", "serve", "--host", "0.0.0.0", "--port", "8080"]
七、Agent 评估:让 Agent 质量可量化
Agent 的输出是概率性的,测试不能只看"能不能跑",还要看"跑得好不好"。ADK-Rust 的 adk-eval 提供了完整的评估框架:
7.1 Trajectory 评估
检查 Agent 的工具调用序列是否符合预期:
use adk_rust::eval::{TrajectoryEval, MatchStrategy};
let eval = TrajectoryEval::new()
.expected_tools(vec!["search_code", "query_database", "format_response"])
.strategy(MatchStrategy::Subset) // 允许额外调用,但必须包含预期的
.run(&agent, test_input).await?;
println!("Tool call accuracy: {:.1}%", eval.accuracy() * 100.0);
println!("Missing tools: {:?}", eval.missing);
println!("Extra tools: {:?}", eval.extra);
7.2 LLM-as-Judge
用另一个 LLM 做语义评估:
use adk_rust::eval::LlmJudge;
let judge = LlmJudge::new(judge_model)
.criteria("Is the response accurate, helpful, and safe?")
.rubric(vec![
("accuracy", 0.4, "Is the information correct?"),
("helpfulness", 0.3, "Does it address the user's need?"),
("safety", 0.3, "Does it avoid harmful content?"),
]);
let result = judge.evaluate(&agent_output).await?;
println!("Overall score: {:.1}/10", result.score());
for (criterion, score) in result.breakdown() {
println!(" {criterion}: {score:.1}");
}
7.3 持续评估流水线
use adk_rust::eval::{EvalSuite, EvalRunner};
let suite = EvalSuite::new("my_agent_eval")
.add_case("greeting", TestCase::new("Hello!").expect_no_tool_call())
.add_case("code_search", TestCase::new("Find all async functions")
.expect_tools(vec!["search_code"]))
.add_case("db_query", TestCase::new("Show me user #42")
.expect_tools(vec!["query_database"])
.expect_output_contains("user_id: 42"))
.add_judge(LlmJudge::new(judge_model)
.criteria("Is the response appropriate for the query?"));
let runner = EvalRunner::new(agent.clone());
let report = runner.run_suite(&suite).await?;
println!("Pass rate: {:.1}%", report.pass_rate() * 100.0);
for failure in &report.failures {
println!("FAIL: {} - {}", failure.case_name, failure.reason);
}
这套评估体系可以集成到 CI/CD 中——每次 Agent 代码变更后自动跑评估,防止回归。
八、Feature Tier:按需选择功能层级
ADK-Rust 用 Cargo feature 实现了功能分层,你不需要拉取整个框架:
# Cargo.toml
# 最小化:只需要 Gemini + Agent + Session
[dependencies]
adk-rust = { version = "1.0", default-features = true } # minimal 是默认
# 标准版:+ OpenAI、Anthropic、工具、Memory、Server、Auth、Graph、Eval
[dependencies]
adk-rust = { version = "1.0", features = ["standard"] }
# 企业版:+ Realtime、Browser、RAG、Payments、AWP
[dependencies]
adk-rust = { version = "1.0", features = ["enterprise"] }
# 全功能:+ Audio、Code Execution、Sandbox
[dependencies]
adk-rust = { version = "1.0", features = ["full"] }
这个设计很 Rust——你为你用到的功能付出编译时间和二进制大小的代价,不用的不付。Python 框架通常做不到这点,pip install 出来就是一整个包。
| Tier | 包含内容 | 适用场景 | 编译时间 |
|---|---|---|---|
| minimal(默认) | Gemini + Agent + Session | 快速起步、原型验证 | ~2min |
| standard | + OpenAI、Anthropic、工具、Memory、Server、Auth、Graph、Eval | 生产部署 | ~5min |
| enterprise | + Realtime、Browser、RAG、Payments、AWP | 全功能生产 | ~8min |
| full | + Audio、Code Execution、Sandbox | 全部 | ~10min |
九、实战案例:构建一个生产级代码审查 Agent
把前面学到的所有知识串起来,构建一个完整的代码审查 Agent:
use adk_rust::prelude::*;
use std::sync::Arc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// 1. 配置模型(带 fallback)
let primary = OpenAIClient::new(OpenAIConfig::from_env("gpt-5-mini")?)?;
let fallback = AnthropicClient::new(AnthropicConfig::from_env("claude-sonnet-4-6")?)?;
let model = FallbackModel::new(primary, fallback);
// 2. 定义工具
let search_tool = search_code(); // 代码搜索
let query_tool = query_database(); // 数据库查询
let git_tool = McpToolset::builder()
.server("github", "npx -y @modelcontextprotocol/server-github")
.build().await?; // GitHub MCP
// 3. 构建 Graph 工作流
let analyzer = LlmAgentBuilder::new("analyzer")
.instruction(r#"
You are a code review analyzer. Given a diff or code snippet:
1. Identify potential bugs and edge cases
2. Check for security vulnerabilities
3. Evaluate code style and maintainability
4. Suggest specific improvements with code examples
"#)
.model(Arc::new(model.clone()))
.tool(search_tool.clone())
.build()?;
let security_checker = LlmAgentBuilder::new("security")
.instruction(r#"
You are a security specialist. Focus exclusively on:
- SQL injection, XSS, CSRF
- Authentication/authorization flaws
- Sensitive data exposure
- Dependency vulnerabilities
Rate severity: critical/high/medium/low
"#)
.model(Arc::new(model.clone()))
.build()?;
let summarizer = LlmAgentBuilder::new("summarizer")
.instruction(r#"
You are a review summarizer. Combine the code analysis and security review into:
1. Executive summary (2-3 sentences)
2. Critical issues (must fix before merge)
3. Suggestions (nice to have)
4. Overall assessment: approve/request changes/block
"#)
.model(Arc::new(model.clone()))
.build()?;
// 4. 构建图
let graph = GraphAgent::builder("code_review")
.channels(&["input", "analysis", "security", "output"])
.node(analyzer.into_node("analyzer"))
.node(security_checker.into_node("security"))
.node(summarizer.into_node("summarizer"))
.edge(START, "analyzer")
.edge(START, "security") // 分析和安全检查并行
.edge("analyzer", "summarizer")
.edge("security", "summarizer") // 两者完成后汇总
.edge("summarizer", END)
.build()?;
// 5. 配置安全护栏
let guardrail = GuardrailPipeline::new()
.add(PiiFilter::new().redact_emails().redact_api_keys())
.add(ContentFilter::new().block_harmful_content());
// 6. 部署为 Server
let server = ServerConfig::new()
.host("0.0.0.0")
.port(8080)
.with_sse(true)
.with_auth(RbacPolicy::from_file("rbac.yaml")?)
.with_guardrail(guardrail)
.with_telemetry(TelemetryConfig::production()?)
.build()
.await?;
server.serve(graph).await?;
Ok(())
}
这个例子展示了 ADK-Rust 的完整能力:多 Agent 图工作流 + MCP 工具集成 + 模型 fallback + 安全护栏 + RBAC + 可观测性 + Server 部署——全部在一个 Rust 项目里完成,编译期类型检查,运行时零额外开销。
十、性能对比:Rust vs Python Agent 框架
| 维度 | ADK-Rust | LangChain (Python) | Google ADK (Python) |
|---|---|---|---|
| 冷启动 | 快(4.6x) | 慢 | 中等 |
| 内存占用 | 低(~30MB) | 高(~200MB) | 中等 |
| 类型安全 | 编译期 | 运行时 | 运行时 |
| 并发模型 | Tokio async(真并行) | GIL 限制 | asyncio |
| 提供商数量 | 17+ | 30+ | 6 |
| 图工作流 | 内置 adk-graph | LangGraph | 内置 |
| 实时语音 | 内置 adk-realtime | 需第三方 | 内置 |
| 可视化编辑 | ADK Studio | LangGraph Studio | 无 |
| Agent 评估 | 内置 adk-eval | LangSmith | 内置 |
| 部署模式 | CLI/Server/Embedded | 多种 | CLI/Server |
Rust 在性能和类型安全上有天然优势,但 Python 生态的丰富度仍是 ADK-Rust 需要追赶的。不过在 Agent 运行时这个特定场景,Rust 的优势(低延迟、低内存、高并发、长运行稳定)非常匹配。
十一、ADK Studio:可视化构建工具
如果你不想手写图工作流的代码,ADK Studio 提供了拖拽式可视化编辑器:
cargo adk studio # 启动本地 Studio
Studio 的核心能力:
- 拖拽设计:从工具栏拖 Agent 节点到画布,连线定义数据流
- 实时代码生成:画布上的每个操作都实时生成对应的 Rust 代码
- 在线测试:在 Studio 里直接运行 Agent,查看每步的输入输出
- 模板市场:社区共享的 Agent 模板,一键导入
还有 ADK Playground(playground.adk-rust.com),可以在浏览器里运行 70+ Agent 示例,无需登录和安装。适合在决定投入之前先看看框架能做什么。
十二、脚手架工具:从零到一的最短路径
# 安装 CLI
cargo install cargo-adk
# 创建项目(8 个基础模板)
cargo adk new my-agent # 基础 Gemini Agent
cargo adk new my-agent --template tools # 带自定义工具
cargo adk new my-agent --template rag # RAG 向量搜索
cargo adk new my-agent --template api # REST 服务器
cargo adk new my-agent --template graph # 图工作流
cargo adk new my-agent --template realtime # 实时语音
# 加 addon(9 个 addon 可组合)
cargo adk new my-agent --template api --addon telemetry,docker,ci
# 运行
cd my-agent
cargo adk run
最简单的"Hello Agent"只需要三行代码:
use adk_rust::run;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let response = run("You are a helpful assistant.", "What is 2 + 2?").await?;
println!("{response}");
Ok(())
}
总结与展望
ADK-Rust 证明了一件事:Rust 写 Agent 不是炫技,是工程选择。
当你的 Agent 需要处理高并发、长运行、低延迟的场景时,Rust 的类型安全、零成本抽象、真并行能力是 Python 生态无法提供的。ADK-Rust 把这些 Rust 优势包装成了开发者友好的 API——#[tool] 宏让你零样板定义工具,LlmAgentBuilder 让你链式构建 Agent,GraphAgent 让你用声明式 API 定义复杂工作流。
当然,ADK-Rust 也有不足:
- Python 生态的丰富度仍是追赶目标:30+ vs 17+ 提供商
- 学习曲线:Rust 本身的入门门槛不低
- 社区规模:相比 LangChain 的庞大社区,还处于早期
但趋势是清晰的:Agent 从原型走向生产,从"能跑"走向"跑得稳",Rust 的价值会越来越大。如果你的下一个 Agent 项目需要跑在生产环境,值得认真考虑 ADK-Rust。
关键链接:
- GitHub: https://github.com/zavora-ai/adk-rust
- Playground: https://playground.adk-rust.com
- 文档 Wiki: https://github.com/zavora-ai/adk-rust/wiki