LlmAgent

LlmAgent, ADK-Rust में मुख्य एजेंट प्रकार है जो तर्क-वितर्क और निर्णय लेने के लिए एक Large Language Model का उपयोग करता है।

त्वरित शुरुआत

एक नया प्रोजेक्ट बनाएं:

cargo new llm_agent
cd llm_agent

Cargo.toml में dependencies जोड़ें:

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

अपने API key के साथ .env बनाएं:

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

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

अपने एजेंट के साथ इंटरैक्ट करना

आपको एक interactive prompt दिखाई देगा:

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

निर्देशों के साथ एजेंट के व्यवहार को आकार देना

instruction() method आपके एजेंट की personality और behavior को परिभाषित करता है। यह वह system prompt है जो हर response को मार्गदर्शन देता है:

// 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()?;

उदाहरण आउटपुट

User prompt: "Rust क्या है?"

Formal Business Assistant:

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.

Friendly Coding 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?

Creative Storyteller:

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

निर्देश टेम्प्लेटिंग

निर्देश {var} syntax का उपयोग करके variable injection का समर्थन करते हैं। Variables runtime पर session state से resolve किए जाते हैं:

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

टेम्प्लेटिंग का उपयोग करने के लिए चरण-दर-चरण मार्गदर्शिका:

  1. एजेंट बनाएं जिसमें instruction में template variables हों
  2. Runner और SessionService सेट अप करें ताकि state को manage किया जा सके
  3. State variables के साथ session बनाएं जो आपके template से मेल खाते हों
  4. एजेंट चलाएं - templates स्वतः replace हो जाते हैं

यहाँ एक पूर्ण working example है:

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

टेम्पलेट वेरिएबल प्रकार:

पैटर्नउदाहरणस्रोत
{var}{user_name}सत्र स्थिति
{prefix:var}{user:name}, {app:config}उपसर्गित स्थिति
{var?}{user_name?}वैकल्पिक (यदि अनुपस्थित हो तो खाली)
{artifact.file}{artifact.resume.pdf}आर्टिफैक्ट सामग्री

आउटपुट उदाहरण:

Template: "You are helping {user_name}. Their role is {user_role}."
बनता है: "You are helping Alice. Their role is Senior Developer."

एजेंट तब उपयोगकर्ता के नाम और विशेषज्ञता स्तर के आधार पर वैयक्तिकृत सामग्री के साथ उत्तर देगा!


टूल्स जोड़ना

टूल्स आपके एजेंट को बातचीत से परे क्षमताएँ देते हैं—वे डेटा ला सकते हैं, गणनाएँ कर सकते हैं, वेब खोज सकते हैं, या बाहरी APIs को कॉल कर सकते हैं। LLM उपयोगकर्ता के अनुरोध के आधार पर तय करता है कि टूल कब उपयोग करना है।

टूल्स कैसे काम करते हैं

  1. एजेंट उपयोगकर्ता संदेश प्राप्त करता है → "टोक्यो में मौसम कैसा है?"
  2. LLM टूल कॉल करने का निर्णय लेता हैget_weather को {"city": "Tokyo"} के साथ चुनता है
  3. टूल निष्पादित होता है{"temperature": "22°C", "condition": "sunny"} लौटाता है
  4. LLM उत्तर को स्वरूपित करता है → "टोक्यो में मौसम 22°C पर धूप वाला है।"

FunctionTool के साथ टूल बनाना

FunctionTool टूल बनाने का सबसे सरल तरीका है—किसी भी async Rust function को wrap करें और LLM उसे कॉल कर सकता है। आप एक नाम, विवरण, और handler function प्रदान करते हैं जो JSON arguments प्राप्त करता है और एक JSON result लौटाता है।

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
    },
);

अंतर्निर्मित provider-native tools अब उसी एजेंट में FunctionTool instances के साथ मिश्रित किए जा सकते हैं। ADK native tool declarations को provider तक forward करता है, जबकि ordinary function tools को local रूप से निष्पादित करता रहता है।

बहु-टूल एजेंट बनाना

एक नया प्रोजेक्ट बनाएं:

cargo new tool_agent
cd tool_agent

