स्टेट मैनेजमेंट

ADK-Rust में सेशन स्टेट एजेंट्स को उस डेटा को स्टोर और रिट्रीव करने की अनुमति देता है जो वार्तालाप के दौरान बना रहता है। स्टेट को कुंजी उपसर्गों का उपयोग करके व्यवस्थित किया जाता है जो डेटा के दायरे और जीवनकाल को निर्धारित करते हैं।

अवलोकन

स्टेट को कुंजी-मूल्य जोड़ों के रूप में संग्रहीत किया जाता है, जहाँ:

  • कुंजियाँ वैकल्पिक उपसर्गों वाली स्ट्रिंग्स होती हैं
  • मान JSON मान (serde_json::Value) होते हैं

उपसर्ग प्रणाली विभिन्न स्कोपिंग स्तरों को सक्षम करती है:

  • सेशन-स्कोप वाला: डिफ़ॉल्ट, एक ही सेशन से जुड़ा हुआ
  • उपयोगकर्ता-स्कोप वाला: एक उपयोगकर्ता के लिए सभी सेशनों में साझा किया गया
  • ऐप-स्कोप वाला: एक एप्लिकेशन के सभी उपयोगकर्ताओं में साझा किया गया
  • अस्थायी: प्रत्येक इनवोकेशन के बाद साफ़ किया जाता है

स्टेट ट्रेट

State ट्रेट स्टेट एक्सेस के लिए इंटरफ़ेस को परिभाषित करता है:

use serde_json::Value;
use std::collections::HashMap;

pub trait State: Send + Sync {
    /// Get a value by key
    fn get(&self, key: &str) -> Option<Value>;
    
    /// Set a value
    fn set(&mut self, key: String, value: Value);
    
    /// Get all state as a map
    fn all(&self) -> HashMap<String, Value>;
}

रीड-ओनली एक्सेस के लिए एक ReadonlyState ट्रेट भी है:

pub trait ReadonlyState: Send + Sync {
    fn get(&self, key: &str) -> Option<Value>;
    fn all(&self) -> HashMap<String, Value>;
}

स्टेट कुंजी उपसर्ग

ADK-Rust स्टेट स्कोपिंग को नियंत्रित करने के लिए तीन कुंजी उपसर्गों का उपयोग करता है:

उपसर्गConstantदायरा
app:KEY_PREFIX_APPसभी उपयोगकर्ताओं और सेशनों में साझा किया गया
user:KEY_PREFIX_USERएक उपयोगकर्ता के लिए सभी सेशनों में साझा किया गया
temp:KEY_PREFIX_TEMPप्रत्येक इनवोकेशन के बाद साफ़ किया गया
(कोई नहीं)-सेशन-स्कोप वाला (डिफ़ॉल्ट)

app: - एप्लिकेशन स्टेट

एक एप्लिकेशन के सभी उपयोगकर्ताओं और सेशनों में साझा किया गया स्टेट।

use adk_session::KEY_PREFIX_APP;

// KEY_PREFIX_APP = "app:"
let key = format!("{}settings", KEY_PREFIX_APP);  // "app:settings"

उपयोग के मामले:

  • एप्लिकेशन कॉन्फ़िगरेशन
  • साझा संसाधन
  • ग्लोबल काउंटर या आंकड़े

user: - उपयोगकर्ता स्टेट

एक विशिष्ट उपयोगकर्ता के लिए सभी सेशनों में साझा किया गया स्टेट।

use adk_session::KEY_PREFIX_USER;

// KEY_PREFIX_USER = "user:"
let key = format!("{}preferences", KEY_PREFIX_USER);  // "user:preferences"

उपयोग के मामले:

  • उपयोगकर्ता प्राथमिकताएँ
  • उपयोगकर्ता प्रोफ़ाइल डेटा
  • क्रॉस-सेशन उपयोगकर्ता संदर्भ

temp: - अस्थायी स्टेट

वह स्टेट जो प्रत्येक इनवोकेशन के बाद साफ़ हो जाता है। यह स्थायी नहीं होता।

use adk_session::KEY_PREFIX_TEMP;

