LlmAgent

Der LlmAgent ist der zentrale Agententyp in ADK-Rust, der ein großes Sprachmodell für Schlussfolgerungen und Entscheidungsfindung verwendet.

Schnellstart

Erstellen Sie ein neues Projekt:

cargo new llm_agent
cd llm_agent

Fügen Sie Cargo.toml Abhängigkeiten hinzu:

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

Erstellen Sie .env mit Ihrem API-Schlüssel:

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

Ersetzen Sie src/main.rs:

use adk_rust::prelude::*;
use adk_rust::{SessionId, UserId};
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-3.7-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(())
}

Führen Sie es aus:

cargo run

Mit Ihrem Agenten interagieren

Sie sehen eine interaktive Eingabeaufforderung:

🤖 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!

Agentenverhalten mit Anweisungen gestalten

Die Methode instruction() definiert die Persönlichkeit und das Verhalten Ihres Agenten. Dies ist der System-Prompt, der jede Antwort steuert:

// A formal business assistant
let formal_agent = LlmAgentBuilder::new("formal_assistant")
    .instruction("You are a professional business consultant. \
                 Use formal language. Be concise and data-driven.")
    .model(Arc::new(model))
    .build()?;

// A friendly coding tutor
let tutor_agent = LlmAgentBuilder::new("code_tutor")
    .instruction("You are a friendly coding tutor for beginners. \
                 Explain concepts simply. Use examples. \
                 Encourage questions. Never make the user feel bad for not knowing.")
    .model(Arc::new(model))
    .build()?;

// A creative storyteller
let story_agent = LlmAgentBuilder::new("storyteller")
    .instruction("You are a creative storyteller. \
                 Craft engaging narratives with vivid descriptions. \
                 Use plot twists and memorable characters.")
    .model(Arc::new(model))
    .build()?;

Beispielausgaben

Benutzer-Prompt: „Was ist Rust?“

Formeller Geschäftsassistent:

Rust is a systems programming language focused on performance, memory safety, 
and concurrency. Key metrics: 0 runtime overhead, 0 garbage collection. 
Adoption growing 30% YoY in enterprise. Recommended for performance-critical 
applications where reliability is paramount.

Freundlicher Programmierlehrer:

Great question! 🎉 Rust is a programming language that helps you write fast 
and safe code. Think of it like a helpful friend who stops you from making 
mistakes before they happen!

Here's a simple example:
  let name = "Alice";  // This creates a variable

What makes Rust special is that it catches bugs at compile time, not when 
your program is running. Pretty cool, right? Want me to explain more?

Kreativer Geschichtenerzähler:

In the twilight of 2010, in a secret Mozilla laboratory, a lone developer 
named Graydon Hoare breathed life into something extraordinary—a language 
that would challenge the old gods of C and C++.

They called it Rust, named for a fungus that survives against all odds. 
Like a phoenix rising from the ashes of segmentation faults and memory 
leaks, Rust promised a new era: speed without sacrifice, power without peril.

And so, the revolution began...

Anweisungsvorlagen

Anweisungen unterstützen die Variableninjektion mithilfe der Syntax {var}. Variablen werden zur Laufzeit aus dem Sitzungsstatus aufgelöst:

let agent = LlmAgentBuilder::new("personalized")
    .instruction("You are helping {user_name}. Their role is {user_role}. \
                 Tailor your responses to their expertise level.")
    .model(Arc::new(model))
    .build()?;

Schritt-für-Schritt-Anleitung zur Verwendung von Vorlagen:

  1. Erstellen Sie den Agenten mit Vorlagenvariablen in der Anweisung
  2. Richten Sie Runner und SessionService ein, um den Status zu verwalten
  3. Erstellen Sie eine Sitzung mit Statusvariablen, die Ihrer Vorlage entsprechen
  4. Führen Sie den Agenten aus – Vorlagen werden automatisch ersetzt

