메모리

adk-memory를 사용하는 AI 에이전트를 위한 장기 의미론적 메모리.

개요

메모리 시스템은 에이전트 대화를 위한 영구적이고 검색 가능한 저장소를 제공합니다. (일시적인) 세션 상태와 달리, 메모리는 세션 간에 지속되며 에이전트가 과거 상호 작용에서 관련 컨텍스트를 불러올 수 있도록 합니다.

설치

[dependencies]
adk-memory = "0.2.0"

핵심 개념

MemoryEntry

content, author, timestamp를 포함하는 단일 메모리 레코드:

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. 각 메모리의 content가 토큰화됩니다.
  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 {
    // Your vector DB client
}

#[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. Generate embeddings for each entry
        // 2. Store in vector database with metadata
        Ok(())
    }

    async fn search(&self, req: SearchRequest) -> Result<SearchResponse> {
        // 1. Generate embedding for query
        // 2. Perform similarity search
        // 3. Return top-k results
        Ok(SearchResponse { memories: vec![] })
    }
}

Agent와의 통합

메모리는 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            │
└─────────────────────────────────────────────────────────────┘

모범 사례

관행설명
프로덕션에서 벡터 DB 사용InMemory는 개발/테스트 전용입니다
사용자별 범위 지정개인 정보 보호를 위해 항상 user_id를 포함하세요
결과 제한컨텍스트 오버플로를 방지하기 위해 반환되는 기억을 제한하세요
오래된 기억 정리오래된 데이터에 대한 TTL 또는 아카이빙을 구현하세요
전략적으로 임베딩원시 대화가 아닌 요약을 저장하세요

Session과의 비교

기능Session 상태기억
지속성Session 수명영구적
범위단일 SessionSession 간
검색키-값 조회의미론적 검색
사용 사례현재 컨텍스트장기 기억

이전: ← Guardrails | 다음: Studio →