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_sessioningere 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ão | Memória | |
|---|---|---|
| Duração | Uma conversa | Entre conversas |
| API | adk-session (SessionService, state map) | adk-memory (MemoryService) |
| Armazena | O transcript vivo + estado temporário | Fatos duráveis que valem a pena lembrar depois |
| Lê | Sempre no contexto | Sob 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.
}
| Backend | Escopo do projeto |
|---|---|
InMemoryMemoryService | Sim |
SqliteMemoryService | Sim |
PostgresMemoryService | Sim |
RedisMemoryService | Sim |
MongoMemoryService | Sim |
Neo4jMemoryService | Sim |
GraphMemoryService | Nã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 →