LlmAgent

الـ LlmAgent هو نوع العميل الأساسي في adk-rust الذي يستخدم نموذجًا لغويًا كبيرًا (Large Language Model) للاستدلال واتخاذ القرار.

بدء سريع

أنشئ مشروعًا جديدًا:

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"

أنشئ ملف .env باستخدام مفتاح API الخاص بك:

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)

سترى موجهًا تفاعليًا:

🤖 العميل جاهز! اكتب أسئلتك (أو 'exit' للخروج).

أنت: مرحباً! بماذا يمكنك مساعدتي؟
المساعد: مرحباً! أنا مساعد مفيد. يمكنني مساعدتك في:
- الإجابة على الأسئلة حول مواضيع مختلفة
- شرح المفاهيم بوضوح
- إجراء محادثة

ماذا تود أن تعرف؟

أنت: exit
👋 وداعاً!

تحديد سلوك Agent باستخدام التعليمات

يحدد الأسلوب instruction() شخصية وسلوك Agent الخاص بك. هذا هو موجه النظام الذي يوجه كل استجابة:

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

أمثلة على المخرجات

موجه المستخدم: "What is Rust?"

مساعد الأعمال الرسمي:

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.

معلم البرمجة الودود:

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?

القصاص المبدع:

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}. يتم حل المتغيرات من حالة الجلسة في وقت التشغيل:

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. أنشئ Agent باستخدام متغيرات القالب في التعليمات
  2. قم بإعداد Runner و SessionService لإدارة الحالة
  3. أنشئ جلسة مع متغيرات الحالة التي تتطابق مع القالب الخاص بك
  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. 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(())
}

أنواع متغيرات القالب:

النمطمثالالمصدر
{var}{user_name}حالة الجلسة
{prefix:var}{user:name}, {app:config}حالة مسبوقة
{var?}{user_name?}اختياري (فارغ إذا كان مفقودًا)
{artifact.file}{artifact.resume.pdf}محتوى الـArtifact

مثال على المخرجات:

القالب: "You are helping {user_name}. Their role is {user_role}." يصبح: "You are helping Alice. Their role is Senior Developer."

سيقوم Agent بعد ذلك بالرد بمحتوى مخصص بناءً على اسم المستخدم ومستوى خبرته!


إضافة الأدوات

تمنح الأدوات وكيلك قدرات تتجاوز المحادثة - يمكنها جلب البيانات، إجراء العمليات الحسابية، البحث في الويب، أو استدعاء واجهات برمجة التطبيقات الخارجية. يقرر LlmAgent متى يستخدم أداة بناءً على طلب المستخدم.

كيف تعمل الأدوات

  1. يتلقى الوكيل رسالة المستخدم ← "ما هو الطقس في طوكيو؟"
  2. يقرر LlmAgent استدعاء الأداة ← يختار get_weather مع {"city": "Tokyo"}
  3. تنفذ الأداة ← تعيد {"temperature": "22°C", "condition": "sunny"}
  4. يقوم LlmAgent بتنسيق الاستجابة ← "الطقس في طوكيو مشمس ودرجة الحرارة 22 درجة مئوية."

إنشاء أداة باستخدام FunctionTool

FunctionTool هي أبسط طريقة لإنشاء أداة - قم بتغليف أي دالة Rust غير متزامنة ويمكن لـ LlmAgent استدعائها. توفر اسمًا ووصفًا ودالة معالجة تتلقى وسائط JSON وتعيد نتيجة JSON.

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

⚠️ ملاحظة: قيد حالي: الأدوات المدمجة مثل GoogleSearchTool غير متوافقة حاليًا مع FunctionTool في نفس الوكيل. استخدم إما الأدوات المدمجة أو FunctionTools المخصصة، ولكن ليس كلاهما معًا. 💡 حل بديل: أنشئ وكلاء فرعيين منفصلين، لكل منهم نوع الأداة الخاص به، ونسق بينهم باستخدام LLMAgent رئيسي، أو وكلاء سير العمل، أو أنماط الوكلاء المتعددة.

بناء وكيل متعدد الأدوات

أنشئ مشروعًا جديدًا:

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 بوكيل يحتوي على ثلاث أدوات:

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

للتطبيقات التي تحتاج إلى بيانات منظمة، استخدم 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(IncludeContents::Default)

// عديم الحالة - يرى الإدخال الحالي فقط
.include_contents(IncludeContents::None)

مفتاح الإخراج

حفظ استجابات Agent إلى حالة Session:

.output_key("summary")  // يتم حفظ الاستجابة في 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

Methodالوصف
new(name)ينشئ Builder باسم Agent
model(Arc<dyn Llm>)يضبط LLM (مطلوب)
description(text)وصف Agent
instruction(text)موجه النظام
tool(Arc<dyn Tool>)يضيف Tool
output_schema(json)JSON schema للمخرجات المنظمة
output_key(key)يحفظ الاستجابة إلى الحالة
include_contents(mode)رؤية السجل
build()ينشئ 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")?;

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

ذات صلة


السابق: Quickstart | التالي: Workflow Agents →