セッション

adk-rustにおけるセッションは会話コンテキスト管理を提供し、Agentが複数のやり取りにわたって状態を維持できるようにします。セッションは会話履歴(イベント)と、会話全体を通じて永続する任意のstateデータを保存します。

概要

Sessionは、ユーザーとAgent間の単一の会話を表します。各Sessionは以下を含みます:

  • 一意の識別子を持つ
  • アプリケーション (app_name) およびユーザー (user_id) に属する
  • イベントのリスト(会話履歴)を含む
  • stateデータ(キーと値のペア)を維持する
  • 最終更新時間を追跡する

Session Trait

Session traitは、Sessionオブジェクトのインターフェースを定義します:

use adk_session::{Events, State};
use chrono::{DateTime, Utc};

pub trait Session: Send + Sync {
    /// ユニークなセッション識別子
    fn id(&self) -> &str;
    
    /// このセッションが属するアプリケーション名
    fn app_name(&self) -> &str;
    
    /// ユーザー識別子
    fn user_id(&self) -> &str;
    
    /// セッションのstateにアクセスする
    fn state(&self) -> &dyn State;
    
    /// 会話イベントにアクセスする
    fn events(&self) -> &dyn Events;
    
    /// セッションが最後に更新された時刻
    fn last_update_time(&self) -> DateTime<Utc>;
}

SessionService Trait

SessionService traitは、Sessionを管理するための操作を定義します:

use adk_session::{CreateRequest, GetRequest, ListRequest, DeleteRequest, Event, Session};
use adk_core::Result;
use async_trait::async_trait;

#[async_trait]
pub trait SessionService: Send + Sync {
    /// 新しいセッションを作成する
    async fn create(&self, req: CreateRequest) -> Result<Box<dyn Session>>;
    
    /// 既存のセッションを取得する
    async fn get(&self, req: GetRequest) -> Result<Box<dyn Session>>;
    
    /// アプリ/ユーザーのすべてのセッションをリストする
    async fn list(&self, req: ListRequest) -> Result<Vec<Box<dyn Session>>>;
    
    /// セッションを削除する
    async fn delete(&self, req: DeleteRequest) -> Result<()>;
    
    /// セッションにイベントを追加する
    async fn append_event(&self, session_id: &str, event: Event) -> Result<()>;
}

リクエストタイプ

CreateRequest

use adk_session::CreateRequest;
use std::collections::HashMap;

let request = CreateRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: None,  // Noneの場合、UUIDを自動生成する
    state: HashMap::new(),  // 初期state
};

GetRequest

use adk_session::GetRequest;

let request = GetRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: "session_abc".to_string(),
    num_recent_events: Some(10),  // 返されるイベントを制限する
    after: None,  // タイムスタンプ以降のイベントをフィルタリングする
};

ListRequest

use adk_session::ListRequest;

let request = ListRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
};

DeleteRequest

use adk_session::DeleteRequest;

let request = DeleteRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: "session_abc".to_string(),
};

SessionService の実装

adk-rust は、2つの SessionService 実装を提供します。

InMemorySessionService

セッションをメモリに保存します。開発、テスト、およびシングルインスタンスのデプロイに最適です。

use adk_session::{InMemorySessionService, SessionService, CreateRequest};
use std::collections::HashMap;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Create the service
    let session_service = InMemorySessionService::new();
    
    // Create a session
    let session = session_service.create(CreateRequest {
        app_name: "my_app".to_string(),
        user_id: "user_123".to_string(),
        session_id: None,
        state: HashMap::new(),
    }).await?;
    
    println!("Session ID: {}", session.id());
    println!("App: {}", session.app_name());
    println!("User: {}", session.user_id());
    
    Ok(())
}

DatabaseSessionService

セッションを SQLite データベースに保存します。永続性が必要な本番環境でのデプロイに適しています。

use adk_session::{DatabaseSessionService, SessionService, CreateRequest};
use std::collections::HashMap;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Connect to database
    let session_service = DatabaseSessionService::new("sqlite:sessions.db").await?;
    
    // Run migrations to create tables
    session_service.migrate().await?;
    
    // Create a session
    let session = session_service.create(CreateRequest {
        app_name: "my_app".to_string(),
        user_id: "user_123".to_string(),
        session_id: None,
        state: HashMap::new(),
    }).await?;
    
    println!("Session persisted: {}", session.id());
    
    Ok(())
}

: DatabaseSessionService には、database フィーチャフラグが必要です。

adk-session = { version = "0.2", features = ["database"] }

セッションのライフサイクル

1. 作成

セッションは CreateRequest を使用して作成されます。session_id が指定されていない場合、UUID が自動的に生成されます。

use adk_session::{InMemorySessionService, SessionService, CreateRequest};
use std::collections::HashMap;

let service = InMemorySessionService::new();