// KEY_PREFIX_TEMP = "temp:"
let key = format!("{}current_step", KEY_PREFIX_TEMP);  // "temp:current_step"

उपयोग के मामले:

  • मध्यवर्ती गणना परिणाम
  • वर्तमान ऑपरेशन संदर्भ
  • वह डेटा जिसे स्थायी नहीं रहना चाहिए

कोई उपसर्ग नहीं - सेशन स्टेट

बिना उपसर्ग वाली कुंजियाँ सेशन-स्कोप वाली होती हैं (डिफ़ॉल्ट व्यवहार)।

let key = "conversation_topic";  // Session-scoped

उपयोग के मामले:

  • वार्तालाप संदर्भ
  • सेशन-विशिष्ट डेटा
  • टर्न-बाय-टर्न स्टेट

प्रारंभिक स्टेट सेट करना

एक सेशन बनाते समय स्टेट को इनिशियलाइज़ किया जा सकता है:

use adk_session::{InMemorySessionService, SessionService, CreateRequest, KEY_PREFIX_APP, KEY_PREFIX_USER};
use serde_json::json;
use std::collections::HashMap;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let mut initial_state = HashMap::new();

    // App-scoped state
    initial_state.insert(
        format!("{}version", KEY_PREFIX_APP),
        json!("1.0.0")
    );

    // User-scoped state
    initial_state.insert(
        format!("{}name", KEY_PREFIX_USER),
        json!("Alice")
    );

    // Session-scoped state
    initial_state.insert(
        "topic".to_string(),
        json!("Getting started")
    );

    let service = InMemorySessionService::new();
    let session = service.create(CreateRequest {
        app_name: "my_app".to_string(),
        user_id: "user_123".to_string(),
        session_id: None,
        state: initial_state,
    }).await?;
    
    Ok(())
}

स्टेट पढ़ना

सेशन के state() मेथड के माध्यम से स्टेट तक पहुंचें:

let state = session.state();

// Get a specific key
if let Some(value) = state.get("topic") {
    println!("Topic: {}", value);
}

// Get app-scoped state
if let Some(version) = state.get("app:version") {
    println!("App version: {}", version);
}

// Get all state
let all_state = state.all();
for (key, value) in all_state {
    println!("{}: {}", key, value);
}

इवेंट्स के माध्यम से स्टेट अपडेट

स्टेट को आमतौर पर इवेंट एक्शन के माध्यम से अपडेट किया जाता है। जब किसी सेशन में कोई इवेंट जोड़ा जाता है, तो उसका state_delta लागू किया जाता है:

use adk_session::{Event, EventActions};
use serde_json::json;
use std::collections::HashMap;

let mut state_delta = HashMap::new();
state_delta.insert("counter".to_string(), json!(42));
state_delta.insert("user:last_seen".to_string(), json!("2024-01-15"));

let mut event = Event::new("invocation_123");
event.actions = EventActions {
    state_delta,
    ..Default::default()
};

// When this event is appended, state is updated
service.append_event(session.id(), event).await?;

स्टेट स्कोपिंग व्यवहार

सेशन सर्विस स्वचालित रूप से स्टेट स्कोपिंग को संभालती है:

सेशन बनाने पर

  1. app: प्रीफिक्स वाली कुंजियाँ निकालें → app state में स्टोर करें
  2. user: प्रीफिक्स वाली कुंजियाँ निकालें → user state में स्टोर करें
  3. शेष कुंजियाँ (temp: को छोड़कर) → session state में स्टोर करें
  4. लौटाए गए सेशन के लिए सभी स्कोप मर्ज करें

सेशन पुनः प्राप्त करने पर

  1. एप्लिकेशन के लिए app state लोड करें
  2. उपयोगकर्ता के लिए user state लोड करें
  3. session state लोड करें
  4. सभी स्कोप मर्ज करें (app → user → session)

इवेंट जोड़ने पर

  1. इवेंट से state delta निकालें
  2. temp: कुंजियों को फ़िल्टर करें (जिन्हें परसिस्ट नहीं किया जाता)
  3. app: डेल्टा को app state पर लागू करें
  4. user: डेल्टा को user state पर लागू करें
  5. शेष डेल्टा को session state पर लागू करें

