[!NOTE] Tradução automática Este artigo foi traduzido automaticamente a partir da versão original em inglês.
Memória de Agente de IA: Estado Tipado Orientado por Esquema para Sistemas em Execução Contínua
Agentes que operam por períodos prolongados costumam recuperar informações desatualizadas, pois a memória semântica convencional não dispõe de regras para determinar qual valor é o atual.
Quando um utilizador altera a data limite de um passaporte de 15 de julho para 30 de junho, a busca vetorial pode recuperar ambas as afirmações. Uma camada de memória com estado deve registar que o valor de 30 de junho substitui o anterior.
TL;DR: Trate a memória duradoura do agente como um estado da aplicação tipado. Extraia os candidatos à memória através de uma fronteira de saída estruturada, armazene os registos com escopo de utilizador, janelas de validade, regras de substituição, proveniência e versionamento de esquemas, e recupere apenas a parte mais recente no caminho de leitura. Reserva a busca vetorial para recuperação aproximada. Leia os factos mutáveis a partir de registos atuais e delimitados.
A armadilha da janela de contexto
A janela de contexto representa os dados de entrada disponíveis para uma única chamada do modelo. Uma aplicação pode transmitir mensagens para chamadas posteriores, mas a política da aplicação deve decidir quais factos antigos continuam válidos e quem pode acedê-los.
Agentes em execução contínua precisam de memorizar preferências, status de tarefas, dados de clientes, decisões relativas a ferramentas, notas de conformidade e erros anteriores. A abordagem mais simples consiste em adicionar resumos ou guardar notas antigas num repositório vetorial. Isso funciona até que um dos factos memorizados seja alterado.
Nesse caso, o agente passa a ter dois prazos de passaporte, dois formatos preferidos ou duas decisões de projeto. A busca semântica pode recuperar ambos. Um resumo pode sobrescrever um deles. Um contexto extenso pode incluir o facto desatualizado ao lado do atual. Esses designs permitem a recuperação de texto, mas sem garantir a aplicação do valor atual.
O contrato deve responder a questões concretas:
- O que é verdadeiro agora?
- O que era verdadeiro em 2 de junho?
- Quem o afirmou?
- A que utilizador pertence?
- Qual facto anterior foi substituído por este?
- Posso eliminá-lo ou torná-lo expirado?
A Memória de Agente Orientada por Esquema (SGAM) armazena essas respostas como campos e relações, em vez de as deixar implícitas no texto.
O que significa SGAM
Três conceitos com nomes semelhantes definem o âmbito da SGAM.
Diálogo Orientado por Esquema (SGD) refere-se ao conjunto de dados de diálogo orientado a tarefas da Google de 2019. O seu esquema descreve APIs de serviço, intenções e slots, permitindo que um modelo de diálogo acompanhe o estado de serviços que ainda não viu. É um precedente útil para o rastreio baseado em esquemas, embora com escopo limitado a serviços de diálogo.
Memória Orientada por Esquema (SGM) é o termo de investigação utilizado por Mei et al. em According to Me: Long-Term Personalized Referential Memory QA. O artigo compara a Memória Descritiva (DM) em formato de texto livre com itens de memória em formato chave-valor com esquema fixo. Ambas as representações contêm as mesmas informações de origem, mas em estruturas diferentes.
Neste artigo, uso Memória de Agente Orientada por Esquema (SGAM) para designar um padrão de engenharia no qual os esquemas regulam as operações de escrita, atualização, recuperação e eliminação. O esquema define o estado da aplicação e o seu ciclo de vida.
O ATM-Bench demonstra por que a representação é importante. Ele utiliza cerca de quatro anos de dados pessoais provenientes de e-mails, imagens e vídeos. As perguntas exigem referências pessoais, localização, múltiplas provas e atualizações ao longo do tempo. O desempenho diminui quando se utiliza a separação tradicional, enquanto a SGM melhora em relação à DM, pois o mecanismo de recuperação consegue aceder diretamente a campos como hora, fonte, localização, entidades e etiquetas.
SGM versus DM aborda uma questão de armazenamento: a memória deve permanecer em formato de texto livre ou utilizar campos nomeados? Um agente em produção enfrenta outro desafio antes do armazenamento: precisa raciocinar a partir de uma conversa não estruturada para determinar uma atualização adequada na memória. O Schema-Guided Reasoning (SGR) define esse processo: inspecionar as evidências, identificar o sujeito e os atributos, verificar se o fato altera o estado existente e, em seguida, gerar uma proposta de escrita. O SGAM aplica as regras de armazenamento e de ciclo de vida após essa chamada ao modelo.
Separação entre extração do modelo e propriedade da memória
A escrita na memória atravessa três camadas. O Structured Output (SO) garante a estrutura correta do objeto proposto. O Schema-Guided Reasoning (SGR) codifica os passos e a ordem que o modelo deve seguir para chegar a essa proposta. Já o Schema-Guided Agent Memory (SGAM) gere esse objeto como um estado duradouro após a chamada ao modelo.
Uma decisão, rota ou plano geralmente expira com a solicitação atual. Uma nova execução pode ler essa proposta de memória dias depois ou utilizá‑la para escolher uma chamada de ferramenta. Esse período mais longo exige regras de armazenamento que o SGR não oferece.
O SGR restringe uma única chamada ao modelo ao definir sua topologia de raciocínio. Para uma escrita na memória, o esquema pode exigir evidências de origem, um sujeito e atributos normalizados, uma comparação com o estado atual e, somente então, a atualização proposta. Ferramentas como Pydantic ou JSON Schema descrevem esse fluxo. O Structured Output nativo do fornecedor ou um ambiente de decodificação guiado, como o XGrammar, impede que o modelo pule campos ou retorne uma estrutura diferente.
O esquema não consegue garantir uma conclusão correta. Ele torna explícito e inspecionável o caminho de decisão necessário, incluindo as evidências e a comparação que geraram a proposta.
O SGAM decide o que acontece após o objeto ser criado. Deve ser armazenado? Substitui um fato anterior? Qual usuário pode acessá‑lo? É atual ou histórico? Qual episódio de fonte o sustenta?
A tabela abaixo indica a propriedade responsável e o modo de falha de cada camada:
| Dimensão | SO | SGR | SGAM |
|---|---|---|---|
| Finalidade | Devolver um objeto que esteja em conformidade com um esquema | Orientar o modelo ao longo de um caminho de raciocínio predefinido | Gerir a memória persistente após a chamada ao modelo |
| Âmbito | Uma resposta gerada | Um caminho de raciocínio e decisão numa única chamada ao modelo | Registos utilizados entre chamadas, sessões e execuções |
| Papel no esquema | Define os campos de saída, tipos e valores permitidos | Define as fases intermédias de raciocínio e a decisão final | Define os registos armazenados, relações e seu ciclo de vida |
| Aplicação da regra | Bloqueia a decodificação de outputs inválidos segundo o esquema | Utiliza o SO para exigir a execução de cada fase declarada e da decisão final | Validação da aplicação, restrições de base de dados e regras de conflito |
| Duração | A chamada atual, a menos que a aplicação armazene o objeto | O rasto de raciocínio é normalmente descartado após a decisão | Permanece até ser atualizado, expirar ou ser eliminado |
| Modo de falha | Formato válido, mas com significado incorreto | Os passos necessários estão presentes, mas o raciocínio ainda pode estar errado | Estado obsoleto, poluído, sem âmbito definido ou impossível de auditar |
No caminho de escrita, a sequência é:
SGR reasoning schema + Structured Output -> candidate write -> SGAM policy and persistence
O seguinte excerto ilustrativo de memory_models.py define o objeto transmitido da extração para o serviço de escrita do SGAM:
from datetime import datetime
from pydantic import BaseModel, Field
class MemoryDelta(BaseModel):
tenant_id: str = Field(description="Isolation boundary, e.g. acme")
subject: str = Field(description="Normalized entity ID, e.g. mira")
attribute: str = Field(description="Property being updated")
value: str = Field(description="New value")
valid_from: datetime
source_episode_id: str
MemoryDelta mostra o que foi extraído pelo modelo. O serviço de escrita do SGAM decide ainda se o deve rejeitar, fundir ou armazenar.
Os caminhos de escrita e leitura têm funções distintas
O SGAM dispõe de um caminho de escrita e um de leitura. Apenas o caminho de escrita modifica o estado armazenado. O caminho de leitura seleciona os registos necessários para a solicitação atual.
O fluxo de ingestão corresponde ao caminho de escrita:
- Capturar um episódio bruto a partir de mensagens, resultados de ferramentas ou eventos empresariais.
- Extrair candidatos estruturados através da saída formatada.
- Validar o esquema e rejeitar registos mal formatados.
- Resolver conflitos, encerrar factos obsoletos e manter a proveniência.
- Cometer o registo no armazenamento do SGAM.
O fluxo de solicitação corresponde ao caminho de leitura:
- Partir da pergunta do utilizador.
- Decidir se a pergunta requer o estado atual ou um estado em determinado momento.
- Filtrar por inquilino, tipo de memória, assunto, atributo e janela de validade.
- Adicionar expansão vetorial ou gráfica apenas se a consulta direta ao estado não for suficiente.
- Compilar o contexto mais reduzido necessário para o modelo.
Leia esse diagrama da esquerda para a direita, em duas faixas. A faixa superior escreve na memória, enquanto a inferior a lê. Ambas utilizam o mesmo armazenamento.
O que deve constar num esquema de memória
Um registo SGAM mínimo requer mais do que text.
tenant_id
memory_id
subject
attribute
value
memory_type
schema_version
valid_from
valid_to
supersedes_memory_id
source_episode_id
confidence
retention_policy
Com estes campos, um novo prazo de passaporte pode substituir o prazo anterior sem apagar o histórico. A mesma tabela permite responder a consultas atuais e em determinado momento, podendo depois rastrear o resultado até ao episódio de origem. schema_version suporta migrações, enquanto retention_policy indica aos job de eliminação quais outros elementos devem ser removidos.
Deve‑se utilizar RAG para recuperar documentos e SGAM para gerir o estado mutável. A busca vetorial continua a ser essencial no sistema para recuperação fuzzy, agrupamento e expansão de resultados. O valor atual de mira.passport_deadline deve provir de um registo de memória delimitado, e não do primeiro bloco que aparecer classificado.
Exemplo de facto obsoleto
Considere um rasto sintético composto por dois episódios, representado por uma linha de base DM e um livro‑razão SGAM:
e1: Mira prefers concise answers. Her passport deadline is 2026-07-15.
e2: Mira corrected the deadline. It is now 2026-06-30.
Uma linha de base DM armazena ambos os episódios como texto livre, pelo que a busca por texto pode retornar e1, uma vez que contém as palavras corretas. O SGAM extrai um facto tipado de cada episódio, indexado por inquilino, assunto e atributo. Deve retornar e2 como estado atual e manter e1 para consultas históricas.
A função seguinte corresponde ao código do caminho de escrita do SGAM. Ela ficaria num módulo de armazenamento como sgam_store.py. O DM não possui um equivalente, pois não mantém uma linha atual por atributo. Antes de o chamador inserir uma substituição, esta função fecha a linha atual:
def close_previous_fact(db: sqlite3.Connection, fact: MemoryFact) -> int | None:
row = db.execute(
"""
select fact_id
from memory_facts
where tenant_id = ?
and subject = ?
and attribute = ?
and valid_to is null
order by valid_from desc
limit 1
""",
(fact.tenant_id, fact.subject, fact.attribute),
).fetchone()
if not row:
return None
db.execute(
"update memory_facts set valid_to = ? where fact_id = ?",
(fact.valid_from, row["fact_id"]),
)
return int(row["fact_id"])
Quando e2 chega, a função define valid_to no facto extraído de e1 para o timestamp de e2. Em seguida, o chamador insere o novo facto com um valid_to ainda aberto. Como o DM não tem um passo de atualização correspondente, o texto antigo pode continuar a ter prioridade sobre a correção.
A execução de consultas atuais e históricas sobre prazos com ambas as representações produz resultados diferentes:
Naive text memory:
returned episode: e1 -> passport deadline is 2026-07-15
SGAM current state:
mira.passport_deadline = 2026-06-30
valid_from=2026-06-03T10:00:00Z, source=e2
SGAM point-in-time state:
on 2026-06-02, mira.passport_deadline = 2026-07-15
Em produção, deve‑se associar esta transação à extração estruturada no caminho de escrita. A transação de base de dados atualiza a validade temporal. O modelo extrai um facto candidato, mas não decide qual linha armazenada permanece atual.
As escolhas de armazenamento seguem o padrão de recuperação
Os projetos utilizam vários nomes para partes deste padrão: armazenamentos de memória, grafos de contexto, perfis, armazenamentos de longo prazo, RAG de grafos e agentes com estado.
| Ferramenta ou framework | Camada principal de armazenamento | Mecanismo de estado temporal | Mecanismo de esquema | Nicho prático |
|---|---|---|---|---|
| Zep / Graphiti | Neo4j, FalkorDB, Neptune, suporte a Kuzu legado | Intervalos de validade dos factos e proveniência das fontes | Tipos de entidade e aresta em Pydantic, arestas temporais, proveniência | Memória de grafos temporais |
| LangGraph / LangMem | Armazenamentos LangGraph, armazenamentos baseados em Postgres | Timestamps e campos pertencentes à aplicação nos registos do armazenamento | Armazenamentos em JSON mais extração de perfis ou coleções em Pydantic | Aplicações de agente já desenvolvidas com LangGraph |
| Mem0 | Stack gerida, backends Valkey / Redis / vector em ambientes OSS | Atualizações de memória; a política temporal permanece sob responsabilidade da aplicação | Tipos de memória, categorias personalizadas, prompts de extração | Memória de utilizador, agente e sessão como serviço |
| Letta / MemGPT | Estado do agente e blocos de memória baseados em base de dados | Blocos editáveis sem intervalos de validade a nível de campo | Blocos de memória rotulados e editáveis | Agentes com estado e gestão de contexto ao estilo do SO |
| Cognee | Backends de grafos, vector e relacionais | O histórico depende da ontologia e do backend selecionado | Extração e validação orientadas para a ontologia | Memória de grafos de conhecimento empresarial |
| LlamaIndex property graph | Armazenamentos de grafos de propriedades mais armazenamentos vectoriais | Campos de tempo dependem do esquema do grafos e do armazenamento | SchemaLLMPathExtractor com entidades e relações permitidas | Extração de grafos a partir de documentos e rastreios |
Graphiti é uma implementação concreta em código aberto de memória relacional e temporal. Ele regista as alterações nos factos, mantém ponteiros para as episódios de origem e suporta recuperação híbrida. LangGraph separa os pontos de verificação por thread dos armazenamentos entre threads. Mem0 apresenta as operações de memória como um serviço gerido. Letta utiliza blocos de contexto editáveis em vez de SGAM a nível de campo, mas continua a tratar o estado do agente como dados persistentes.
Comece pelo modelo de dados. Se a consulta exata de factos for a operação principal, geralmente basta uma tabela relacional com payloads em JSON, colunas de validade, índices por utilizador e um sidecar vectorial. Adicione um grafos apenas quando a navegação por relações fizer parte do produto, e não porque a demonstração com grafos pareça impressionante.
Construir o caminho de escrita antes do grafo
Primeiro, defina o que o produto pode memorizar. A escolha entre grafo e vetor será feita posteriormente.
Um agente de suporte pode guardar o nível da conta, casos abertos e preferências de contacto duradouras. Não deve transformar cada reclamação do utilizador em um estado no perfil. Um agente de programação pode memorizar convenções do repositório e tarefas não resolvidas. Não deve conservar uma nota privada indefinidamente só porque essa nota foi consultada uma vez.
Comece com o caminho de escrita e trate a memória como uma pequena mutação de estado:
- Defina o tipo de memória, o assunto, o escopo do utilizador e a classe de retenção.
- Extraia os registos candidatos com saída estruturada.
- Valide a carga com Pydantic ou com a camada de esquema já utilizada pela sua arquitetura.
- Resolva conflitos antes da inserção, incluindo se o novo registo substitui um antigo.
- Mantenha um ponteiro de origem para o episódio bruto, resultado da ferramenta, ficheiro, ticket ou confirmação do utilizador que gerou o registo.
- Registe a versão do esquema junto de cada registo, em vez de a deixar apenas no código da aplicação.
O primeiro armazenamento SGAM pode ser uma tabela relacional com uma coluna JSON e alguns índices. O grafo torna-se útil quando o produto precisa percorrer relações como cliente-conta, conta-política, tarefa-artefato ou projeto-Decisão.
Caminho imediato e escritas em segundo plano
A extração imediata vale a pena quando a próxima interação depende da nova memória. Se o utilizador disser “lembre-se de que prefiro respostas curtas”, o sistema não precisa de uma tarefa noturna para começar a agir de forma diferente.
A maioria das interações não requer escrita imediata. Guarde o episódio bruto com metadados do utilizador, sessão e ferramenta, e deixe que um processo em segundo plano extraia os registos candidatos mais tarde. Com consolidação baseada em recorrência, o processo armazena temporariamente sinais fracos e promove um facto apenas após evidências semelhantes se repetirem ou o utilizador o confirmar. Isso gera um atraso na atualização dos dados. Isso é aceitável para casos como “o utilizador pede frequentemente exportações em CSV”, mas arriscado em situações como “o cliente alterou o endereço de entrega”.
Mantenha o caminho de leitura determinístico. Imponha primeiro o escopo do utilizador e a validade, e utilize a recuperação por similaridade apenas quando isso puder adicionar contexto útil.
- Filtre por utilizador, tipo de memória e janela de validade.
- Recupere primeiro o estado estruturado exato, e depois os vizinhos semânticos.
- Utilize expansão por vetores ou grafo para obter evidências complementares, entidades relacionadas e exemplos, e não como fonte autorizada dos factos atuais.
- Monte o menor conjunto de contexto possível que permita responder à pergunta.
Trate a migração de esquemas como uma alteração no produto, pois ela modifica o que o agente pode recordar, citar ou eliminar. Também pode alterar quais factos históricos são considerados atuais. Planeie scripts de migração, processos de preenchimento retroativo, períodos de leitura dupla e comportamentos de eliminação na mesma versão do produto.
Quando o SGAM justifica a complexidade
Utilize o SGAM quando os factos podem mudar ao longo do tempo:
- Preferências do utilizador que possam ser atualizadas ou revogadas
- Factos sobre clientes ou contas que exigem auditoria
- Estado de tarefas em assistentes de execução prolongada
- Memória de projetos de agentes de programação
- Estado partilhado entre vários agentes
- Notas de conformidade em que a proveniência é importante
- Perguntas temporais, como “no que acreditávamos antes da migração?”
O SGAM é um exagero quando a memória tem vida curta, é utilizada de forma exploratória ou quando seu recálculo é barato. Se o agente precisar apenas de algumas iterações de continuidade, um ponto de verificação e um histórico de mensagens reduzido são suficientes. Na verificação de qualidade de documentos estáticos, pode ser necessário apenas o RAG. E se o domínio for tão instável que o esquema muda todos os dias, a utilização de memória tipada irá atrasar a equipa.
Lista de verificação de avaliação
Avalie tanto o ciclo de vida da memória como a resposta final. Um sistema pode gerar uma resposta plausível mesmo após ter registado um facto incorreto, recuperado um dado desatualizado ou ultrapassado os limites definidos para um determinado utilizador.
Utilizo a mesma divisão fase a fase descrita no meu artigo de avaliação do RAG. Medimos a fase em que uma falha pode ocorrer, em vez de limitarmos a avaliação apenas ao texto gerado. A abordagem de rastreio do artigo de avaliação de agentes também é aplicável, pois um erro na memória costuma aparecer no histórico de execução antes de chegar à resposta.
Testaria o SGAM com reprodução de cenários. Inseriria uma sequência fixa de episódios no mecanismo de escrita da memória, inspecionaria o registo após cada iteração significativa e, em seguida, faria perguntas sobre o estado atual e sobre momentos específicos, utilizando o armazenamento resultante.
| Camada | Falha a ser detetada | Métricas utilizadas |
|---|---|---|
| Extração de escrita | O agente omitiu um facto, inventou um ou gerou uma estrutura inválida | Taxa de escritas válidas segundo o esquema, precisão/recall da extração, cobertura dos episódios de origem |
| Gestão de conflitos | Um facto desatualizado permaneceu ativo ou um facto antigo válido foi substituído | Correção da substituição, taxa de duplicatas, correção da invalidação de factos desatualizados |
| Isolamento e políticas | A memória vazou entre utilizadores ou permaneceu ativa além do prazo definido pela política | Falhas de isolamento por utilizador, correção das exclusões, conformidade com regras de retenção |
| Recuperação de leitura | O registo correto existe, mas o leitor não o recuperou | Precisão do estado atual, precisão em momentos específicos, recall@k entre os registos da memória |
| Anclagem da resposta | A resposta utilizou a memória sem suporte adequado ou citou a fonte errada | Verificação da existência de suporte nos episódios de origem, precisão das citações, correção na resolução de conflitos |
| Operações | O caminho de acesso à memória é demasiado lento, desatualizado ou dispendioso | Latência de escrita p95, atraso na atualização, latência de leitura, custo por consulta |
Benchmarks como LoCoMo, LongMemEval e ATM-Bench disponibilizam casos de teste públicos. No entanto, eles não substituem um conjunto de testes específico para o domínio em questão. Um assistente de programação, um bot de suporte ao cliente e um copiloto de conformidade exigem esquemas, filtros, regras de retenção e testes de falha diferentes.
Considerações importantes
SGAM é o meu rótulo para um determinado padrão, e não um padrão técnico estabelecido. Projetos existentes abordam o problema de forma diferente. LangGraph memory e LangMem descrevem mecanismos de armazenamento de curto e longo prazo, perfis, coleções, operações em caminhos críticos e gestores de memória em segundo plano. Zep Graphiti utiliza o termo “Grapho de Contexto Temporal”. Letta permite a persistência de blocos de memória editáveis, enquanto Mem0 oferece uma camada de memória gerida. Microsoft GraphRAG, os Graphs de propriedades do LlamaIndex e o Cognee tratam partes do problema como Graphos de conhecimento.
Um perfil de utilizador, um registo de episódios, um Graph de documentos e um bloco de memória editável por um agente resolvem problemas distintos de recuperação e atualização de dados. Reservo SGAM para a memória duradoura que representa o estado atual da aplicação, exigindo, portanto, esquema estruturado, validade, rastreabilidade da origem dos dados, gestão de conflitos, políticas de retenção e migração.
A memória tipada ainda pode conter erros. Um esquema facilita a inspeção de escritas incorretas, mas não garante a sua fiabilidade. Continua a ser necessário confiar nas fontes, obter confirmação do utilizador para factos sensíveis, definir políticas de gestão de conflitos, realizar exclusões e monitorizar a memória.
A migração de esquemas é um processo trabalhoso. Uma vez que a memória se torne parte do estado da aplicação, torna-se responsabilidade do desenvolvedor gerir a versãoização, os dados antigos, as regras de exclusão e o comportamento associado. Se esse processo for ignorado, os registos antigos permanecerão ativos mesmo após a mudança das políticas semânticas ou de retenção.
Referências
- According to Me: Long-Term Personalized Referential Memory QA - Artigo de Mei et al. que introduz o ATM-Bench e a memória orientada por esquema.
- Towards Scalable Multi-Domain Conversational Agents: The Schema-Guided Dialogue Dataset - Artigo de Rastogi et al. sobre o conjunto de dados SGD.
- LongMemEval: Benchmarking Chat Assistants on Long-Term Interactive Memory - Benchmark de Wu et al. para avaliar capacidades de memória a longo prazo.
- Graphiti: Build Temporal Context Graphs for AI Agents
- Zep: A Temporal Knowledge Graph Architecture for Agent Memory
- Mem0 Platform Overview
- Mem0: Building Production-Ready AI Agents with Scalable Long-Term Memory
- LangGraph Memory Overview
- LangGraph Persistence
- LangMem documentation
- Letta: Introduction to Stateful Agents
- Microsoft GraphRAG documentation
- LlamaIndex: Using a Property Graph Index
- Cognee Documentation
- Pydantic model validation docs
- Python sqlite3 documentation