कॉलबैक
ADK-Rust में कॉलबैक एजेंट के व्यवहार को महत्वपूर्ण निष्पादन बिंदुओं पर देखने, अनुकूलित करने और नियंत्रित करने के लिए हुक प्रदान करते हैं। वे लॉगिंग, गार्डरेल्स, कैशिंग, प्रतिक्रिया संशोधन और बहुत कुछ सक्षम करते हैं।
अवलोकन
ADK-Rust छह कॉलबैक प्रकारों का समर्थन करता है जो एजेंट निष्पादन के विभिन्न चरणों को इंटरसेप्ट करते हैं:
| कॉलबैक प्रकार | कब निष्पादित होता है | उपयोग के मामले |
|---|---|---|
before_agent | एजेंट प्रसंस्करण शुरू करने से पहले | इनपुट सत्यापन, लॉगिंग, शीघ्र समाप्ति |
after_agent | एजेंट पूरा होने के बाद | प्रतिक्रिया संशोधन, लॉगिंग, सफाई |
before_model | LLM कॉल से पहले | अनुरोध संशोधन, कैशिंग, दर सीमित करना |
after_model | LLM प्रतिक्रिया के बाद | प्रतिक्रिया फ़िल्टरिंग, लॉगिंग, कैशिंग |
before_tool | टूल निष्पादन से पहले | अनुमति जांच, पैरामीटर सत्यापन |
after_tool | टूल निष्पादन के बाद | परिणाम संशोधन, लॉगिंग |
कॉलबैक प्रकार
एजेंट कॉलबैक
एजेंट कॉलबैक पूरे एजेंट निष्पादन चक्र को लपेटते हैं।
use adk_rust::prelude::*;
use std::sync::Arc;
// BeforeAgentCallback type signature
type BeforeAgentCallback = Box<
dyn Fn(Arc<dyn CallbackContext>)
-> Pin<Box<dyn Future<Output = Result<Option<Content>>> + Send>>
+ Send + Sync
>;
// AfterAgentCallback type signature
type AfterAgentCallback = Box<
dyn Fn(Arc<dyn CallbackContext>)
-> Pin<Box<dyn Future<Output = Result<Option<Content>>> + Send>>
+ Send + Sync
>;
मॉडल कॉलबैक
मॉडल कॉलबैक LLM अनुरोधों और प्रतिक्रियाओं को इंटरसेप्ट करते हैं।
use adk_rust::prelude::*;
use std::sync::Arc;
// BeforeModelResult - कॉलबैक के बाद क्या होता है उसे नियंत्रित करता है
pub enum BeforeModelResult {
Continue(LlmRequest), // (संभावित रूप से संशोधित) अनुरोध के साथ जारी रखें
Skip(LlmResponse), // मॉडल कॉल को छोड़ें, इसके बजाय इस प्रतिक्रिया का उपयोग करें
}
// BeforeModelCallback - अनुरोध को संशोधित कर सकता है या मॉडल कॉल को छोड़ सकता है
type BeforeModelCallback = Box<
dyn Fn(Arc<dyn CallbackContext>, LlmRequest)
-> Pin<Box<dyn Future<Output = Result<BeforeModelResult>> + Send>>
+ Send + Sync
>;
// AfterModelCallback - प्रतिक्रिया को संशोधित कर सकता है
type AfterModelCallback = Box<
dyn Fn(Arc<dyn CallbackContext>, LlmResponse)
-> Pin<Box<dyn Future<Output = Result<Option<LlmResponse>>> + Send>>
+ Send + Sync
>;
टूल कॉलबैक
टूल कॉलबैक टूल निष्पादन को इंटरसेप्ट करते हैं।
use adk_rust::prelude::*;
use std::sync::Arc;
// BeforeToolCallback - Some(Content) लौटाकर टूल को छोड़ सकता है
type BeforeToolCallback = Box<
dyn Fn(Arc<dyn CallbackContext>)
-> Pin<Box<dyn Future<Output = Result<Option<Content>>> + Send>>
+ Send + Sync
>;
// AfterToolCallback - टूल परिणाम को संशोधित कर सकता है
type AfterToolCallback = Box<
dyn Fn(Arc<dyn CallbackContext>)
-> Pin<Box<dyn Future<Output = Result<Option<Content>>> + Send>>
+ Send + Sync
>;
रिटर्न वैल्यू सिमेंटिक्स
Callbacks निष्पादन प्रवाह को नियंत्रित करने के लिए विभिन्न रिटर्न वैल्यू का उपयोग करते हैं:
Agent/Tool Callbacks
| रिटर्न वैल्यू | प्रभाव |
|---|---|
Ok(None) | सामान्य निष्पादन जारी रखें |
Ok(Some(content)) | प्रदत्त content के साथ ओवरराइड/छोड़ें |
Err(e) | त्रुटि के साथ निष्पादन रद्द करें |
Model Callbacks
BeforeModelCallback BeforeModelResult का उपयोग करता है:
| रिटर्न वैल्यू | प्रभाव |
|---|---|
Ok(BeforeModelResult::Continue(request)) | संभवतः संशोधित request के साथ जारी रखें |
Ok(BeforeModelResult::Skip(response)) | model कॉल छोड़ें, इसके बजाय इस response का उपयोग करें |
Err(e) | त्रुटि के साथ निष्पादन रद्द करें |
AfterModelCallback Option<LlmResponse> का उपयोग करता है:
| रिटर्न वैल्यू | प्रभाव |
|---|---|
Ok(None) | मूल response रखें |
Ok(Some(response)) | संशोधित response के साथ बदलें |
Err(e) | त्रुटि के साथ निष्पादन रद्द करें |
सारांश
- Before agent/tool callbacks: जारी रखने के लिए
Noneलौटाएँ, छोड़ने के लिएSome(content)लौटाएँ - Before model callback: आगे बढ़ने के लिए
Continue(request)लौटाएँ, model को बाईपास करने के लिएSkip(response)लौटाएँ - After callbacks: मूल को रखने के लिए
Noneलौटाएँ, बदलने के लिएSome(...)लौटाएँ
Agent में Callbacks जोड़ना
Callbacks को LlmAgentBuilder का उपयोग करके Agent में जोड़ा जाता है:
use adk_rust::prelude::*;
use std::sync::Arc;
#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
let api_key = std::env::var("GOOGLE_API_KEY")?;
let model = Arc::new(GeminiModel::new(&api_key, "gemini-2.5-flash")?);
let agent = LlmAgentBuilder::new("my_agent")
.model(model)
.instruction("You are a helpful assistant.")
// before_agent callback जोड़ें
.before_callback(Box::new(|ctx| {
Box::pin(async move {
println!("Agent starting: {}", ctx.agent_name());
Ok(None) // निष्पादन जारी रखें
})
}))
// after_agent callback जोड़ें
.after_callback(Box::new(|ctx| {
Box::pin(async move {
println!("Agent completed: {}", ctx.agent_name());
Ok(None) // मूल परिणाम रखें
})
}))
.build()?;
Ok(())
}
CallbackContext इंटरफ़ेस
CallbackContext trait निष्पादन संदर्भ तक पहुंच प्रदान करता है:
use adk_rust::prelude::*;
#[async_trait]
pub trait CallbackContext: ReadonlyContext {
/// आर्टिफैक्ट स्टोरेज तक पहुंचें (यदि कॉन्फ़िगर किया गया हो)
fn artifacts(&self) -> Option<Arc<dyn Artifacts>>;
}
// CallbackContext ReadonlyContext का विस्तार करता है
#[async_trait]
pub trait ReadonlyContext: Send + Sync {
/// वर्तमान इनवोकेशन ID
fn invocation_id(&self) -> &str;
/// वर्तमान Agent का नाम
fn agent_name(&self) -> &str;
/// सेशन से यूजर ID
fn user_id(&self) -> &str;
/// एप्लिकेशन का नाम
fn app_name(&self) -> &str;
/// सेशन ID
fn session_id(&self) -> &str;
/// वर्तमान शाखा (मल्टी-Agent के लिए)
fn branch(&self) -> &str;
/// उपयोगकर्ता का इनपुट content
fn user_content(&self) -> &Content;
}
सामान्य पैटर्न
लॉगिंग कॉलबैक
सभी Agent इंटरैक्शन को लॉग करें:
use adk_rust::prelude::*;
use std::sync::Arc;
let agent = LlmAgentBuilder::new("logged_agent")
.model(model)
.before_callback(Box::new(|ctx| {
Box::pin(async move {
println!("[LOG] Agent '{}' starting", ctx.agent_name());
println!("[LOG] Session: {}", ctx.session_id());
println!("[LOG] User: {}", ctx.user_id());
Ok(None)
})
}))
.after_callback(Box::new(|ctx| {
Box::pin(async move {
println!("[LOG] Agent '{}' completed", ctx.agent_name());
Ok(None)
})
}))
.build()?;
इनपुट गार्डरेल्स
अनुचित सामग्री को प्रोसेस करने से पहले ब्लॉक करें:
use adk_rust::prelude::*;
use std::sync::Arc;
let agent = LlmAgentBuilder::new("guarded_agent")
.model(model)
.before_callback(Box::new(|ctx| {
Box::pin(async move {
// Check user input for blocked content
let user_content = ctx.user_content();
for part in &user_content.parts {
if let Part::Text { text } = part {
if text.to_lowercase().contains("blocked_word") {
// Return early with rejection message
return Ok(Some(Content {
role: "model".to_string(),
parts: vec![Part::Text {
text: "I cannot process that request.".to_string(),
}],
}));
}
}
}
Ok(None) // Continue normal execution
})
}))
.build()?;
प्रतिक्रिया कैशिंग (मॉडल से पहले)
API कॉल्स को कम करने के लिए LLM प्रतिक्रियाओं को कैश करें:
use adk_rust::prelude::*;
use std::sync::Arc;
use std::collections::HashMap;
use std::sync::Mutex;
// Simple in-memory cache
let cache: Arc<Mutex<HashMap<String, LlmResponse>>> = Arc::new(Mutex::new(HashMap::new()));
let cache_clone = cache.clone();
let agent = LlmAgentBuilder::new("cached_agent")
.model(model)
.before_model_callback(Box::new(move |ctx, request| {
let cache = cache_clone.clone();
Box::pin(async move {
// Create cache key from request contents
let key = format!("{:?}", request.contents);
// Check cache
if let Some(cached) = cache.lock().unwrap().get(&key) {
println!("[CACHE] Hit for request");
return Ok(BeforeModelResult::Skip(cached.clone()));
}
println!("[CACHE] Miss, calling model");
Ok(BeforeModelResult::Continue(request)) // Continue to model
})
}))
.build()?;
मल्टीमॉडल सामग्री इंजेक्ट करना (मॉडल से पहले)
मल्टीमॉडल विश्लेषण के लिए LLM अनुरोधों में चित्र या अन्य बाइनरी सामग्री इंजेक्ट करें:
use adk_rust::prelude::*;
use adk_rust::artifact::{ArtifactService, LoadRequest};
use std::sync::Arc;
// Artifact service with pre-loaded image
let artifact_service: Arc<dyn ArtifactService> = /* ... */;
let callback_service = artifact_service.clone();
let agent = LlmAgentBuilder::new("image_analyst")
.model(model)
.instruction("Describe the image provided by the user.")
.before_model_callback(Box::new(move |_ctx, mut request| {
let service = callback_service.clone();
Box::pin(async move {
// Load image from artifact storage
if let Ok(response) = service.load(LoadRequest {
app_name: "my_app".to_string(),
user_id: "user".to_string(),
session_id: "session".to_string(),
file_name: "user:photo.png".to_string(),
version: None,
}).await {
// Inject image into the user's message
if let Some(last_content) = request.contents.last_mut() {
if last_content.role == "user" {
last_content.parts.push(response.part);
}
}
}
Ok(BeforeModelResult::Continue(request))
})
}))
.build()?;
यह पैटर्न मल्टीमॉडल AI के लिए आवश्यक है क्योंकि Tool प्रतिक्रियाएँ JSON टेक्स्ट होती हैं - Model उन चित्रों को 'देख' नहीं सकता जो Tools द्वारा लौटाए जाते हैं। छवि को सीधे अनुरोध में इंजेक्ट करके, Model वास्तविक छवि डेटा प्राप्त करता है।
प्रतिक्रिया संशोधन (मॉडल के बाद)
Model प्रतिक्रियाओं को संशोधित या फ़िल्टर करें:
use adk_rust::prelude::*;
use std::sync::Arc;
let agent = LlmAgentBuilder::new("filtered_agent")
.model(model)
.after_model_callback(Box::new(|ctx, mut response| {
Box::pin(async move {
// Modify the response content
if let Some(ref mut content) = response.content {
for part in &mut content.parts {
if let Part::Text { text } = part {
// Add disclaimer to all responses
*text = format!("{}\n\n[AI-generated response]", text);
}
}
}
Ok(Some(response))
})
}))
.build()?;
Tool अनुमति जाँच (Tool से पहले)
Tool निष्पादन अनुमतियों को मान्य करें:
use adk_rust::prelude::*;
use std::sync::Arc;
let agent = LlmAgentBuilder::new("permission_agent")
.model(model)
.tool(Arc::new(GoogleSearchTool::new()))
.before_tool_callback(Box::new(|ctx| {
Box::pin(async move {
// Check if user has permission for tools
let user_id = ctx.user_id();
// Example: block certain users from using tools
if user_id == "restricted_user" {
return Ok(Some(Content {
role: "function".to_string(),
parts: vec![Part::Text {
text: "Tool access denied for this user.".to_string(),
}],
}));
}
Ok(None) // Allow tool execution
})
}))
.build()?;
Tool परिणाम लॉगिंग (Tool के बाद)
सभी Tool निष्पादन को लॉग करें:
use adk_rust::prelude::*;
use std::sync::Arc;
let agent = LlmAgentBuilder::new("tool_logged_agent")
.model(model)
.tool(Arc::new(GoogleSearchTool::new()))
.after_tool_callback(Box::new(|ctx| {
Box::pin(async move {
println!("[TOOL LOG] Tool executed for agent: {}", ctx.agent_name());
println!("[TOOL LOG] Session: {}", ctx.session_id());
Ok(None) // Keep original result
})
}))
.build()?;
मल्टीपल कॉलबैक
आप एक ही प्रकार के मल्टीपल कॉलबैक जोड़ सकते हैं। वे क्रम में निष्पादित होते हैं:
use adk_rust::prelude::*;
use std::sync::Arc;
let agent = LlmAgentBuilder::new("multi_callback_agent")
.model(model)
// First before callback - logging
.before_callback(Box::new(|ctx| {
Box::pin(async move {
println!("[1] Logging callback");
Ok(None)
})
}))
// Second before callback - validation
.before_callback(Box::new(|ctx| {
Box::pin(async move {
println!("[2] Validation callback");
Ok(None)
})
}))
.build()?;
जब कोई कॉलबैक Some(content) लौटाता है, तो उसी प्रकार के बाद के कॉलबैक छोड़ दिए जाते हैं।
त्रुटि प्रबंधन
कॉलबैक निष्पादन को रद्द करने के लिए त्रुटियाँ लौटा सकते हैं:
use adk_rust::prelude::*;
use std::sync::Arc;
let agent = LlmAgentBuilder::new("error_handling_agent")
.model(model)
.before_callback(Box::new(|ctx| {
Box::pin(async move {
// Validate something critical
if ctx.user_id().is_empty() {
return Err(AdkError::Agent("User ID is required".to_string()));
}
Ok(None)
})
}))
.build()?;
सर्वोत्तम अभ्यास
- कॉलबैक को हल्का रखें: कॉलबैक में भारी गणना से बचें
- त्रुटियों को शालीनता से संभालें: सार्थक त्रुटि संदेश लौटाएँ
- लॉगिंग का संयम से उपयोग करें: बहुत अधिक लॉगिंग प्रदर्शन को प्रभावित कर सकती है
- बुद्धिमानी से कैश करें: कैश अमान्यकरण रणनीतियों पर विचार करें
- कॉलबैक का स्वतंत्र रूप से परीक्षण करें: कॉलबैक लॉजिक का अलग से यूनिट परीक्षण करें
संबंधित
पिछला: ← स्टेट मैनेजमेंट | अगला: आर्टिफैक्ट्स →