Cargo.toml में dependencies जोड़ें:

[dependencies]
adk-rust = { version = "2.0.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 को ऐसे एजेंट से बदलें जिसमें तीन 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-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(())
}

अपना एजेंट चलाएं:

cargo run

उदाहरण इंटरैक्शन

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!

JSON Schema के साथ संरचित आउटपुट

जिन applications को संरचित डेटा की आवश्यकता होती है, उनके लिए 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(())
}

प्रदाता Schema को कैसे लागू करते हैं

output_schema GenerateContentConfig::response_schema के रूप में provider तक पहुँचता है। provider उसके साथ क्या करता है, यह अलग-अलग हो सकता है, और एजेंट परिणाम को दोनों ही स्थितियों में validate करता है:

प्रदातामूल प्रवर्तन
Geminiपूर्ण स्कीमा, जिसे प्रतिक्रिया स्कीमा के रूप में भेजा जाता है
OpenAI और OpenAI-संगतपूर्ण स्कीमा, जिसे एक सख्त json_schema प्रतिक्रिया प्रारूप के रूप में भेजा जाता है
OpenRouterपूर्ण स्कीमा
DeepSeekJSON सिंटैक्स केवल — DeepSeek's JSON आउटपुट मोड में कोई json_schema संस्करण नहीं है, इसलिए स्कीमा एजेंट के सत्यापन द्वारा लागू किया जाता है

जब कोई provider केवल syntax लागू करता है, या बिल्कुल भी नहीं करता, तब भी agent schema को instruction के रूप में inject करता है और reply को validate करता है, इसलिए non-conforming उत्तर bad data लौटाने के बजाय retry का cost देता है।

नोट: DeepSeek को prompt में "json" शब्द दिखाई देना आवश्यक है जब भी JSON Output on हो, अन्यथा API empty content लौटा सकता है। Adapter यह mention खुद जोड़ देता है जब आपका prompt पहले से इसे शामिल नहीं करता।

JSON आउटपुट उदाहरण

इनपुट: "John met Sarah in Paris on December 25th"

आउटपुट:

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

उन्नत सुविधाएँ

सामग्री शामिल करें

conversation history की visibility नियंत्रित करें:

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

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

आउटपुट कुंजी

agent responses को session state में सहेजें:

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

गतिशील निर्देश

runtime पर instructions compute करें:

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

callbacks

agent behavior को intercept करें:

.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)एजेंट नाम के साथ बिल्डर बनाता है
model(Arc<dyn Llm>)LLM को सेट करता है (आवश्यक)
description(text)एजेंट विवरण
instruction(text)सिस्टम प्रॉम्प्ट
tool(Arc<dyn Tool>)एक स्थिर टूल जोड़ता है
toolset(Arc<dyn Toolset>)प्रत्येक invocation पर हल होने वाला एक गतिशील टूलसेट जोड़ता है
output_schema(json)संरचित आउटपुट के लिए JSON schema
output_key(key)प्रतिक्रिया को state में सहेजता है
include_contents(mode)इतिहास की दृश्यता
max_iterations(n)अधिकतम LLM round-trips (default: 100)
tool_execution_strategy(strategy)टूल डिस्पैच मोड: Sequential, Parallel, या Auto
default_retry_budget(RetryBudget)विफल टूल्स को देरी के साथ N बार तक पुनः प्रयास करें
tool_retry_budget(name, RetryBudget)प्रति-टूल पुनः प्रयास ओवरराइड
circuit_breaker_threshold(u32)N लगातार विफलताओं के बाद टूल को अक्षम करें
on_tool_error(callback)टूल विफलताओं के लिए फ़ॉलबैक हैंडलर पंजीकृत करें
after_tool_callback_full(callback)टूल, args, और response के साथ V2 समृद्ध after-tool कॉलबैक
build()एजेंट बनाता है

पुनरावृत्ति नियंत्रण

max_iterations() विधि यह सीमित करती है कि कोई एजेंट रुकने से पहले कितनी LLM राउंड-ट्रिप कर सकता है। यह निम्न के लिए उपयोगी है:

  • अनियंत्रित टूल-कॉलिंग लूप्स को रोकना
  • उत्पादन में लागत नियंत्रित करना
  • जटिल कार्यों के लिए उचित सीमाएँ निर्धारित करना
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()?;

