Memória

Memória semântica de longo prazo para agentes de IA usando adk-memory.

Visão Geral

O sistema de memória oferece armazenamento persistente e pesquisável para conversas de agentes. Ao contrário do estado da sessão (que é efêmero), a memória persiste entre sessões e permite que os agentes relembrem o contexto relevante de interações passadas.

Instalação

[dependencies]
adk-memory = "0.2.0"

Conceitos Centrais

MemoryEntry

Um único registro de memória com content, author e 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(),
};

Trait MemoryService

O trait central para backends de memória:

#[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

Parâmetros de consulta para pesquisa de memória:

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

Implementação simples em memória para desenvolvimento e teste:

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(())
}

Isolamento de Memória

As memórias são isoladas por:

  • app_name: Diferentes aplicações têm espaços de memória separados
  • user_id: As memórias de cada user são privadas
// 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(),
};

Comportamento de Busca

O InMemoryMemoryService usa correspondência baseada em palavras:

  1. A query é tokenizada em palavras (minúsculas)
  2. O content de cada memória é tokenizado
  3. Memórias com quaisquer palavras correspondentes são retornadas
// Query: "rust programming"
// Matches memories containing "rust" OR "programming"

Backend de Memória Personalizado

Implemente MemoryService para armazenamento personalizado (por exemplo, banco de dados vetorial):

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![] })
    }
}

Integração com Agents

Memory se integra com 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()?;

Quando a memória é configurada:

  1. Antes de cada turno, memórias relevantes são pesquisadas
  2. Memórias correspondentes são injetadas no contexto
  3. Após cada sessão, a conversa é armazenada como memórias

Arquitetura

┌─────────────────────────────────────────────────────────────┐
│                      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            │
└─────────────────────────────────────────────────────────────┘

Melhores Práticas

PráticaDescrição
Use DB vetorial em produçãoInMemory é apenas para desenvolvimento/teste
Escopo por usuárioSempre inclua user_id para privacidade
Limite os resultadosLimite as memórias retornadas para evitar o transbordo de contexto
Limpe memórias antigasImplemente TTL ou arquivamento para dados obsoletos
Incorpore estrategicamenteArmazene resumos, não conversas brutas

Comparação com Sessions

RecursoEstado da SessionMemory
PersistênciaTempo de vida da SessionPermanente
EscopoÚnica SessionEntre Sessions
BuscaConsulta por chave-valorBusca semântica
Caso de usoContexto atualRecordação de longo prazo

Anterior: ← Guardrails | Próximo: Studio →