Hier ist ein vollständiges, funktionierendes Beispiel:

use adk_rust::prelude::*;
use adk_rust::{SessionId, UserId};
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-3.7-flash")?;

    // 1. Agent with templated instruction
    let agent = LlmAgentBuilder::new("personalized")
        .instruction("You are helping {user_name}. Their role is {user_role}. \
                     Tailor your responses to their expertise level.")
        .model(Arc::new(model))
        .build()?;

    // 2. Create session service and 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. Create session with state variables
    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. Run the agent - instruction becomes:
    // "You are helping Alice. Their role is Senior Developer..."
    let mut response_stream = runner.run(
        UserId::new("user123")?,
        SessionId::new(session.id())?,
        Content::new("user").with_text("Explain async/await in Rust"),
    ).await?;

    // Print the response
    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(())
}

Typen von Vorlagenvariablen:

MusterBeispielQuelle
{var}{user_name}Sitzungsstatus
{prefix:var}{user:name}, {app:config}Status mit Präfix
{var?}{user_name?}Optional (leer, falls nicht vorhanden)
{artifact.file}{artifact.resume.pdf}Artefaktinhalt

Ausgabebeispiel:

Vorlage: "You are helping {user_name}. Their role is {user_role}."
Wird zu: "You are helping Alice. Their role is Senior Developer."

Der Agent antwortet anschließend mit personalisierten Inhalten, die auf dem Namen und dem Kenntnisstand des Benutzers basieren!


Hinzufügen von Tools

Tools verleihen Ihrem Agenten Fähigkeiten, die über die Unterhaltung hinausgehen – sie können Daten abrufen, Berechnungen durchführen, das Web durchsuchen oder externe APIs aufrufen. LLM entscheidet anhand der Anfrage des Benutzers, wann ein Tool verwendet werden soll.

Funktionsweise von Tools

  1. Der Agent empfängt die Nachricht des Benutzers → „Wie ist das Wetter in Tokio?“
  2. LLM entscheidet sich, ein Tool aufzurufen → Wählt get_weather mit {"city": "Tokyo"} aus
  3. Das Tool wird ausgeführt → Gibt {"temperature": "22°C", "condition": "sunny"} zurück
  4. LLM formatiert die Antwort → „Das Wetter in Tokio ist sonnig bei 22 °C.“

Erstellen eines Tools mit FunctionTool

FunctionTool ist die einfachste Möglichkeit, ein Tool zu erstellen – umschließen Sie eine beliebige asynchrone Rust-Funktion, und LLM kann sie aufrufen. Sie geben einen Namen, eine Beschreibung und eine Handler-Funktion an, die JSON-Argumente empfängt und ein JSON-Ergebnis zurückgibt.

let weather_tool = FunctionTool::new(
    "get_weather",                              // Tool name (used by LLM)
    "Get the current weather for a city",       // Description (helps LLM decide when to use it)
    |_ctx, args| async move {                   // Handler function
        let city = args.get("city")             // Extract arguments from JSON
            .and_then(|v| v.as_str())
            .unwrap_or("unknown");
        Ok(json!({ "city": city, "temperature": "22°C" }))  // Return JSON result
    },
);

Integrierte, anbieterspezifische Tools können jetzt mit FunctionTool-Instanzen im selben Agenten kombiniert werden. ADK leitet die Deklarationen der nativen Tools an den Anbieter weiter, während gewöhnliche Funktionstools weiterhin lokal ausgeführt werden.

Erstellen eines Agenten mit mehreren Tools

Erstellen Sie ein neues Projekt:

cargo new tool_agent
cd tool_agent

Fügen Sie Cargo.toml Abhängigkeiten hinzu:

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

Erstellen Sie .env:

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

