LlmAgent

LlmAgent 是 adk-rust 中的核心代理类型,它使用大型语言模型进行推理和决策。

快速开始

创建一个新项目:

cargo new llm_agent
cd llm_agent

添加依赖到 Cargo.toml

[dependencies]
adk-rust = "0.2.0"
tokio = { version = "1.40", features = ["full"] }
dotenvy = "0.15"
serde_json = "1.0"

使用您的 API 密钥创建 .env 文件:

echo 'GOOGLE_API_KEY=your-api-key' > .env

替换 src/main.rs

use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;

#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
    dotenvy::dotenv().ok();
    
    let api_key = std::env::var("GOOGLE_API_KEY")?;
    let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;

    let agent = LlmAgentBuilder::new("my_agent")
        .instruction("You are a helpful assistant.")
        .model(Arc::new(model))
        .build()?;

    Launcher::new(Arc::new(agent)).run().await?;
    Ok(())
}

运行它:

cargo run

与您的 Agent 交互

您将看到一个交互式提示符:

🤖 Agent ready! Type your questions (or 'exit' to quit).

You: Hello! What can you help me with?
Assistant: Hello! I'm a helpful assistant. I can help you with:
- Answering questions on various topics
- Explaining concepts clearly
- Having a conversation

What would you like to know?

You: exit
👋 Goodbye!

使用指令塑造 Agent 行为

instruction() 方法定义了 Agent 的个性和行为。这是指导每个响应的 系统提示

// 一个正式的商业助手
let formal_agent = LlmAgentBuilder::new("formal_assistant")
    .instruction("您是一名专业的商业顾问。使用正式语言。简洁并以数据为驱动。")
    .model(Arc::new(model))
    .build()?;

// 一个友好的编程导师
let tutor_agent = LlmAgentBuilder::new("code_tutor")
    .instruction("您是一位友好的编程初学者导师。简单解释概念。使用示例。鼓励提问。永远不要让用户因为不懂而感到不适。")
    .model(Arc::new(model))
    .build()?;

// 一个富有创意的讲故事者
let story_agent = LlmAgentBuilder::new("storyteller")
    .instruction("您是一位富有创意的讲故事者。用生动的描述创作引人入胜的叙事。使用情节反转和令人难忘的角色。")
    .model(Arc::new(model))
    .build()?;

示例输出

用户提示: "What is Rust?"

正式商业助手:

Rust 是一种专注于性能、内存安全和并发性的系统编程语言。关键指标:0 运行时开销,0 垃圾回收。企业采用率同比增长 30%。推荐用于对可靠性至关重要的性能关键型应用程序。

友好的编程导师:

好问题!🎉 Rust 是一种编程语言,可以帮助你编写快速且安全的代码。把它想象成一个乐于助人的朋友,在错误发生之前就阻止你!

这是一个简单的例子:
  let name = "Alice";  // 这会创建一个变量

Rust 的特别之处在于它在编译时捕获错误,而不是在你的程序运行时。很酷吧?想让我解释更多吗?

富有创意的讲故事者:

在 2010 年的暮色中,在 Mozilla 的一个秘密实验室里,一位名叫 Graydon Hoare 的孤独开发者为一种非凡的语言注入了生命——一种将挑战 C 和 C++ 等旧神的语言。

他们称之为 Rust,取名自一种在逆境中生存下来的真菌。就像凤凰从段错误和内存泄漏的灰烬中升起一样,Rust 承诺了一个新时代:不牺牲速度,不冒风险的力量。

于是,革命开始了...

指令模板化

指令支持使用 {var} 语法进行变量注入。变量在运行时从 session state 中解析:

let agent = LlmAgentBuilder::new("personalized")
    .instruction("您正在帮助 {user_name}。他们的角色是 {user_role}。请根据他们的专业水平调整您的回复。")
    .model(Arc::new(model))
    .build()?;

