Conceitos de Memória

O lado do semantic-store da memória é construído a partir de alguns tipos pequenos. Aprenda esses quatro e o restante da seção se segue.

MemoryEntry

Um único registro de memória: algum conteúdo, quem o ავტorizou, e quando.

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

Entries são a unidade de armazenamento e a unidade de recuperação — search retorna as entries mais relevantes para uma consulta.

O trait MemoryService

Todo backend implementa um trait. Dois métodos são obrigatórios; o restante tem implementações padrão que um backend pode sobrescrever:

#[async_trait]
pub trait MemoryService: Send + Sync {
    // Required
    async fn add_session(&self, app: &str, user: &str, session: &str,
                         entries: Vec<MemoryEntry>) -> Result<()>;
    async fn search(&self, req: SearchRequest) -> Result<SearchResponse>;

    // Optional (default: "not implemented")
    async fn delete_user(&self, app: &str, user: &str) -> Result<()>;          // GDPR
    async fn delete_session(&self, app: &str, user: &str, session: &str) -> Result<()>;
    async fn add_entry(&self, app: &str, user: &str, entry: MemoryEntry) -> Result<()>;
    async fn delete_entries(&self, app: &str, user: &str, query: &str) -> Result<u64>;
    // …plus a health check
}
  • add_session ingere uma conversa concluída inteira de entries. Um Runner chama isso para você quando a memory está anexada.
  • search é a recuperação. Os backends interpretam a consulta de forma diferente — keyword, similaridade de embedding, ou pontuação de tokens em grafo — mas o contrato é o mesmo.

SearchRequest / SearchResponse

use adk_memory::SearchRequest;

let req = SearchRequest {
    app_name: "support".into(),
    user_id:  "alice".into(),
    query:    "contact preference".into(),
    ..Default::default()      // top_k, project scoping, etc.
};

let resp = memory.search(req).await?;   // resp.entries: Vec<MemoryEntry>

Estado da sessão vs. memória

Estas são ferramentas diferentes — não as confunda:

Estado da sessãoMemória
DuraçãoUma conversaEntre conversas
APIadk-session (SessionService, state map)adk-memory (MemoryService)
ArmazenaO transcript vivo + estado temporárioFatos duráveis que valem a pena lembrar depois
Sempre no contextoSob demanda, via search_memory

Um fluxo típico: a conversa vive no estado da sessão; quando ela termina (ou a cada turno), as partes relevantes são gravadas na memória; a próxima sessão pesquisa a memória para reidratar o contexto. Veja Sessions & State.

Isolamento: app, usuário e projeto

A memória é sempre indexada por (app_name, user_id), então os usuários nunca veem as memórias uns dos outros. Você pode delimitar um terceiro nível — projeto — dentro de um usuário:

  • Entradas globais (project_id = None) — visíveis em qualquer contexto.
  • Entradas de projeto (project_id = Some(id)) — visíveis apenas dentro desse projeto.
  • Busca de projeto retorna entradas globais + entradas de projeto correspondentes; a busca global retorna apenas entradas globais.
use adk_memory::{MemoryServiceAdapter, InMemoryMemoryService};
use std::sync::Arc;

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

// store within a project
service.add_session_to_project("app", "user", "sess", "acme-project", entries).await?;

// an adapter scoped to that project
let adapter = MemoryServiceAdapter::new(service, "app", "user")
    .with_project_id("acme-project");

Use projetos para evitar que, por exemplo, assistentes de trabalho e pessoais de um usuário compartilhem memória, sem deixar de compartilhar fatos realmente globais.

Nem todo backend implementa o escopo de projeto

O isolamento por projeto é uma capacidade do backend, não algo que o trait possa garantir. Pergunte antes de depender disso:

if service.supports_project_scoping() {
    service.add_entry_to_project("app", "user", "acme-project", entry).await?;
} else {
    // Decide explicitly: refuse, or store globally on purpose.
}
BackendEscopo do projeto
InMemoryMemoryServiceSim
SqliteMemoryServiceSim
PostgresMemoryServiceSim
RedisMemoryServiceSim
MongoMemoryServiceSim
Neo4jMemoryServiceSim
GraphMemoryServiceNão — os métodos do projeto retornam um erro

Um backend sem suporte a projeto falha a chamada em vez de gravar ou excluir globalmente de forma silenciosa. Ampliar o escopo de uma gravação tornaria dados destinados a um projeto visíveis para tudo sob o mesmo app e usuário, e ampliar uma exclusão removeria entradas fora do projeto nomeado — nenhuma das duas coisas é algo que um chamador pudesse detectar pelo valor de retorno. MemoryServiceAdapter::supports_project_scoping informa o que seu backend suporta.

Exclusão por GDPR

delete_user(app, user) remove todas as memórias de um usuário (entradas e embeddings) em todos os projetos — o primitivo de direito ao apagamento. Backends que armazenam de forma durável implementam isso; chame-o no seu caminho de exclusão de conta.

memory.delete_user("support", "alice").await?;

Próximo: Backends →