LlmAgent

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

Schnellstart

Erstellen Sie ein neues Projekt:

cargo new llm_agent
cd llm_agent

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

[dependencies]
adk-rust = "0.2.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::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(())
}

Führen Sie es aus:

cargo run

Interaktion mit Ihrem Agent

Sie sehen eine interaktive Eingabeaufforderung:

🤖 Agent bereit! Geben Sie Ihre Fragen ein (oder 'exit' zum Beenden).

You: Hallo! Wobei können Sie mir helfen?
Assistant: Hallo! Ich bin ein hilfreicher Assistent. Ich kann Ihnen helfen bei:
- Beantwortung von Fragen zu verschiedenen Themen
- Klare Erklärungen von Konzepten
- Eine Unterhaltung führen

Was möchten Sie wissen?

You: exit
👋 Auf Wiedersehen!

Agent-Verhalten mit Anweisungen gestalten

Die instruction()-Methode definiert die Persönlichkeit und das Verhalten Ihres Agent. Dies ist der system prompt, der jede Antwort leitet:

// 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: "What is 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 Programmier-Tutor:

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...

Anweisungs-Templating

Anweisungen unterstützen die Variablen-Injektion mittels der {var}-Syntax. Variablen werden zur Laufzeit aus dem Session state 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 Templating:

  1. Erstellen Sie den Agent mit Template-Variablen in der Anweisung
  2. Richten Sie Runner und SessionService ein, um den Zustand zu verwalten
  3. Erstellen Sie eine Session mit State-Variablen, die Ihrem Template entsprechen
  4. Führen Sie den Agent aus – Templates werden automatisch ersetzt

Hier ist ein vollständiges, funktionierendes Beispiel:

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. 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(
        "user123".to_string(),
        session.id().to_string(),
        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(())
}

Template-Variablentypen:

MusterBeispielQuelle
{var}{user_name}Sitzungszustand
{prefix:var}{user:name}, {app:config}Zustand mit Präfix
{var?}{user_name?}Optional (leer, falls fehlend)
{artifact.file}{artifact.resume.pdf}Inhalt des Artifact

Ausgabebeispiel:

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

Der Agent wird dann mit personalisierten Inhalten antworten, basierend auf dem Namen und dem Fachwissen des Benutzers!


Tools hinzufügen

Tools verleihen Ihrem Agenten Fähigkeiten, die über die Konversation hinausgehen – sie können Daten abrufen, Berechnungen durchführen, das Web durchsuchen oder externe APIs aufrufen. Das LLM entscheidet basierend auf der Benutzeranfrage, wann ein Tool verwendet werden soll.

Wie Tools funktionieren

  1. Agent empfängt Benutzernachricht → "Wie ist das Wetter in Tokio?"
  2. LLM entscheidet sich für Tool-Aufruf → Wählt get_weather mit {"city": "Tokyo"}
  3. Tool wird ausgeführt → Gibt {"temperature": "22°C", "condition": "sunny"} zurück
  4. LLM formatiert Antwort → "Das Wetter in Tokio ist sonnig bei 22°C."

Ein Tool mit FunctionTool erstellen

FunctionTool ist der einfachste Weg, ein Tool zu erstellen – umwickeln Sie jede async Rust-Funktion, und das LLM kann sie aufrufen. Sie stellen einen Namen, eine Beschreibung und eine Handler-Funktion bereit, 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
    },
);

⚠️ Hinweis: Aktuelle Einschränkung: Integrierte Tools wie GoogleSearchTool sind derzeit inkompatibel mit FunctionTool im selben Agenten. Verwenden Sie entweder integrierte Tools ODER benutzerdefinierte FunctionTools, aber nicht beides zusammen. 💡 Workaround: Erstellen Sie separate Subagenten, jeder mit seinem eigenen Tool-Typ, und koordinieren Sie diese mithilfe eines Master-LLMAgenten, Workflow-Agenten oder Multi-Agenten-Mustern.

Einen Multi-Tool Agenten bauen

Erstellen Sie ein neues Projekt:

cargo new tool_agent
cd tool_agent

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

[dependencies]
adk-rust = { version = "0.2.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, der drei Tools hat:

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

    // 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 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-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-Ausgabebeispiel

Eingabe: "John met Sarah in Paris on December 25th"

Ausgabe:

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

Erweiterte Funktionen

Inhalte einbeziehen

Steuern Sie die Sichtbarkeit des Konversationsverlaufs:

// Vollständiger Verlauf (Standard)
.include_contents(IncludeContents::Default)

// Zustandsfrei - sieht nur die aktuelle Eingabe
.include_contents(IncludeContents::None)

Ausgabeschlüssel

Speichern Sie Agent-Antworten im Session-Zustand:

.output_key("summary")  // Antwort wird in state["summary"] gespeichert

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ückrufe (Callbacks)

Fangen Sie das Verhalten des Agenten 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 Builder mit Agent-Namen
model(Arc<dyn Llm>)Setzt das LLM (erforderlich)
description(text)Agent-Beschreibung
instruction(text)System-Prompt
tool(Arc<dyn Tool>)Fügt ein Tool hinzu
output_schema(json)JSON-Schema für strukturierte Ausgabe
output_key(key)Speichert die Antwort im Zustand
include_contents(mode)Sichtbarkeit des Verlaufs
build()Erstellt den Agenten

Vollständiges Beispiel

Ein produktionsbereiter Agent mit mehreren Tools (Wetter, Rechner, Suche) und in den Session-Zustand gespeicherter Ausgabe:

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(())
}

Probieren Sie diese Prompts aus:

Sie: Was ist 25 mal 4?
Assistant: Es ist 100.

Sie: Wie ist das Wetter in New York?
Assistant: Das Wetter in New York ist teilweise bewölkt mit einer Temperatur von 22°C und 65% Luftfeuchtigkeit.

Sie: Berechne 15% Trinkgeld auf $85
Assistant: 15% Trinkgeld auf $85 sind $12.75, was insgesamt $97.75 ergibt.

Verwandt


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