メモリ

adk-memory を使用したAI Agentのための長期的意味記憶。

概要

メモリシステムは、Agentの会話を永続的に検索可能なストレージとして提供します。セッションの状態(一時的)とは異なり、メモリはセッション間で永続化され、Agentが過去のやり取りから関連するコンテキストを思い出すことを可能にします。

インストール

[dependencies]
adk-memory = "0.2.0"

主要な概念

MemoryEntry

コンテンツ、作成者、タイムスタンプを含む単一のメモリレコード:

use adk_memory::MemoryEntry;
use adk_core::Content;
use chrono::Utc;

let entry = MemoryEntry {
    content: Content::new("user").with_text("I prefer dark mode"),
    author: "user".to_string(),
    timestamp: Utc::now(),
};

MemoryService Trait

メモリバックエンドの中核となるtrait:

#[async_trait]
pub trait MemoryService: Send + Sync {
    /// Store session memories for a user
    async fn add_session(
        &self,
        app_name: &str,
        user_id: &str,
        session_id: &str,
        entries: Vec<MemoryEntry>,
    ) -> Result<()>;

    /// Search memories by query
    async fn search(&self, req: SearchRequest) -> Result<SearchResponse>;
}

SearchRequest

メモリ検索のためのクエリパラメータ:

use adk_memory::SearchRequest;

let request = SearchRequest {
    query: "user preferences".to_string(),
    user_id: "user-123".to_string(),
    app_name: "my_app".to_string(),
};

InMemoryMemoryService

開発およびテスト用のシンプルなインメモリ実装:

use adk_memory::{InMemoryMemoryService, MemoryService, MemoryEntry, SearchRequest};
use adk_core::Content;
use chrono::Utc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let memory = InMemoryMemoryService::new();

    // Store memories from a session
    let entries = vec![
        MemoryEntry {
            content: Content::new("user").with_text("I like Rust programming"),
            author: "user".to_string(),
            timestamp: Utc::now(),
        },
        MemoryEntry {
            content: Content::new("assistant").with_text("Rust is great for systems programming"),
            author: "assistant".to_string(),
            timestamp: Utc::now(),
        },
    ];

    memory.add_session("my_app", "user-123", "session-1", entries).await?;

    // Search memories
    let request = SearchRequest {
        query: "Rust".to_string(),
        user_id: "user-123".to_string(),
        app_name: "my_app".to_string(),
    };

    let response = memory.search(request).await?;
    println!("Found {} memories", response.memories.len());

    Ok(())
}

メモリの分離

メモリは以下によって分離されます。

  • app_name: 異なるアプリケーションは別々のメモリ空間を持ちます
  • user_id: 各ユーザーのメモリはプライベートです
// User A's memories
memory.add_session("app", "user-a", "sess-1", entries_a).await?;

// User B's memories (separate)
memory.add_session("app", "user-b", "sess-1", entries_b).await?;

// Search only returns user-a's memories
let request = SearchRequest {
    query: "topic".to_string(),
    user_id: "user-a".to_string(),
    app_name: "app".to_string(),
};

検索動作

InMemoryMemoryService は単語ベースのマッチングを使用します。

  1. クエリは単語にトークン化されます (小文字)
  2. 各メモリのコンテンツがトークン化されます
  3. 一致する単語を含むメモリが返されます
// Query: "rust programming"
// Matches memories containing "rust" OR "programming"

カスタムメモリバックエンド

カスタムストレージ(例:ベクトルデータベース)用に MemoryService を実装します。

use adk_memory::{MemoryService, MemoryEntry, SearchRequest, SearchResponse};
use adk_core::Result;
use async_trait::async_trait;

pub struct VectorMemoryService {
    // あなたのベクトルDBクライアント
}

#[async_trait]
impl MemoryService for VectorMemoryService {
    async fn add_session(
        &self,
        app_name: &str,
        user_id: &str,
        session_id: &str,
        entries: Vec<MemoryEntry>,
    ) -> Result<()> {
        // 1. 各エントリの埋め込みを生成する
        // 2. メタデータとともにベクトルデータベースに保存する
        Ok(())
    }

    async fn search(&self, req: SearchRequest) -> Result<SearchResponse> {
        // 1. クエリの埋め込みを生成する
        // 2. 類似度検索を実行する
        // 3. 上位k件の結果を返す
        Ok(SearchResponse { memories: vec![] })
    }
}

エージェントとの統合

メモリは LlmAgentBuilder と統合します。

use adk_agent::LlmAgentBuilder;
use adk_memory::InMemoryMemoryService;
use std::sync::Arc;

let memory = Arc::new(InMemoryMemoryService::new());

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

メモリが設定されている場合:

  1. 各ターンが開始する前に、関連するメモリが検索されます
  2. マッチするメモリがコンテキストに注入されます
  3. 各セッションの後、会話がメモリとして保存されます

アーキテクチャ

┌─────────────────────────────────────────────────────────────┐
│                      Agent Request                          │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Memory Search                            │
│                                                             │
│   SearchRequest { query, user_id, app_name }               │
│                         │                                   │
│                         ▼                                   │
│   ┌─────────────────────────────────────────────────────┐  │
│   │              MemoryService                          │  │
│   │  ┌─────────────┐  ┌─────────────┐  ┌────────────┐  │  │
│   │  │ InMemory    │  │ Vector DB   │  │ Custom     │  │  │
│   │  │ (dev/test)  │  │ (Qdrant)    │  │ Backend    │  │  │
│   │  └─────────────┘  └─────────────┘  └────────────┘  │  │
│   └─────────────────────────────────────────────────────┘  │
│                         │                                   │
│                         ▼                                   │
│   SearchResponse { memories: Vec<MemoryEntry> }            │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│              Context Injection                              │
│                                                             │
│   Relevant memories added to agent context                 │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Agent Execution                          │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                   Memory Storage                            │
│                                                             │
│   Session conversation stored for future recall            │
└─────────────────────────────────────────────────────────────┘

ベストプラクティス

プラクティス説明
本番環境ではvector DBを使用するInMemoryは開発/テスト専用です
ユーザーごとにスコープを設定するプライバシーのために常にuser_idを含める
結果を制限するコンテキストオーバーフローを避けるため、返されるメモリを制限する
古いメモリをクリーンアップする古いデータにはTTLまたはアーカイブを実装する
戦略的に埋め込む生の会話ではなく、要約を保存する

セッションとの比較

機能セッション状態メモリ
永続性セッションの寿命永続的
スコープ単一セッションセッション間
検索キーバリュー検索セマンティック検索
ユースケース現在のコンテキスト長期的な想起

前へ: ← Guardrails | 次へ: Studio →