फ़ंक्शन टूल
कस्टम Rust फ़ंक्शन के साथ एजेंट क्षमताओं का विस्तार करें।
फ़ंक्शन टूल क्या हैं?
फ़ंक्शन टूल आपको एजेंटों को बातचीत से परे क्षमताएं प्रदान करने की सुविधा देते हैं - एपीआई कॉल करना, गणना करना, डेटाबेस एक्सेस करना, या कोई भी कस्टम लॉजिक। LLM उपयोगकर्ता के अनुरोध के आधार पर यह तय करता है कि कब किसी टूल का उपयोग करना है।
मुख्य विशेषताएं:
- 🔧 किसी भी async फ़ंक्शन को एक कॉलिंग योग्य टूल के रूप में रैप करें
- 📝 JSON पैरामीटर - लचीला इनपुट/आउटपुट
- 🎯 टाइप-सेफ स्कीमा - वैकल्पिक JSON स्कीमा सत्यापन
- 🔗 कंटेक्स्ट एक्सेस - सेशन स्थिति, आर्टिफैक्ट्स, मेमोरी
चरण 1: मूल टूल
FunctionTool::new() के साथ एक टूल बनाएं और हमेशा एक स्कीमा जोड़ें ताकि LLM को पता चले कि कौन से पैरामीटर पास करने हैं:
use adk_rust::prelude::*;
use adk_rust::Launcher;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::sync::Arc;
#[derive(JsonSchema, Serialize, Deserialize)]
struct WeatherParams {
/// The city or location to get weather for
location: String,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenvy::dotenv().ok();
let api_key = std::env::var("GOOGLE_API_KEY")?;
let model = GeminiModel::new(&api_key, "gemini-2.5-flash")?;
// Weather tool with proper schema
let weather_tool = FunctionTool::new(
"get_weather",
"Get current weather for a location",
|_ctx, args| async move {
let location = args.get("location")
.and_then(|v| v.as_str())
.unwrap_or("unknown");
Ok(json!({
"location": location,
"temperature": "22°C",
"conditions": "sunny"
}))
},
)
.with_parameters_schema::<WeatherParams>(); // Required for LLM to call correctly!
let agent = LlmAgentBuilder::new("weather_agent")
.instruction("You help users check the weather. Always use the get_weather tool.")
.model(Arc::new(model))
.tool(Arc::new(weather_tool))
.build()?;
Launcher::new(Arc::new(agent)).run().await?;
Ok(())
}
⚠️ महत्वपूर्ण: हमेशा
.with_parameters_schema<T>()का उपयोग करें - इसके बिना, LLM को पता नहीं चलेगा कि कौन से पैरामीटर पास करने हैं और यह टूल को कॉल नहीं कर सकता है।
यह कैसे काम करता है:
- उपयोगकर्ता पूछता है: "टोक्यो में मौसम कैसा है?"
- LLM
{"location": "Tokyo"}के साथget_weatherको कॉल करने का निर्णय लेता है - टूल
{"location": "Tokyo", "temperature": "22°C", "conditions": "sunny"}लौटाता है - LLM प्रतिक्रिया को स्वरूपित करता है: "टोक्यो में मौसम 22°C पर धूप वाला है।"
चरण 2: पैरामीटर हैंडलिंग
JSON args से पैरामीटर निकालें:
let order_tool = FunctionTool::new(
"process_order",
"Process an order. Parameters: product_id (required), quantity (required), priority (optional)",
|_ctx, args| async move {
// Required parameters - return error if missing
let product_id = args.get("product_id")
.and_then(|v| v.as_str())
.ok_or_else(|| adk_core::AdkError::Tool("product_id is required".into()))?;
let quantity = args.get("quantity")
.and_then(|v| v.as_i64())
.ok_or_else(|| adk_core::AdkError::Tool("quantity is required".into()))?;
// Optional parameter with default
let priority = args.get("priority")
.and_then(|v| v.as_str())
.unwrap_or("normal");
Ok(json!({
"order_id": "ORD-12345",
"product_id": product_id,
"quantity": quantity,
"priority": priority,
"status": "confirmed"
}))
},
);
चरण 3: स्कीमा के साथ टाइप्ड पैरामीटर
जटिल टूल के लिए, JSON स्कीमा के साथ टाइप्ड स्ट्रक्ट्स का उपयोग करें:
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(JsonSchema, Serialize, Deserialize)]
struct CalculatorParams {
/// The arithmetic operation to perform
operation: Operation,
/// First operand
a: f64,
/// Second operand
b: f64,
}
#[derive(JsonSchema, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
enum Operation {
Add,
Subtract,
Multiply,
Divide,
}
let calculator = FunctionTool::new(
"calculator",
"Perform arithmetic operations",
|_ctx, args| async move {
let params: CalculatorParams = serde_json::from_value(args)?;
let result = match params.operation {
Operation::Add => params.a + params.b,
Operation::Subtract => params.a - params.b,
Operation::Multiply => params.a * params.b,
Operation::Divide if params.b != 0.0 => params.a / params.b,
Operation::Divide => return Err(adk_core::AdkError::Tool("Cannot divide by zero".into())),
};
Ok(json!({ "result": result }))
},
)
.with_parameters_schema::<CalculatorParams>();
स्कीमा Rust प्रकारों से schemars का उपयोग करके स्वतः उत्पन्न होती है।
चरण 4: मल्टी-टूल एजेंट
एक एजेंट में कई टूल जोड़ें:
let agent = LlmAgentBuilder::new("assistant")
.instruction("Help with calculations, conversions, and weather.")
.model(Arc::new(model))
.tool(Arc::new(calc_tool))
.tool(Arc::new(convert_tool))
.tool(Arc::new(weather_tool))
.build()?;
LLM उपयोगकर्ता के अनुरोध के आधार पर स्वचालित रूप से सही टूल चुनता है।
त्रुटि प्रबंधन
टूल-विशिष्ट त्रुटियों के लिए AdkError::Tool लौटाएँ:
let divide_tool = FunctionTool::new(
"divide",
"Divide two numbers",
|_ctx, args| async move {
let a = args.get("a").and_then(|v| v.as_f64())
.ok_or_else(|| adk_core::AdkError::Tool("Parameter 'a' is required".into()))?;
let b = args.get("b").and_then(|v| v.as_f64())
.ok_or_else(|| adk_core::AdkError::Tool("Parameter 'b' is required".into()))?;
if b == 0.0 {
return Err(adk_core::AdkError::Tool("Cannot divide by zero".into()));
}
Ok(json!({ "result": a / b }))
},
);
त्रुटि संदेश LLM को पास किए जाते हैं, जो पुनः प्रयास कर सकता है या भिन्न इनपुट के लिए पूछ सकता है।
टूल संदर्भ
ToolContext के माध्यम से सत्र की जानकारी एक्सेस करें:
#[derive(JsonSchema, Serialize, Deserialize)]
struct GreetParams {
#[serde(default)]
message: Option<String>,
}
let greet_tool = FunctionTool::new(
"greet",
"Greet the user with session info",
|ctx, _args| async move {
let user_id = ctx.user_id();
let session_id = ctx.session_id();
let agent_name = ctx.agent_name();
Ok(json!({
"greeting": format!("Hello, user {}!", user_id),
"session": session_id,
"served_by": agent_name
}))
},
)
.with_parameters_schema::<GreetParams>();
उपलब्ध संदर्भ:
ctx.user_id()- वर्तमान उपयोगकर्ता IDctx.session_id()- वर्तमान सत्र IDctx.agent_name()- एजेंट का नामctx.artifacts()- आर्टिफैक्ट स्टोरेज तक पहुंचctx.search_memory(query)- मेमोरी सेवा खोजें
लंबे समय तक चलने वाले टूल्स
उन ऑपरेशनों के लिए जिनमें महत्वपूर्ण समय लगता है (डेटा प्रोसेसिंग, एक्सटर्नल APIs), नॉन-ब्लॉकिंग पैटर्न का उपयोग करें:
- स्टार्ट टूल तुरंत एक task_id के साथ लौटता है
- बैकग्राउंड वर्क एसिंक्रोनस रूप से चलता है
- स्टेटस टूल उपयोगकर्ताओं को प्रगति की जांच करने देता है
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
#[derive(JsonSchema, Serialize, Deserialize)]
struct ReportParams {
topic: String,
}
#[derive(JsonSchema, Serialize, Deserialize)]
struct StatusParams {
task_id: String,
}
// Shared task store
let tasks: Arc<RwLock<HashMap<String, TaskState>>> = Arc::new(RwLock::new(HashMap::new()));
let tasks1 = tasks.clone();
let tasks2 = tasks.clone();
// Tool 1: Start (returns immediately)
let start_tool = FunctionTool::new(
"generate_report",
"Start generating a report. Returns task_id immediately.",
move |_ctx, args| {
let tasks = tasks1.clone();
async move {
let topic = args.get("topic").and_then(|v| v.as_str()).unwrap_or("general").to_string();
let task_id = format!("task_{}", rand::random::<u32>());
// Store initial state
tasks.write().await.insert(task_id.clone(), TaskState {
status: "processing".to_string(),
progress: 0,
result: None,
});
// Spawn background work (non-blocking!)
let tasks_bg = tasks.clone();
let tid = task_id.clone();
tokio::spawn(async move {
// Simulate work...
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
if let Some(t) = tasks_bg.write().await.get_mut(&tid) {
t.status = "completed".to_string();
t.result = Some("Report complete".to_string());
}
});
// Return immediately with task_id
Ok(json!({"task_id": task_id, "status": "processing"}))
}
},
)
.with_parameters_schema::<ReportParams>()
.with_long_running(true); // Mark as long-running
// Tool 2: Check status
let status_tool = FunctionTool::new(
"check_report_status",
"Check report generation status",
move |_ctx, args| {
let tasks = tasks2.clone();
async move {
let task_id = args.get("task_id").and_then(|v| v.as_str()).unwrap_or("");
if let Some(t) = tasks.read().await.get(task_id) {
Ok(json!({"status": t.status, "result": t.result}))
} else {
Ok(json!({"error": "Task not found"}))
}
}
},
)
.with_parameters_schema::<StatusParams>();
मुख्य बिंदु:
.with_long_running(true)एजेंट को बताता है कि यह टूल लंबित स्टेटस लौटाता है- टूल
tokio::spawn()के साथ काम शुरू करता है और तुरंत लौट आता है - एक स्टेटस चेक टूल प्रदान करें ताकि उपयोगकर्ता प्रगति को पोल कर सकें
यह LLM को टूल को बार-बार कॉल करने से रोकने के लिए एक नोट जोड़ता है।
उदाहरण चलाएँ
cd official_docs_examples/tools/function_tools_test
# Basic tool with closure
cargo run --bin basic
# Tool with typed JSON schema
cargo run --bin with_schema
# Multi-tool agent (3 tools)
cargo run --bin multi_tool
# Tool context (session info)
cargo run --bin context
# Long-running tool
cargo run --bin long_running
सर्वोत्तम अभ्यास
- स्पष्ट विवरण - LLM को यह समझने में मदद करें कि टूल का उपयोग कब करना है
- इनपुट मान्य करें - गुम पैरामीटर्स के लिए सहायक त्रुटि संदेश लौटाएँ
- संरचित JSON लौटाएँ - स्पष्ट फ़ील्ड नामों का उपयोग करें
- टूल्स को केंद्रित रखें - प्रत्येक टूल को एक काम अच्छी तरह से करना चाहिए
- स्कीमा का उपयोग करें - जटिल टूल्स के लिए, पैरामीटर स्कीमा परिभाषित करें
संबंधित
- बिल्ट-इन टूल्स - प्री-बिल्ट टूल्स (GoogleSearch, ExitLoop)
- MCP टूल्स - मॉडल कॉन्टेक्स्ट प्रोटोकॉल इंटीग्रेशन
- LlmAgent - एजेंट्स में टूल्स जोड़ना
पिछला: ← mistral.rs | अगला: बिल्ट-इन टूल्स →