メモリ
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 は単語ベースのマッチングを使用します。
- クエリは単語にトークン化されます (小文字)
- 各メモリのコンテンツがトークン化されます
- 一致する単語を含むメモリが返されます
// 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()?;
メモリが設定されている場合:
- 各ターンが開始する前に、関連するメモリが検索されます
- マッチするメモリがコンテキストに注入されます
- 各セッションの後、会話がメモリとして保存されます
アーキテクチャ
┌─────────────────────────────────────────────────────────────┐
│ 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 →