डिफ़ॉल्ट 100 पुनरावृत्तियाँ है, जो अधिकांश उपयोग मामलों के लिए पर्याप्त है। सरल Q&A एजेंटों के लिए कम मान (5-20) अनुशंसित हैं, जबकि जटिल बहु-चरणीय तर्क कार्यों के लिए अधिक मानों की आवश्यकता हो सकती है।


डायनेमिक टूलसेट्स

उन टूलों के लिए जो इनवोकेशन संदर्भ पर निर्भर करते हैं (जैसे, प्रति-उपयोगकर्ता ब्राउज़र सत्र), .tool() के बजाय .toolset() का उपयोग करें। टूलसेट्स का समाधान प्रत्येक run() कॉल की शुरुआत में किया जाता है:

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

आप एक ही एजेंट पर स्थिर .tool() और डायनेमिक .toolset() को मिला सकते हैं। स्थिर टूल्स और टूलसेट्स में डुप्लिकेट टूल नाम एक निर्धारक त्रुटि उत्पन्न करते हैं।

RealtimeAgentBuilder समान अर्थ के साथ .toolset() का भी समर्थन करता है, इसलिए रियलटाइम वॉइस एजेंटों को भी डायनेमिक टूल समाधान मिलता है।

टूलसेट संयोजन

FilteredToolset, MergedToolset, और PrefixedToolset का उपयोग adk-tool से जटिल टूलसेट कॉन्फ़िगरेशन बनाने के लिए करें:

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

सभी संयोजन उपयोगिताएँ किसी भी Toolset कार्यान्वयन के साथ काम करती हैं, जिनमें McpToolset और BrowserToolset शामिल हैं।

समानांतर टूल निष्पादन

जब कोई LLM एक ही प्रतिक्रिया में कई टूल कॉल लौटाता है, तो आप नियंत्रित कर सकते हैं कि उन्हें कैसे भेजा जाए:

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

तीन रणनीतियाँ उपलब्ध हैं:

  • Sequential (डिफ़ॉल्ट) — टूल्स LLM क्रम में एक-एक करके निष्पादित होते हैं
  • Parallel — सभी टूल्स समकालिक रूप से निष्पादित होते हैं; यह स्पष्ट ओवरराइड सुरक्षा मेटाडेटा को बायपास करता है, इसलिए सुरक्षा की ज़िम्मेदारी कॉलर की होती है
  • Auto — जिन कॉल्स के टूल दोनों read-only और concurrency-safe हैं, वे पहले समकालिक रूप से चलती हैं; फिर शेष सभी कॉल्स क्रमिक रूप से चलती हैं

परिणाम हमेशा मूल LLM क्रम में लौटाए जाते हैं, रणनीति की परवाह किए बिना। असफल टूल्स बैच को रोके बिना एक JSON त्रुटि प्रतिक्रिया उत्पन्न करते हैं।

रणनीति प्रति-एजेंट LlmAgentBuilder::tool_execution_strategy() के माध्यम से सेट की जाती है। यदि सेट नहीं है, तो डिफ़ॉल्ट Sequential है।

टूल विश्वसनीयता

उत्पादन एजेंटों के लिए retry बजट और circuit breakers कॉन्फ़िगर करें:

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 संरचित ToolOutcome मेटाडेटा को CallbackContext::tool_outcome() के माध्यम से जाँच सकते हैं:

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

पूर्ण उदाहरण

कई टूल्स (मौसम, कैलकुलेटर, खोज) वाले एक production-ready एजेंट के साथ-साथ session state में सहेजा गया output:

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

इन prompts को आज़माएँ:

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.

  • Workflow Agents - Sequential, Parallel, और Loop agents
  • Multi-Agent Systems - एजेंट पदानुक्रम बनाना
  • Function Tools - कस्टम टूल बनाना
  • Callbacks - एजेंट व्यवहार को इंटरसेप्ट करना

Previous: Quickstart | Next: Workflow Agents →

LlmAgent - ADK-Rust दस्तावेज़ीकरण | ADK-Rust