पूर्ण उदाहरण

use adk_session::{
    InMemorySessionService, SessionService, CreateRequest, GetRequest,
    KEY_PREFIX_APP, KEY_PREFIX_USER,
};
use serde_json::json;
use std::collections::HashMap;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let service = InMemorySessionService::new();
    
    // Create first session with initial state
    let mut state1 = HashMap::new();
    state1.insert(format!("{}theme", KEY_PREFIX_APP), json!("dark"));
    state1.insert(format!("{}language", KEY_PREFIX_USER), json!("en"));
    state1.insert("context".to_string(), json!("session1"));
    
    let session1 = service.create(CreateRequest {
        app_name: "my_app".to_string(),
        user_id: "alice".to_string(),
        session_id: Some("s1".to_string()),
        state: state1,
    }).await?;
    
    // Create second session for same user
    let mut state2 = HashMap::new();
    state2.insert("context".to_string(), json!("session2"));
    
    let session2 = service.create(CreateRequest {
        app_name: "my_app".to_string(),
        user_id: "alice".to_string(),
        session_id: Some("s2".to_string()),
        state: state2,
    }).await?;
    
    // Session 2 inherits app and user state
    let s2_state = session2.state();
    
    // App state is shared
    assert_eq!(s2_state.get("app:theme"), Some(json!("dark")));
    
    // User state is shared
    assert_eq!(s2_state.get("user:language"), Some(json!("en")));
    
    // Session state is separate
    assert_eq!(s2_state.get("context"), Some(json!("session2")));
    
    println!("State scoping works correctly!");
    Ok(())
}

स्टेट के साथ इंस्ट्रक्शन टेम्प्लेटिंग

स्टेट मानों को {key} सिंटैक्स का उपयोग करके agent इंस्ट्रक्शन में इंजेक्ट किया जा सकता है:

use adk_rust::prelude::*;
use std::sync::Arc;

let agent = LlmAgentBuilder::new("personalized_assistant")
    .instruction("You are helping {user:name} with {topic}. Their preferred language is {user:language}.")
    .model(Arc::new(model))
    .build()?;

जब agent चलता है, तो {user:name}, {topic}, और {user:language} को session state के मानों से बदल दिया जाता है।

सर्वोत्तम अभ्यास

1. उचित स्कोप का उपयोग करें

// ✅ अच्छा: उपयोगकर्ता स्कोप में उपयोगकर्ता प्राथमिकताएँ
"user:theme"
"user:timezone"

// ✅ अच्छा: बिना उपसर्ग के सत्र-विशिष्ट संदर्भ
"current_task"
"conversation_summary"

// ✅ अच्छा: ऐप स्कोप में ऐप-व्यापी सेटिंग्स
"app:model_version"
"app:feature_flags"

// ❌ बुरा: सत्र स्कोप में उपयोगकर्ता डेटा (सत्रों के बीच खो जाता है)
"user_preferences"  // "user:preferences" होना चाहिए

2. मध्यवर्ती डेटा के लिए अस्थायी स्थिति का उपयोग करें

// ✅ अच्छा: अस्थायी स्कोप में मध्यवर्ती परिणाम
"temp:search_results"
"temp:current_step"

// ❌ बुरा: मध्यवर्ती डेटा अनावश्यक रूप से संग्रहीत किया गया
"search_results"  // डेटाबेस में सहेजा जाएगा

3. स्टेट कीज़ को सुसंगत रखें

// ✅ अच्छा: सुसंगत नामकरण परंपरा
"user:preferences.theme"
"user:preferences.language"

// ❌ बुरा: असंगत नामकरण
"user:theme"
"userLanguage"
"user-timezone"

संबंधित

  • Sessions - सत्र प्रबंधन अवलोकन
  • Events - इवेंट संरचना और state_delta
  • LlmAgent - इंस्ट्रक्शन टेम्पलेटिंग

पिछला: ← Sessions | अगला: Callbacks →