使用模板化的分步指南:

  1. 在 instruction 中使用模板变量创建 agent
  2. 设置 Runner 和 SessionService 来管理 state
  3. 创建具有与模板匹配的 state 变量的 session
  4. 运行 agent - 模板将自动替换

这是一个完整的可运行示例:

use adk_rust::prelude::*;
use adk_rust::runner::{Runner, RunnerConfig};
use adk_rust::session::{CreateRequest, InMemorySessionService, SessionService};
use adk_rust::futures::StreamExt;
use serde_json::json;
use std::collections::HashMap;
use std::sync::Arc;

#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
    dotenvy::dotenv().ok();
    let api_key = std::env::var("GOOGLE_API_KEY")?;
    let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;

    // 1. 带有模板化 instruction 的 Agent
    let agent = LlmAgentBuilder::new("personalized")
        .instruction("您正在帮助 {user_name}。他们的角色是 {user_role}。请根据他们的专业水平调整您的回复。")
        .model(Arc::new(model))
        .build()?;

    // 2. 创建 session service 和 runner
    let session_service = Arc::new(InMemorySessionService::new());
    let runner = Runner::new(RunnerConfig {
        app_name: "templating_demo".to_string(),
        agent: Arc::new(agent),
        session_service: session_service.clone(),
        artifact_service: None,
        memory_service: None,
        run_config: None,
    })?;

    // 3. 创建具有 state 变量的 session
    let mut state = HashMap::new();
    state.insert("user_name".to_string(), json!("Alice"));
    state.insert("user_role".to_string(), json!("Senior Developer"));

    let session = session_service.create(CreateRequest {
        app_name: "templating_demo".to_string(),
        user_id: "user123".to_string(),
        session_id: None,
        state,
    }).await?;

    // 4. 运行 agent - instruction 变为:
    // "You are helping Alice. Their role is Senior Developer..."
    let mut response_stream = runner.run(
        "user123".to_string(),
        session.id().to_string(),
        Content::new("user").with_text("Explain async/await in Rust"),
    ).await?;

    // 打印响应
    while let Some(event) = response_stream.next().await {
        let event = event?;
        if let Some(content) = event.content() {
            for part in &content.parts {
                if let Part::Text { text } = part {
                    print!("{}", text);
                }
            }
        }
    }

    Ok(())
}

模板变量类型:

模式示例来源
{var}{user_name}Session 状态
{prefix:var}{user:name}, {app:config}带前缀的状态
{var?}{user_name?}可选(如果缺失则为空)
{artifact.file}{artifact.resume.pdf}Artifact 内容

输出示例:

模板:"您正在帮助 {user_name}。他们的角色是 {user_role}。" 变为:"您正在帮助 Alice。他们的角色是 Senior Developer。"

然后,Agent 将根据用户的姓名和专业水平回复个性化内容!

添加工具

工具赋予您的 Agent 超越对话的能力——它们可以获取数据、执行计算、搜索网络或调用外部 API。LLM 根据用户的请求决定何时使用工具。

工具的工作原理

  1. Agent 接收用户消息 → "东京天气如何?"
  2. LLM 决定调用工具 → 选用 get_weather,参数为 {"city": "Tokyo"}
  3. 工具执行 → 返回 {"temperature": "22°C", "condition": "sunny"}
  4. LLM 格式化响应 → "东京的天气晴朗,气温 22°C。"

使用 FunctionTool 创建工具

FunctionTool 是创建工具最简单的方式——封装任何 async Rust 函数,LLM 即可调用它。您需要提供一个名称、描述和一个处理函数,该函数接收 JSON 参数并返回 JSON 结果。

let weather_tool = FunctionTool::new(
    "get_weather",                              // 工具名称(由 LLM 使用)
    "Get the current weather for a city",       // 描述(帮助 LLM 决定何时使用)
    |_ctx, args| async move {                   // 处理函数
        let city = args.get("city")             // 从 JSON 中提取参数
            .and_then(|v| v.as_str())
            .unwrap_or("unknown");
        Ok(json!({ "city": city, "temperature": "22°C" }))  // 返回 JSON 结果
    },
);