// Create with auto-generated ID
let session = service.create(CreateRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: None,
    state: HashMap::new(),
}).await?;

// Create with specific ID
let session = service.create(CreateRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: Some("my-custom-id".to_string()),
    state: HashMap::new(),
}).await?;

2. 取得

セッションをその識別子で取得します。

use adk_session::GetRequest;

let session = service.get(GetRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: "session_abc".to_string(),
    num_recent_events: None,
    after: None,
}).await?;

println!("Retrieved session: {}", session.id());
println!("Events: {}", session.events().len());

3. イベントの追加

会話が進むにつれて、イベントはセッションに追加されます。これは通常 Runner によって処理されますが、手動で行うことも可能です。

use adk_session::Event;

let event = Event::new("invocation_123");
service.append_event(session.id(), event).await?;

4. リスト表示

ユーザーのすべてのセッションをリスト表示します。

use adk_session::ListRequest;

let sessions = service.list(ListRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
}).await?;

for session in sessions {
    println!("Session: {} (updated: {})", 
        session.id(), 
        session.last_update_time()
    );
}

5. 削除

不要になったセッションを削除します。

use adk_session::DeleteRequest;

service.delete(DeleteRequest {
    app_name: "my_app".to_string(),
    user_id: "user_123".to_string(),
    session_id: "session_abc".to_string(),
}).await?;

Runnerでのセッションの使用

セッションは、エージェントの実行時に通常Runnerによって管理されます。Runnerは以下の処理を行います。

  1. セッションを作成または取得します
  2. セッションコンテキストをエージェントに渡します
  3. 会話の進行に合わせてイベントを追加します
  4. エージェントのアクションに基づいてセッションの状態を更新します
use adk_rust::prelude::*;
use adk_runner::{Runner, RunnerConfig};
use adk_session::InMemorySessionService;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    let api_key = std::env::var("GOOGLE_API_KEY")?;
    let model = Arc::new(GeminiModel::new(&api_key, "gemini-2.0-flash")?);

    let agent = LlmAgentBuilder::new("assistant")
        .model(model)
        .instruction("You are a helpful assistant.")
        .build()?;

    let session_service = Arc::new(InMemorySessionService::new());

    // Create runner with session service
    let runner = Runner::new(RunnerConfig {
        app_name: "my_app".to_string(),
        agent: Arc::new(agent),
        session_service,
        artifact_service: None,
        memory_service: None,
        run_config: None,
    })?;

    // Run with user and session IDs
    let user_content = Content::new("user").with_text("Hello!");
    let stream = runner.run(
        "user_123".to_string(),
        "session_abc".to_string(),
        user_content,
    ).await?;

    Ok(())
}

イベント

Eventsトレイトは、会話履歴へのアクセスを提供します。

pub trait Events: Send + Sync {
    /// Get all events
    fn all(&self) -> Vec<Event>;
    
    /// Get number of events
    fn len(&self) -> usize;
    
    /// Get event at index
    fn at(&self, index: usize) -> Option<&Event>;
    
    /// Check if empty
    fn is_empty(&self) -> bool;
}

セッションからイベントにアクセスする例:

let events = session.events();
println!("Total events: {}", events.len());

for event in events.all() {
    println!("Event {} by {} at {}", 
        event.id, 
        event.author, 
        event.timestamp
    );
}

完全な例

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

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let service = InMemorySessionService::new();
    
    // Create session with initial state
    let mut initial_state = HashMap::new();
    initial_state.insert(format!("{}name", KEY_PREFIX_USER), json!("Alice"));
    initial_state.insert("topic".to_string(), json!("Getting started"));
    
    let session = service.create(CreateRequest {
        app_name: "demo".to_string(),
        user_id: "alice".to_string(),
        session_id: None,
        state: initial_state,
    }).await?;
    
    println!("Created session: {}", session.id());
    
    // Check state
    let state = session.state();
    println!("User name: {:?}", state.get("user:name"));
    println!("Topic: {:?}", state.get("topic"));
    
    // Append an event
    let event = Event::new("inv_001");
    service.append_event(session.id(), event).await?;
    
    // Retrieve session with events
    let session = service.get(GetRequest {
        app_name: "demo".to_string(),
        user_id: "alice".to_string(),
        session_id: session.id().to_string(),
        num_recent_events: None,
        after: None,
    }).await?;
    
    println!("Events: {}", session.events().len());
    
    // List all sessions
    let sessions = service.list(ListRequest {
        app_name: "demo".to_string(),
        user_id: "alice".to_string(),
    }).await?;
    
    println!("Total sessions: {}", sessions.len());
    
    // Delete session
    service.delete(DeleteRequest {
        app_name: "demo".to_string(),
        user_id: "alice".to_string(),
        session_id: session.id().to_string(),
    }).await?;
    
    println!("Session deleted");
    
    Ok(())
}

関連


前へ: ← MCP Tools | 次へ: ステート管理 →