इवेंट्स
ADK-Rust में इवेंट्स बातचीत के इतिहास के मूलभूत निर्माण खंड हैं। एजेंट के साथ प्रत्येक इंटरैक्शन - चाहे वह उपयोगकर्ता का संदेश हो, एजेंट का जवाब हो, या टूल का निष्पादन हो - एक इवेंट के रूप में रिकॉर्ड किया जाता है। इवेंट्स एक अपरिवर्तनीय लॉग बनाते हैं जो एजेंट सेशन के पूर्ण निष्पादन ट्रेस को कैप्चर करता है।
अवलोकन
इवेंट सिस्टम कई महत्वपूर्ण उद्देश्यों को पूरा करता है:
- बातचीत का इतिहास: इवेंट्स एक सेशन में सभी इंटरैक्शन का कालानुक्रमिक रिकॉर्ड बनाते हैं।
- स्टेट मैनेजमेंट: इवेंट्स
state_deltaफ़ील्ड के माध्यम से स्टेट परिवर्तनों को आगे बढ़ाते हैं। - आर्टिफैक्ट ट्रैकिंग: इवेंट्स
artifact_deltaफ़ील्ड के माध्यम से आर्टिफैक्ट ऑपरेशंस को रिकॉर्ड करते हैं। - एजेंट समन्वय: इवेंट्स एजेंट के स्थानांतरण और वृद्धि को सक्षम करते हैं।
- डीबगिंग और ऑब्जरवेबिलिटी: इवेंट्स एजेंट के व्यवहार का एक पूर्ण ऑडिट ट्रेल प्रदान करते हैं।
इवेंट संरचना
एक Event बातचीत में एक एकल इंटरैक्शन का प्रतिनिधित्व करता है। ADK-Rust एक एकीकृत Event प्रकार का उपयोग करता है जो LlmResponse को एम्बेड करता है, ADK-Go में उपयोग किए जाने वाले डिज़ाइन पैटर्न से मेल खाता है:
pub struct Event {
pub id: String, // Unique event identifier (UUID)
pub timestamp: DateTime<Utc>, // When the event occurred
pub invocation_id: String, // Links related events in a single invocation
pub branch: String, // For future branching support
pub author: String, // Who created this event (user, agent name, tool name)
pub llm_response: LlmResponse, // Contains content and LLM metadata
pub actions: EventActions, // Side effects and metadata
pub long_running_tool_ids: Vec<String>, // IDs of long-running tools
}
LlmResponse स्ट्रक्ट में शामिल है:
pub struct LlmResponse {
pub content: Option<Content>, // The message content (text, parts, etc.)
pub usage_metadata: Option<UsageMetadata>,
pub finish_reason: Option<FinishReason>,
pub partial: bool, // True for streaming partial responses
pub turn_complete: bool, // True when the turn is complete
pub interrupted: bool, // True if generation was interrupted
pub error_code: Option<String>,
pub error_message: Option<String>,
}
Content को event.llm_response.content के माध्यम से लगातार एक्सेस किया जाता है:
if let Some(content) = &event.llm_response.content {
for part in &content.parts {
if let Part::Text { text } = part {
println!("{}", text);
}
}
}
मुख्य फ़ील्ड
-
id: इस विशिष्ट इवेंट की पहचान करने वाला एक अद्वितीय UUID। इवेंट पुनर्प्राप्ति और ऑर्डरिंग के लिए उपयोग किया जाता है।
-
timestamp: इवेंट बनने का UTC टाइमस्टैम्प। इवेंट्स सेशन में कालानुक्रमिक रूप से ऑर्डर किए जाते हैं।
-
invocation_id: उन इवेंट्स को समूहित करता है जो एक ही एजेंट इनवोकेशन से संबंधित हैं। जब कोई एजेंट किसी संदेश को संसाधित करता है, तो सभी उत्पन्न इवेंट्स (एजेंट प्रतिक्रिया, टूल कॉल, सब-एजेंट कॉल) एक ही invocation_id साझा करते हैं।
-
branch: भविष्य की ब्रांचिंग कार्यक्षमता के लिए आरक्षित। वर्तमान में अप्रयुक्त है लेकिन भविष्य के संस्करणों में बातचीत की ब्रांचिंग की अनुमति देता है।
-
author: यह पहचानता है कि इवेंट किसने बनाया:
- उपयोगकर्ता संदेश: आमतौर पर "user" या एक उपयोगकर्ता पहचानकर्ता
- एजेंट प्रतिक्रियाएं: एजेंट का नाम
- टूल निष्पादन: टूल का नाम
- सिस्टम इवेंट्स: "system"
-
llm_response: संदेश Content और LLM मेटाडेटा शामिल है।
event.llm_response.contentके माध्यम से Content को एक्सेस करें।Contentप्रकार में text, मल्टीमॉडल Part (images, audio) या संरचित डेटा हो सकता है। कुछ इवेंट्स (जैसे शुद्ध स्टेट अपडेट) मेंcontent: Noneहो सकता है।
EventActions
स्ट्रक्चर EventActions में किसी इवेंट से संबंधित मेटाडेटा और साइड इफेक्ट्स होते हैं:
pub struct EventActions {
pub state_delta: HashMap<String, Value>, // State changes to apply
pub artifact_delta: HashMap<String, i64>, // Artifact version changes
pub skip_summarization: bool, // Skip this event in summaries
pub transfer_to_agent: Option<String>, // Transfer control to another agent
pub escalate: bool, // Escalate to human or supervisor
}
state_delta
फील्डर state_delta में सेशन स्टेट में बदलावों को दर्शाने वाले कुंजी-मूल्य युग्म होते हैं। जब किसी इवेंट को एक सेशन में जोड़ा जाता है, तो ये बदलाव सेशन के स्टेट में मर्ज हो जाते हैं।
स्टेट कुंजियाँ स्कोप को नियंत्रित करने के लिए उपसर्गों का उपयोग कर सकती हैं:
app:key- एप्लिकेशन-स्कोपेड स्टेट (सभी उपयोगकर्ताओं में साझा)user:key- उपयोगकर्ता-स्कोपेड स्टेट (एक उपयोगकर्ता के लिए सभी सेशन में साझा)temp:key- अस्थायी स्टेट (आह्वानों के बीच साफ़ की जाती है)- कोई उपसर्ग नहीं - सेशन-स्कोपेड स्टेट (डिफ़ॉल्ट)
उदाहरण:
let mut actions = EventActions::default();
actions.state_delta.insert("user_name".to_string(), json!("Alice"));
actions.state_delta.insert("temp:current_step".to_string(), json!(3));
artifact_delta
फील्डर artifact_delta कलाकृतियों में बदलावों को ट्रैक करता है। कुंजियाँ कलाकृति के नाम हैं, और मान संस्करण संख्याएँ हैं। यह सिस्टम को यह ट्रैक करने की अनुमति देता है कि किसी इवेंट के दौरान कौन सी कलाकृतियाँ बनाई या संशोधित की गईं।
उदाहरण:
actions.artifact_delta.insert("report.pdf".to_string(), 1);
actions.artifact_delta.insert("chart.png".to_string(), 2);
skip_summarization
जब true होता है, तो इस इवेंट को बातचीत के सारांश से बाहर रखा जाएगा। यह आंतरिक इवेंट्स, डिबगिंग जानकारी, या विस्तृत टूल आउटपुट के लिए उपयोगी है जो मुख्य बातचीत प्रवाह का हिस्सा नहीं होने चाहिए।
transfer_to_agent
जब किसी एजेंट के नाम पर सेट किया जाता है, तो नियंत्रण उस एजेंट को हस्तांतरित कर दिया जाता है। यह मल्टी-एजेंट वर्कफ़्लो को सक्षम बनाता है जहाँ एक एजेंट दूसरे को कार्य सौंप सकता है। लक्ष्य एजेंट को एक सब-एजेंट के रूप में कॉन्फ़िगर किया जाना चाहिए।
उदाहरण:
actions.transfer_to_agent = Some("specialist_agent".to_string());
escalate
जब true होता है, तो यह संकेत देता है कि बातचीत को किसी मानव ऑपरेटर या सुपरवाइज़र एजेंट को बढ़ाया जाना चाहिए। विशिष्ट एस्केलेशन व्यवहार आपके एप्लिकेशन के कार्यान्वयन पर निर्भर करता है।
बातचीत इतिहास का निर्माण
इवेंट्स एक सेशन के भीतर कालानुक्रमिक क्रम में जमा होकर बातचीत का इतिहास बनाते हैं। जब एक एजेंट किसी अनुरोध को संसाधित करता है:
- यूज़र मैसेज इवेंट: उपयोगकर्ता के इनपुट के साथ एक नया इवेंट बनाया जाता है
- एजेंट प्रोसेसिंग: एजेंट को बातचीत का इतिहास (सभी पिछले इवेंट्स) प्राप्त होता है
- एजेंट रिस्पॉन्स इवेंट: एजेंट का जवाब एक नए इवेंट के रूप में दर्ज किया जाता है
- टूल एग्ज़ेक्यूशन इवेंट्स: प्रत्येक टूल कॉल अतिरिक्त इवेंट्स उत्पन्न कर सकता है
- स्टेट अपडेट्स: सभी इवेंट्स से स्टेट डेल्टा सेशन स्टेट में मर्ज हो जाते हैं
बातचीत का इतिहास निम्न द्वारा निर्मित होता है:
- सेशन से सभी इवेंट्स को कालानुक्रमिक क्रम में पुनर्प्राप्त करना
- प्रत्येक इवेंट की सामग्री को LLM के लिए उपयुक्त प्रारूप में परिवर्तित करना
- संचित स्टेट डेल्टा से स्टेट जानकारी को शामिल करना
skip_summarizationके साथ चिह्नित इवेंट्स को, जब उचित हो, फ़िल्टर करना
इवेंट प्रवाह उदाहरण
Session Start
↓
[Event 1] User: "What's the weather in Tokyo?"
↓
[Event 2] Agent: "Let me check that for you."
↓
[Event 3] Tool (weather_api): {"temp": 22, "condition": "sunny"}
↓
[Event 4] Agent: "It's 22°C and sunny in Tokyo."
↓
Session State Updated
प्रत्येक इवेंट पिछले इवेंट्स पर आधारित होता है, जिससे बातचीत का एक पूर्ण ऑडिट ट्रेल बनता है।
इवेंट्स के साथ काम करना
एक Session से इवेंट्स को एक्सेस करना
use adk_rust::session::{SessionService, GetRequest};
// Retrieve a session with its events
let session = session_service.get(GetRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: session_id.clone(),
num_recent_events: None, // Get all events
after: None,
}).await?;
// Access the events
let events = session.events();
println!("Total events: {}", events.len());
// Iterate through events (note: session events use llm_response.content)
for i in 0..events.len() {
if let Some(event) = events.at(i) {
println!("Event {}: {} by {} at {}",
event.id,
event.llm_response.content.as_ref().map(|_| "has content").unwrap_or("no content"),
event.author,
event.timestamp
);
}
}
इवेंट के विवरणों का निरीक्षण करना
// Get a specific event from session (uses llm_response.content)
if let Some(event) = events.at(0) {
// Check the author
println!("Author: {}", event.author);
// Check content (session events use llm_response.content)
if let Some(content) = &event.llm_response.content {
for part in &content.parts {
if let Part::Text { text } = part {
println!("Text: {}", text);
}
}
}
// Check for state changes
if !event.actions.state_delta.is_empty() {
println!("State changes:");
for (key, value) in &event.actions.state_delta {
println!(" {} = {}", key, value);
}
}
// Check for agent transfers
if let Some(target) = &event.actions.transfer_to_agent {
println!("Transfers to: {}", target);
}
// Check for artifacts
if !event.actions.artifact_delta.is_empty() {
println!("Artifacts modified:");
for (name, version) in &event.actions.artifact_delta {
println!(" {} (v{})", name, version);
}
}
}
इवेंट इतिहास को सीमित करना
लंबी बातचीत के लिए, आप केवल हाल के इवेंट्स को पुनः प्राप्त करना चाह सकते हैं:
// Get only the last 10 events
let session = session_service.get(GetRequest {
app_name: "my_app".to_string(),
user_id: "user_123".to_string(),
session_id: session_id.clone(),
num_recent_events: Some(10),
after: None,
}).await?;
इवेंट कैसे प्रवाहित होते हैं: निर्माण और प्रसंस्करण
इवेंट कैसे बनाए और संसाधित किए जाते हैं, यह समझने से स्पष्ट होता है कि फ़्रेमवर्क कार्यों और इतिहास को कैसे प्रबंधित करता है।
निर्माण के स्रोत
एजेंट निष्पादन जीवनचक्र के विभिन्न बिंदुओं पर इवेंट बनाए जाते हैं:
- उपयोगकर्ता इनपुट: Runner उपयोगकर्ता संदेशों को
author = "user"के साथ एक Event में लपेटता है। - एजेंट प्रतिक्रियाएँ: Agents प्रतिक्रियाओं को संप्रेषित करने के लिए Event ऑब्जेक्ट (
author = agent.name()सेट करते हुए) उत्पन्न करते हैं। - LLM आउटपुट: मॉडल एकीकरण परत LLM आउटपुट (पाठ, फ़ंक्शन कॉल) को Event ऑब्जेक्ट में अनुवादित करती है।
- Tool परिणाम: Tool निष्पादन के बाद, फ़्रेमवर्क Tool प्रतिक्रिया वाले एक Event को जेनरेट करता है।
प्रसंस्करण प्रवाह
जब कोई इवेंट जेनरेट होता है, तो वह इस प्रसंस्करण पथ का अनुसरण करता है:
- उत्पत्ति: एक इवेंट बनाया जाता है और उसके स्रोत (एजेंट, Tool, या उपयोगकर्ता इनपुट हैंडलर) द्वारा उत्पन्न किया जाता है।
- Runner प्राप्त करता है: एजेंट को निष्पादित करने वाला Runner इवेंट प्राप्त करता है।
- SessionService प्रसंस्करण: Runner इवेंट को SessionService पर भेजता है, जो:
- डेल्टा लागू करता है:
state_deltaको सेशन स्टेट में मर्ज करता है और आर्टिफैक्ट रिकॉर्ड को अपडेट करता है। - मेटाडेटा को अंतिम रूप देता है: यदि अद्वितीय
idमौजूद नहीं है, तो उसे असाइन करता है,timestampसेट करता है। - इतिहास में स्थायी करता है: इवेंट को
session.eventsमें जोड़ता है।
- डेल्टा लागू करता है:
- आउटपुट स्ट्रीम करें: Runner संसाधित इवेंट को कॉल करने वाले एप्लिकेशन को प्रदान करता है।
यह प्रवाह सुनिश्चित करता है कि संचार सामग्री के साथ-साथ स्टेट परिवर्तन और इतिहास लगातार दर्ज किए जाते हैं।
// Conceptual flow
User Input → Runner → Agent → LLM → Event Generated
↓
SessionService
- Apply state_delta
- Record in history
↓
Event Stream → Application
इवेंट प्रकारों की पहचान करना
Runner से इवेंट संसाधित करते समय, आप पहचानना चाहेंगे कि आप किस प्रकार के इवेंट से निपट रहे हैं:
लेखक द्वारा
author फ़ील्ड आपको बताता है कि इवेंट किसने बनाया है:
match event.author.as_str() {
"user" => println!("User input"),
agent_name => println!("Response from agent: {}", agent_name),
}
सामग्री प्रकार द्वारा
पेलोड प्रकार निर्धारित करने के लिए llm_response.content फ़ील्ड की जाँच करें:
if let Some(content) = &event.llm_response.content {
// Check for text content
let has_text = content.parts.iter().any(|part| {
matches!(part, Part::Text { .. })
});
// Check for function calls (tool requests)
let has_function_call = content.parts.iter().any(|part| {
matches!(part, Part::FunctionCall { .. })
});
// Check for function responses (tool results)
let has_function_response = content.parts.iter().any(|part| {
matches!(part, Part::FunctionResponse { .. })
});
if has_text {
println!("Text message");
} else if has_function_call {
println!("Tool call request");
} else if has_function_response {
println!("Tool result");
}
}
क्रियाओं द्वारा
नियंत्रण संकेतों और साइड इफेक्ट्स के लिए actions फ़ील्ड की जाँच करें:
// State changes
if !event.actions.state_delta.is_empty() {
println!("Event contains state changes");
}
// Agent transfer
if let Some(target) = &event.actions.transfer_to_agent {
println!("Transfer to agent: {}", target);
}
// Escalation signal
if event.actions.escalate {
println!("Escalation requested");
}
// Skip summarization
if event.actions.skip_summarization {
println!("Skip this event in summaries");
}
इवेंट स्ट्रीम के साथ काम करना
एक Agent चलाने पर, आपको इवेंट्स की एक स्ट्रीम प्राप्त होती है। उन्हें प्रभावी ढंग से कैसे प्रोसेस करें, यहाँ बताया गया है:
Runner से इवेंट्स को प्रोसेस करना
use futures::StreamExt;
let mut stream = runner.run(
"user_123".to_string(),
"session_id".to_string(),
user_input,
).await?;
while let Some(event_result) = stream.next().await {
match event_result {
Ok(event) => {
// इवेंट को प्रोसेस करें
println!("Event from: {}", event.author);
// टेक्स्ट कंटेंट निकालें
if let Some(content) = &event.llm_response.content {
for part in &content.parts {
if let Part::Text { text } = part {
print!("{}", text);
}
}
}
// स्टेट परिवर्तनों की जाँच करें
if !event.actions.state_delta.is_empty() {
println!("\nState updated: {:?}", event.actions.state_delta);
}
}
Err(e) => {
eprintln!("Error: {}", e);
break;
}
}
}
फंक्शन कॉल निकालना
जब LLM किसी Tool का अनुरोध करता है, तो इवेंट में फंक्शन कॉल की जानकारी होती है:
if let Some(content) = &event.llm_response.content {
for part in &content.parts {
if let Part::FunctionCall { name, args } = part {
println!("Tool requested: {}", name);
println!("Arguments: {}", args);
// आपका एप्लिकेशन यहाँ Tool निष्पादन को डिस्पैच कर सकता है
// Tool के नाम और आर्ग्यूमेंट्स के आधार पर
}
}
}
फंक्शन रिस्पॉन्स निकालना
एक Tool के निष्पादित होने के बाद, परिणाम एक फंक्शन रिस्पॉन्स में वापस किया जाता है:
if let Some(content) = &event.llm_response.content {
for part in &content.parts {
if let Part::FunctionResponse { function_response, .. } = part {
println!("Tool result from: {}", function_response.name);
println!("Response: {}", function_response.response);
// Tool परिणाम को प्रोसेस करें
// LLM बातचीत जारी रखने के लिए इसका उपयोग करेगा
}
}
}
सामान्य इवेंट पैटर्न
यहाँ विशिष्ट इवेंट अनुक्रम दिए गए हैं जिनसे आपका सामना होगा:
सरल टेक्स्ट एक्सचेंज
[Event 1] author="user", content=Text("Hello")
[Event 2] author="assistant", content=Text("Hi! How can I help?")
Tool उपयोग प्रवाह
[Event 1] author="user", content=Text("What's the weather?")
[Event 2] author="assistant", content=FunctionCall(name="get_weather", args={...})
[Event 3] author="assistant", content=FunctionResponse(name="get_weather", response={...})
[Event 4] author="assistant", content=Text("It's sunny and 72°F")
स्टेट अपडेट
[Event 1] author="assistant", content=Text("I've saved your preference")
actions.state_delta={"user_theme": "dark"}
Agent ट्रांसफर
[Event 1] author="router", content=Text("Transferring to specialist")
actions.transfer_to_agent=Some("specialist_agent")
[Event 2] author="specialist_agent", content=Text("I can help with that")
इवेंट मेटाडेटा और आइडेंटिफ़ायर
इवेंट ID
सटीक पहचान के लिए प्रत्येक इवेंट में एक अद्वितीय id (UUID) होता है:
println!("Event ID: {}", event.id);
इनवोकेशन ID
invocation_id एक ही उपयोगकर्ता अनुरोध से लेकर अंतिम प्रतिक्रिया तक के सभी इवेंट्स को समूहबद्ध करता है:
// एक इंटरैक्शन के सभी इवेंट्स एक ही invocation_id साझा करते हैं
println!("Invocation: {}", event.invocation_id);
// लॉगिंग और ट्रेसिंग के लिए इसका उपयोग करें
log::info!("Processing event {} in invocation {}", event.id, event.invocation_id);
टाइमस्टैम्प
कालानुक्रमिक क्रम के लिए इवेंट्स को टाइमस्टैम्प किया जाता है:
println!("Event occurred at: {}", event.timestamp.format("%Y-%m-%d %H:%M:%S"));
सर्वोत्तम अभ्यास
-
Event Immutability: Events को बनाने के बाद कभी भी संशोधित नहीं किया जाना चाहिए। वे एक अपरिवर्तनीय ऑडिट लॉग बनाते हैं।
-
State Management: सभी state परिवर्तनों के लिए
state_deltaका उपयोग करें बजाय सीधे state को संशोधित करने के। यह सुनिश्चित करता है कि परिवर्तनों को event log में ट्रैक किया जाए। -
सार्थक लेखक: Event logs को समझना आसान बनाने के लिए स्पष्ट, वर्णनात्मक लेखक नाम सेट करें।
-
चयनात्मक संक्षेपण: वर्बोस या आंतरिक events के लिए
skip_summarizationका उपयोग करें जो बातचीत के इतिहास को अव्यवस्थित कर सकते हैं। -
आह्वान समूहीकरण: एक ही agent invocation के दौरान उत्पन्न सभी events के लिए समान
invocation_idरखें ताकि तार्किक समूहीकरण बना रहे। -
Artifact Tracking: Artifacts बनाते या संशोधित करते समय संगति बनाए रखने के लिए हमेशा
artifact_deltaको अपडेट करें। -
स्ट्रीम प्रोसेसिंग: Event streams को प्रोसेस करते समय हमेशा त्रुटियों को संभालें। LLM त्रुटियों, Tool विफलताओं, या नेटवर्क समस्याओं के कारण Events विफल हो सकते हैं।
-
Content जांच: parts तक पहुंचने से पहले हमेशा जांचें कि
llm_response.contentSomeहै। कुछ events (जैसे शुद्ध state अपडेट) में content नहीं हो सकता है। -
पैटर्न मिलान: विभिन्न event types और content parts को सुरुचिपूर्ण ढंग से संभालने के लिए Rust के पैटर्न मिलान का उपयोग करें।
-
लॉगिंग: डीबगिंग और ऑब्जर्वेबिलिटी के लिए एक ही उपयोगकर्ता सहभागिता के भीतर सभी events को सहसंबंधित करने के लिए
invocation_idका उपयोग करें।
संबंधित दस्तावेज़
- Sessions - Session प्रबंधन और जीवनचक्र
- State Management - Session state के साथ कार्य करना
- Artifacts - बाइनरी डेटा का प्रबंधन
- Multi-Agent Systems - Agent स्थानान्तरण और समन्वय
- Callbacks - Events को इंटरसेप्ट करना और संशोधित करना
पिछला: ← Artifacts | अगला: Telemetry →