Ersetzen Sie src/main.rs durch einen Agenten mit drei Tools:

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-3.7-flash")?;

    // Tool 1: Weather lookup
    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" }))
        },
    );

    // Tool 2: Calculator
    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 }))
        },
    );

    // Tool 3: Built-in Google Search (Note: Currently unsupported in ADK-Rust)
    // let search_tool = GoogleSearchTool::new();

    // Build agent with weather and calculator tools
    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))  // Currently unsupported
        .build()?;

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

Führen Sie Ihren Agenten aus:

cargo run

Beispielinteraktion

You: What's 15% of 250?
Assistant: [Using calculate tool with a=250, b=0.15, operation=multiply]
15% of 250 is 37.5.

You: What's the weather in Tokyo?
Assistant: [Using get_weather tool with city=Tokyo]
The weather in Tokyo is sunny with a temperature of 22°C.

You: Search for latest Rust features
Assistant: I don't have access to search functionality at the moment, but I can help with other questions about Rust or perform calculations!

Strukturierte Ausgabe mit dem JSON-Schema

Für Anwendungen, die strukturierte Daten benötigen, verwenden Sie 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-3.7-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(())
}

Wie Anbieter das Schema erzwingen

output_schema erreicht den Anbieter als GenerateContentConfig::response_schema. Wie der Anbieter damit umgeht, ist unterschiedlich; der Agent validiert das Ergebnis jedoch in jedem Fall:

AnbieterNative Durchsetzung
GeminiVollständiges Schema, als Antwortschema gesendet
OpenAI und mit OpenAI kompatibelVollständiges Schema, als striktes json_schema-Antwortformat gesendet
OpenRouterVollständiges Schema
DeepSeekJSON Syntax only — der JSON-Ausgabemodus von DeepSeek hat keine json_schema-Variante, daher wird das Schema durch die Validierung des Agenten erzwungen

Wenn ein Anbieter nur die Syntax oder überhaupt nichts erzwingt, fügt der Agent das Schema weiterhin als Anweisung ein und validiert die Antwort. Eine nicht konforme Antwort führt daher zu einem erneuten Versuch, statt fehlerhafte Daten zurückzugeben.

Hinweis: DeepSeek erfordert, dass das Wort „json“ in der Eingabeaufforderung vorkommt, wenn JSON Output aktiviert ist, andernfalls kann API leeren Inhalt zurückgeben. Der Adapter fügt diesen Hinweis selbst hinzu, wenn er in Ihrer Eingabeaufforderung noch nicht enthalten ist.

Beispiel für JSON Output

Eingabe: „John traf Sarah am 25. Dezember in Paris“

Ausgabe:

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

Erweiterte Funktionen

Inhalte einbeziehen

Steuern Sie die Sichtbarkeit des Gesprächsverlaufs:

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

// Stateless - sees only injected instructions plus the current user turn
.include_contents(IncludeContents::None)

Ausgabeschlüssel

Speichern Sie Agentenantworten im Sitzungsstatus:

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

Dynamische Anweisungen

Berechnen Sie Anweisungen zur Laufzeit:

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

Rückruffunktionen

Fangen Sie das Verhalten des Agents ab:

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

Builder-Referenz

MethodeBeschreibung
new(name)Erstellt einen Builder mit Agentennamen
model(Arc<dyn Llm>)Legt die LLM fest (erforderlich)
description(text)Agentenbeschreibung
instruction(text)Systemaufforderung
tool(Arc<dyn Tool>)Fügt ein statisches Tool hinzu
toolset(Arc<dyn Toolset>)Fügt ein dynamisch aufgelöstes Toolset pro Aufruf hinzu
output_schema(json)JSON-Schema für strukturierte Ausgabe
output_key(key)Speichert die Antwort im Zustand
include_contents(mode)Sichtbarkeit des Verlaufs
max_iterations(n)Maximale Anzahl von LLM-Roundtrips (Standard: 100)
tool_execution_strategy(strategy)Tool-Versandmodus: Sequential, Parallel oder Auto
default_retry_budget(RetryBudget)Fehlgeschlagene Tools bis zu N-mal mit Verzögerung erneut ausführen
tool_retry_budget(name, RetryBudget)Überschreibung der Wiederholungsversuche pro Tool
circuit_breaker_threshold(u32)Tool nach N aufeinanderfolgenden Fehlern deaktivieren
on_tool_error(callback)Registriert einen Fallback-Handler für Tool-Fehler
after_tool_callback_full(callback)Umfangreicher V2-Callback nach der Tool-Ausführung mit Tool, Argumenten und Antwort
build()Erstellt den Agenten