⚠️ 注意:当前限制GoogleSearchTool 等内置工具目前与同一 Agent 中的 FunctionTool 不兼容。请使用内置工具或自定义 FunctionTools,但不能同时使用两者。 💡 变通方法:创建单独的子 Agent,每个子 Agent 都有自己的工具类型,并通过主 LLMAgent、工作流 Agent 或多 Agent 模式进行协调。

构建一个多工具 Agent

创建一个新项目:

cargo new tool_agent
cd tool_agent

将依赖项添加到 Cargo.toml

[dependencies]
adk-rust = { version = "0.2.0", features = ["tools"] }
tokio = { version = "1.40", features = ["full"] }
dotenvy = "0.15"
serde_json = "1.0"

创建 .env 文件:

echo 'GOOGLE_API_KEY=your-api-key' > .env

src/main.rs 替换为一个包含三个工具的 Agent:

use adk_rust::prelude::*;
use adk_rust::Launcher;
use serde_json::json;
use std::sync::Arc;

#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
    dotenvy::dotenv().ok();
    let api_key = std::env::var("GOOGLE_API_KEY")?;
    let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;

    // 工具 1:天气查询
    let weather_tool = FunctionTool::new(
        "get_weather",
        "Get the current weather for a city. Parameters: city (string)",
        |_ctx, args| async move {
            let city = args.get("city").and_then(|v| v.as_str()).unwrap_or("unknown");
            Ok(json!({ "city": city, "temperature": "22°C", "condition": "sunny" }))
        },
    );

    // 工具 2:计算器
    let calculator = FunctionTool::new(
        "calculate",
        "Perform arithmetic. Parameters: a (number), b (number), operation (add/subtract/multiply/divide)",
        |_ctx, args| async move {
            let a = args.get("a").and_then(|v| v.as_f64()).unwrap_or(0.0);
            let b = args.get("b").and_then(|v| v.as_f64()).unwrap_or(0.0);
            let op = args.get("operation").and_then(|v| v.as_str()).unwrap_or("add");
            let result = match op {
                "add" => a + b,
                "subtract" => a - b,
                "multiply" => a * b,
                "divide" => if b != 0.0 { a / b } else { 0.0 },
                _ => 0.0,
            };
            Ok(json!({ "result": result }))
        },
    );

    // 工具 3:内置 Google 搜索(注意:ADK-Rust 目前不支持)
    // let search_tool = GoogleSearchTool::new();

    // 使用天气和计算器工具构建 Agent
    let agent = LlmAgentBuilder::new("multi_tool_agent")
        .instruction("You are a helpful assistant. Use tools when needed: \
                     - get_weather for weather questions \
                     - calculate for math")
        .model(Arc::new(model))
        .tool(Arc::new(weather_tool))
        .tool(Arc::new(calculator))
        // .tool(Arc::new(search_tool))  // 目前不支持
        .build()?;

    Launcher::new(Arc::new(agent)).run().await?;
    Ok(())
}

运行您的 Agent:

cargo run

交互示例

你:250 的 15% 是多少?
助手:[使用 calculate 工具,参数为 a=250, b=0.15, operation=multiply]
250 的 15% 是 37.5。

你:东京天气如何?
助手:[使用 get_weather 工具,参数为 city=Tokyo]
东京的天气晴朗,气温 22°C。

你:搜索最新的 Rust 功能
助手:我目前无法访问搜索功能,但我可以帮助您回答其他 Rust 相关问题或进行计算!

使用 JSON Schema 实现结构化输出

对于需要结构化数据的应用程序,请使用 output_schema()

use adk_rust::prelude::*;
use serde_json::json;
use std::sync::Arc;