Iterationssteuerung

Die Methode max_iterations() begrenzt, wie viele LLM-Round-Trips ein Agent durchführen kann, bevor er stoppt. Dies ist nützlich für:

  • Das Verhindern von Endlosschleifen bei Tool-Aufrufen
  • Die Kostenkontrolle in Produktionsumgebungen
  • Das Festlegen angemessener Grenzen für komplexe Aufgaben
let agent = LlmAgentBuilder::new("bounded_agent")
    .model(Arc::new(model))
    .instruction("You are a helpful assistant.")
    .tool(Arc::new(my_tool))
    .max_iterations(10)  // Stop after 10 LLM calls
    .build()?;

Der Standardwert beträgt 100 Iterationen, was für die meisten Anwendungsfälle ausreicht. Für einfache Frage-und-Antwort-Agenten werden niedrigere Werte (5–20) empfohlen, während für komplexe mehrstufige Reasoning-Aufgaben möglicherweise höhere Werte erforderlich sind.


Dynamische Toolsets

Für Tools, die vom Aufrufkontext abhängen (z. B. Browser-Sitzungen pro Benutzer), verwenden Sie .toolset() anstelle von .tool(). Toolsets werden am Anfang jedes run()-Aufrufs aufgelöst:

use adk_browser::{BrowserSessionPool, BrowserToolset, BrowserConfig};
use adk_agent::LlmAgentBuilder;
use std::sync::Arc;

let pool = Arc::new(BrowserSessionPool::new(BrowserConfig::new(), 10));
let toolset = Arc::new(BrowserToolset::with_pool(pool));

let agent = LlmAgentBuilder::new("web_agent")
    .model(model)
    .instruction("You are a web automation assistant.")
    .toolset(toolset)  // Resolved per-user at runtime
    .build()?;

Sie können statische .tool() und dynamische .toolset() im selben Agenten kombinieren. Doppelte Toolnamen in statischen Tools und Toolsets führen zu einem deterministischen Fehler.

RealtimeAgentBuilder unterstützt ebenfalls .toolset() mit derselben Semantik, sodass Echtzeit-Sprachagenten ebenfalls eine dynamische Toolauflösung erhalten.

Toolset-Komposition

Verwenden Sie FilteredToolset, MergedToolset und PrefixedToolset aus adk-tool, um komplexe Toolset-Konfigurationen zusammenzusetzen:

use adk_tool::{BasicToolset, FilteredToolset, MergedToolset, PrefixedToolset, string_predicate};

// Prefix weather tools to avoid name collisions
let weather = Arc::new(PrefixedToolset::new(weather_toolset, "wx"));

// Filter utility tools to only expose search and calculate
let utils = Arc::new(FilteredToolset::new(
    utility_toolset,
    string_predicate(vec!["search".into(), "calculate".into()]),
));

// Merge into a single toolset
let composed = MergedToolset::new("all", vec![weather, utils]);

let agent = LlmAgentBuilder::new("agent")
    .model(model)
    .toolset(Arc::new(composed))
    .build()?;

Alle Kompositionsdienstprogramme funktionieren mit jeder Toolset-Implementierung, einschließlich McpToolset und BrowserToolset.

Parallele Tool-Ausführung

Wenn ein LLM mehrere Tool-Aufrufe in einer einzigen Antwort zurückgibt, können Sie steuern, wie diese ausgeführt werden:

use adk_core::ToolExecutionStrategy;

let agent = LlmAgentBuilder::new("fast_agent")
    .model(Arc::new(model))
    .instruction("You are a research assistant. Use multiple tools in parallel.")
    // Auto requires both safety signals for concurrent inclusion
    .tool_execution_strategy(ToolExecutionStrategy::Auto)
    .tool(Arc::new(
        search_tool
            .with_read_only(true)
            .with_concurrency_safe(true),
    ))
    .tool(Arc::new(
        lookup_tool
            .with_read_only(true)
            .with_concurrency_safe(true),
    ))
    .tool(Arc::new(save_tool)) // runs after the concurrent safe subset
    .build()?;

Es stehen drei Strategien zur Verfügung:

  • Sequential (Standard) — Tools werden nacheinander in der Reihenfolge LLM ausgeführt
  • Parallel — Alle Tools werden gleichzeitig ausgeführt; diese explizite Überschreibung umgeht Sicherheitsmetadaten, daher liegt die Verantwortung für die Sicherheit beim Aufrufer
  • Auto — Aufrufe, deren Tools sowohl schreibgeschützt als auch nebenläufigkeitssicher sind, werden zuerst gleichzeitig ausgeführt; alle übrigen Aufrufe werden anschließend sequenziell ausgeführt

Ergebnisse werden unabhängig von der Strategie immer in der ursprünglichen LLM-Reihenfolge zurückgegeben. Fehlgeschlagene Tools erzeugen eine JSON-Fehlerantwort, ohne den Batch abzubrechen.

Die Strategie wird pro Agent über LlmAgentBuilder::tool_execution_strategy() festgelegt. Wenn sie nicht festgelegt ist, wird standardmäßig Sequential verwendet.

Tool-Resilienz

Konfigurieren Sie für Produktionsagenten Wiederholungsbudgets und Circuit Breaker:

use adk_core::RetryBudget;
use std::time::Duration;

let agent = LlmAgentBuilder::new("resilient_agent")
    .model(model)
    .tool(Arc::new(my_tool))
    // Retry all tools up to 2 times with 500ms delay
    .default_retry_budget(RetryBudget::new(2, Duration::from_millis(500)))
    // Override for a specific tool
    .tool_retry_budget("flaky_api", RetryBudget::new(4, Duration::from_secs(1)))
    // Disable a tool after 3 consecutive failures in one invocation
    .circuit_breaker_threshold(3)
    // Provide a fallback when a tool fails
    .on_tool_error(Box::new(|_ctx, tool, _args, error| {
        Box::pin(async move {
            tracing::warn!(tool = tool.name(), %error, "tool failed");
            Ok(None) // None = propagate error; Some(value) = use as fallback
        })
    }))
    .build()?;

Callbacks nach der Tool-Ausführung können strukturierte ToolOutcome-Metadaten über CallbackContext::tool_outcome() untersuchen:

.after_tool_callback(Box::new(|ctx| {
    Box::pin(async move {
        if let Some(outcome) = ctx.tool_outcome() {
            println!(
                "Tool '{}' {} in {:?} (attempt {})",
                outcome.tool_name,
                if outcome.success { "succeeded" } else { "failed" },
                outcome.duration,
                outcome.attempt,
            );
        }
        Ok(None)
    })
}))

Vollständiges Beispiel

Ein produktionsbereiter Agent mit mehreren Tools (Wetter, Taschenrechner, Suche), dessen Ausgabe im Sitzungsstatus gespeichert wird:

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-3.7-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()))  // Provider-native tools can be mixed with FunctionTool
        .output_key("last_response")
        .build()?;

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

Probieren Sie diese Prompts aus:

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.


Zurück: Schnellstart | Weiter: Workflow-Agenten →

LlmAgent - ADK-Rust Dokumentation | ADK-Rust