#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
    dotenvy::dotenv().ok();
    let api_key = std::env::var("GOOGLE_API_KEY")?;
    let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;

    let extractor = LlmAgentBuilder::new("entity_extractor")
        .instruction("Extract entities from the given text.")
        .model(Arc::new(model))
        .output_schema(json!({
            "type": "object",
            "properties": {
                "people": {
                    "type": "array",
                    "items": { "type": "string" }
                },
                "locations": {
                    "type": "array",
                    "items": { "type": "string" }
                },
                "dates": {
                    "type": "array",
                    "items": { "type": "string" }
                }
            },
            "required": ["people", "locations", "dates"]
        }))
        .build()?;

    println!("Entity extractor ready!");
    Ok(())
}

JSON 输出示例

输入: "John met Sarah in Paris on December 25th"

输出:

{
  "people": ["John", "Sarah"],
  "locations": ["Paris"],
  "dates": ["December 25th"]
}

高级功能

Include Contents

控制对话历史记录可见性:

// Full history (default)
.include_contents(IncludeContents::Default)

// Stateless - only sees current input
.include_contents(IncludeContents::None)

Output Key

将 agent 响应保存到 session 状态:

.output_key("summary")  // Response saved to state["summary"]

动态指令

在运行时计算指令:

.instruction_provider(|ctx| {
    Box::pin(async move {
        let user_id = ctx.user_id();
        Ok(format!("You are assisting user {}.", user_id))
    })
})

Callbacks

拦截 agent 行为:

.before_model_callback(|ctx, request| {
    Box::pin(async move {
        println!("About to call LLM with {} messages", request.contents.len());
        Ok(BeforeModelResult::Continue)
    })
})

Builder 参考

方法描述
new(name)使用 agent 名称创建 builder
model(Arc<dyn Llm>)设置 LLM (必需)
description(text)Agent 描述
instruction(text)系统提示
tool(Arc<dyn Tool>)添加一个 Tool
output_schema(json)用于结构化输出的 JSON schema
output_key(key)将响应保存到 state
include_contents(mode)历史记录可见性
build()创建 agent

完整示例

一个生产就绪的 agent,带有多个工具(天气、计算器、搜索),输出结果保存到 session state:

use adk_rust::prelude::*;
use adk_rust::Launcher;
use serde_json::json;
use std::sync::Arc;

#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
    dotenvy::dotenv().ok();
    let api_key = std::env::var("GOOGLE_API_KEY")?;
    let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;

    // Weather tool
    let weather = FunctionTool::new(
        "get_weather",
        "Get weather for a city. Parameters: city (string)",
        |_ctx, args| async move {
            let city = args.get("city").and_then(|v| v.as_str()).unwrap_or("unknown");
            Ok(json!({
                "city": city,
                "temperature": "22°C",
                "humidity": "65%",
                "condition": "partly cloudy"
            }))
        },
    );

    // Calculator tool
    let calc = FunctionTool::new(
        "calculate",
        "Math operations. Parameters: expression (string like '2 + 2')",
        |_ctx, args| async move {
            let expr = args.get("expression").and_then(|v| v.as_str()).unwrap_or("0");
            Ok(json!({ "expression": expr, "result": "computed" }))
        },
    );

    // Build the full agent
    let agent = LlmAgentBuilder::new("assistant")
        .description("A helpful assistant with weather and calculation abilities")
        .instruction("You are a helpful assistant. \
                     Use the weather tool for weather questions. \
                     Use the calculator for math. \
                     Be concise and friendly.")
        .model(Arc::new(model))
        .tool(Arc::new(weather))
        .tool(Arc::new(calc))
        // .tool(Arc::new(GoogleSearchTool::new()))  // Currently unsupported with FunctionTool
        .output_key("last_response")
        .build()?;

    println!("✅ Agent '{}' ready!", agent.name());
    Launcher::new(Arc::new(agent)).run().await?;
    Ok(())
}

尝试这些提示:

You: What's 25 times 4?
Assistant: It's 100.

You: How's the weather in New York?
Assistant: The weather in New York is partly cloudy with a temperature of 22°C and 65% humidity.

You: Calculate 15% tip on $85
Assistant: A 15% tip on $85 is $12.75, making the total $97.75.

相关


上一页: 快速入门 | 下一页: 工作流 Agents →