Memory
Você construirá um armazenamento local de preferências e episódios com política de escopo e validade. Antes de executar, tente classificar quais informações de um atendimento merecem persistência e quais devem ser consultadas novamente. Essa tentativa revela a finalidade de cada memória.
Use dois usuários fictícios e tempos controlados. A demonstração local não implementa banco, RLS ou exclusão de backups. Sua entrega precisa separar o filtro de recuperação da remoção física e descrever as garantias necessárias na integração real.
JavaScriptAo terminar esta aula
- Memória durável exige política de dados.
- Vetores e relações atendem operações diferentes.
- Esquecimento precisa considerar cópias e escopos.
Antes de continuar: Leitura: Memory
Inventariar tipos e finalidade
FundamentosListe idioma confirmado, pedido atual, falha de consulta e pagamento observado. Classifique preferência, estado de thread e episódio, justificando retenção e atualização. Não transforme um pedido em inglês em preferência permanente sem critério. Retome origem e escopo da engenharia de contexto: cada item precisa de namespace e referência. Escreva casos que contradigam uma memória antiga. O contrato deve permitir corrigir, invalidar ou consultar novamente, em vez de conservar a primeira frase como verdade. Defina também campos que nunca serão persistidos, como credenciais desnecessárias.
↗ LangChain Memory overview↗ Effective context engineering for AI agents
Implementar recuperação e atualização
FundamentosExecute o filtro com u1 e u2 em tempos diferentes. Confirme que escopo e validade se aplicam antes de devolver conteúdo. Acrescente empresaId ao namespace e teste usuários com identificadores locais iguais em empresas diferentes. Implemente atualização de idioma com versão e origem, preservando referência da mudança. Para episódio, mantenha evento e data sem sobrescrever preferência. Compare estrutura relacional para chave exata com texto vetorial para busca por assunto. A decisão depende da operação; não force todo dado a uma coleção de embeddings.
Consolidar e avaliar resumo
FundamentosCrie dois episódios relacionados e um contraditório. Escreva um resumo antes da solução e compare com os originais. Ele deve preservar tempo, origem e pendência, sem transformar tentativa em sucesso. Use referência para recuperar detalhe quando o orçamento exigir. Avalie se a nova confirmação deve substituir preferência antiga e se o episódio continua útil. Consolidação precisa de política por tipo, não de uma regra global de manter a frase mais recente. Teste recuperação com pergunta atual para verificar que histórico é apresentado como histórico, não como estado financeiro vigente.
↗ Effective context engineering for AI agents↗ LangChain Memory overview
Expirar, remover e verificar privacidade
FundamentosImplemente remoção local separada do filtro e confirme que a lista realmente perdeu o item. Desenhe um inventário de cópias: tabela, índice vetorial, resumo, log e backup. Defina como a solicitação de esquecimento alcança cada sistema segundo sua política. TTL de uma chave não resolve sozinho essa coordenação. Para banco real, confira papéis e RLS e teste caminhos de serviço que possam contornar filtros. A rubrica exige isolamento, atualização correta, expiração e limites de remoção declarados. Feche com um mapa de garantias locais e integrações pendentes.
Unir sessão e persistência seletiva
FundamentosComplete o agente de memória com estado de atendimento e armazenamento durável separado. A sessão guarda objetivo, pedido e pendências; o armazenamento seletivo guarda preferências confirmadas e episódios úteis conforme política. Após terminar o caso, execute uma etapa de revisão de candidatos a memória, rejeitando segredos, hipóteses e dados sem finalidade. A recuperação recebe usuário e empresa de contexto autenticado e devolve apenas registros vigentes. Teste nova sessão, correção de idioma, expiração e remoção solicitada. Registre também o que não foi persistido e por quê. A entrega deve demonstrar continuidade sem transformar todo o histórico em perfil permanente. O compromisso entre conveniência e retenção é explícito, e o estudante consegue mostrar tanto lembrança correta quanto esquecimento dentro das garantias implementadas.
Caso adicional para diagnóstico e decisão
FundamentosConsidere um episódio que contém uma senha enviada por engano e uma preferência de idioma confirmada na mesma mensagem. O sistema não deve persistir a mensagem inteira para guardar apenas a preferência. Antes de consolidar, selecione campos pela finalidade e registre rejeição do segredo sem copiá-lo para outro log. Depois faça pedido de esquecimento da preferência e confirme que resumo e índice derivado também deixam de recuperá-la conforme a política implementada. A rubrica adicional exige minimização, escopo e inventário de cópias. Compare armazenar texto bruto com fatos estruturados e referência restrita ao episódio original. O primeiro preserva detalhe, mas aumenta exposição; o segundo facilita atualização seletiva, mas pode perder nuance. A escolha deve explicitar retenção e acesso. Esse caso retoma leakage e mostra que memória não é apenas conveniência: é um contrato de dados que precisa de atualização e remoção verificáveis.
Execução, inspeção e diagnóstico
FundamentosExecute consultas antes e depois da expiração e inspecione a lista original. O registro continua armazenado apesar de não ser recuperado. Acrescente uma função de remoção e compare os estados. Essa experiência evita chamar filtro de validade de esquecimento completo.
const memorias = [
{usuario:"u1",tipo:"preferencia",chave:"idioma",valor:"pt",origem:"confirmacao",expiresAt:2000},
{usuario:"u2",tipo:"preferencia",chave:"idioma",valor:"en",origem:"confirmacao",expiresAt:3000}
];
function recuperar(usuario,agora) {
return memorias.filter(m=>m.usuario===usuario && m.expiresAt>agora);
}
console.log("u1 vigente",recuperar("u1",1000));
console.log("u1 expirado",recuperar("u1",2500));Memória de outro usuário indica falha de namespace ou autorização. Preferência antiga indica política de atualização. Episódio tratado como estado atual indica montagem de contexto. Dado ainda em backup indica limite de remoção. O diagnóstico precisa apontar qual garantia falhou.
Exercício aplicado
Entregue memória local com tipos, escopo, atualização, expiração e plano de esquecimento.
- Tente classificar informações e finalidade.
- Execute filtros e correções de preferência.
- Consolide episódios preservando referências.
- Implemente remoção local e mapeie cópias externas.
Abrir resolução comentada
A solução mantém sessão, preferências, episódios, resumo e índice derivado em coleções separadas. O namespace usa empresa e usuário. corrigirPreferencia aceita somente idioma confirmado, substitui a versão anterior e atualiza o registro derivado. Os asserts comprovam correção com origem, isolamento de usuários e isolamento de usuários com o mesmo identificador em empresas distintas.
registrarEpisodio usa uma allowlist de campos, descartando texto bruto e informação desnecessária. consolidar mantém referências aos episódios, datas, estados e origem, sem transformar consulta-falhou em acesso concluído. O índice derivado do exemplo é textual e local: não foram gerados embeddings nem consultado um banco vetorial. Ele representa uma cópia que também precisa ser atualizada e removida.
recuperar aplica validade sem apagar os dados. O assert seguinte mostra a preferência expirada ainda no Map. removerExpirados realiza remoção física das coleções locais e atualiza referências. esquecerEscopo remove preferências, episódios, índice derivado, resumo e sessão apenas do namespace autorizado. Os testes comprovam que outros usuários e empresas permanecem intactos.
O relatório de esquecimento enumera cópias locais removidas e registra backups ou serviços externos como fora do exemplo, exigindo política própria. A memória em Map não persiste entre reinícios e não implementa RLS: uma integração real precisa de armazenamento, autorização e remoção coordenada documentados. O exemplo executa correção, consolidação, expiração e exclusão locais sem prometer apagamento de sistemas que não acessou.
import assert from "node:assert/strict";
const preferencias=new Map();const episodios=new Map();const resumos=new Map();
const indiceDerivado=new Map();const sessoes=new Map();
const ns=ctx=>JSON.stringify([ctx.empresa,ctx.usuario]);
const chave=(ctx,nome)=>ns(ctx)+"|"+nome;
function corrigirPreferencia(ctx,{nome,valor,origem,expiresAt}){
if(nome!=="idioma"||!['pt','en','es'].includes(valor)||origem!=="confirmacao-usuario")
throw new Error("MEMORIA_NAO_CONFIRMADA");
const id=chave(ctx,nome),anterior=preferencias.get(id);
const item={id,namespace:ns(ctx),tipo:"preferencia",nome,valor,origem,
versao:(anterior?.versao??0)+1,expiresAt};
preferencias.set(id,item);indiceDerivado.set(id,{namespace:ns(ctx),origemId:id,texto:nome+":"+valor});
return item;
}
function registrarEpisodio(ctx,entrada){
const id=chave(ctx,entrada.eventoId);
// Allowlist: não armazenar entrada.textoBruto, senha ou outros campos livres.
const evento={id,namespace:ns(ctx),tipo:"episodio",eventoId:entrada.eventoId,
atendimentoId:entrada.atendimentoId,status:entrada.status,origem:entrada.origem,
data:entrada.data,expiresAt:entrada.expiresAt};
episodios.set(id,evento);indiceDerivado.set(id,{namespace:ns(ctx),origemId:id,
texto:evento.atendimentoId+":"+evento.status});return evento;
}
function consolidar(ctx){
const itens=[...episodios.values()].filter(x=>x.namespace===ns(ctx));
const resumo={namespace:ns(ctx),referencias:itens.map(x=>x.id),
fatos:itens.map(x=>({eventoId:x.eventoId,data:x.data,status:x.status,origem:x.origem}))};
resumos.set(ns(ctx),resumo);return resumo;
}
function recuperar(ctx,agora){
return [...preferencias.values(),...episodios.values()]
.filter(x=>x.namespace===ns(ctx)&&x.expiresAt>agora);
}
function removerRegistro(ctx,id){
const item=preferencias.get(id)??episodios.get(id);
if(!item) return false;
if(item.namespace!==ns(ctx)) throw new Error("SEM_PERMISSAO");
preferencias.delete(id);episodios.delete(id);indiceDerivado.delete(id);
// Reconstruir resumo a partir dos episódios restantes remove referências obsoletas.
consolidar(ctx);return true;
}
function removerExpirados(ctx,agora){
const ids=[...preferencias.values(),...episodios.values()]
.filter(x=>x.namespace===ns(ctx)&&x.expiresAt<=agora).map(x=>x.id);
ids.forEach(id=>removerRegistro(ctx,id));return ids.length;
}
function esquecerEscopo(ctx){
const ids=[...preferencias.values(),...episodios.values()]
.filter(x=>x.namespace===ns(ctx)).map(x=>x.id);
ids.forEach(id=>removerRegistro(ctx,id));resumos.delete(ns(ctx));sessoes.delete(ns(ctx));
return {removidos:ids.length,locais:["preferencias","episodios","indiceDerivado","resumo","sessao"],
externos:[{sistema:"backups-ou-servicos-externos",status:"fora-do-exemplo; requer política própria"}]};
}
const a={empresa:"A",usuario:"u1"},b={empresa:"B",usuario:"u1"},c={empresa:"A",usuario:"u2"};
sessoes.set(ns(a),{objetivo:"consultar acesso",pendencias:["consultar matrícula"]});
const p1=corrigirPreferencia(a,{nome:"idioma",valor:"pt",origem:"confirmacao-usuario",expiresAt:2000});
corrigirPreferencia(b,{nome:"idioma",valor:"en",origem:"confirmacao-usuario",expiresAt:4000});
corrigirPreferencia(c,{nome:"idioma",valor:"es",origem:"confirmacao-usuario",expiresAt:4000});
assert.equal(recuperar(a,1000).length,1);assert.equal(recuperar(b,1000)[0].valor,"en");
const p2=corrigirPreferencia(a,{nome:"idioma",valor:"en",origem:"confirmacao-usuario",expiresAt:2000});
assert.equal(p2.versao,2);assert.equal(preferencias.size,3);
assert.equal(recuperar(a,1000)[0].origem,"confirmacao-usuario");
assert.throws(()=>corrigirPreferencia(a,{nome:"idioma",valor:"pt",origem:"inferida",expiresAt:2000}),
/MEMORIA_NAO_CONFIRMADA/);
const e=registrarEpisodio(a,{eventoId:"ev1",atendimentoId:"at1",status:"consulta-falhou",
origem:"ferramenta-autorizada",data:10,expiresAt:3000,textoBruto:"senha fictícia desnecessária"});
const resumo=consolidar(a);assert.deepEqual(resumo.referencias,[e.id]);
assert.equal(resumo.fatos[0].status,"consulta-falhou");
assert.equal(JSON.stringify([...episodios.values()]).includes("senha"),false);
assert.equal(recuperar(a,2500).some(x=>x.tipo==="preferencia"),false);
assert.ok(preferencias.has(p1.id)); // Expiração lógica não remove fisicamente.
assert.equal(removerExpirados(a,2500),1);
assert.equal(preferencias.has(p1.id),false);assert.equal(indiceDerivado.has(p1.id),false);
assert.throws(()=>removerRegistro(b,e.id),/SEM_PERMISSAO/);
const relatorio=esquecerEscopo(a);
assert.equal(recuperar(a,1000).length,0);assert.equal(resumos.has(ns(a)),false);
assert.equal(sessoes.has(ns(a)),false);
assert.equal([...indiceDerivado.values()].some(x=>x.namespace===ns(a)),false);
assert.equal(recuperar(b,1000).length,1);assert.equal(recuperar(c,1000).length,1);
console.log({status:"aprovado",relatorio,memoriasRestantes:preferencias.size});Como conferir seu resultado
- Usuários e empresas permanecem isolados.
- Preferência pode ser corrigida com origem.
- Expiração e remoção física são distintas.
Aplique em um problema novo
Primeiro resolva sem consultar a resposta. Explique suas decisões e guarde a evidência. A conclusão de leitura é independente desta autoavaliação.
Confira seus pré-requisitos
- Distinguir preferência/episódio/sessão.
- Aplicar TTL/namespace/origem.
A/u1 tem idioma pt v1, corrigido es v2 com origem confirmada, TTL=50; episódio de consulta falha e resumo. B/u1 tem en TTL=100. Em 60 expire preferências e esqueça A. Resolva cópias e isolamento.
Conferir raciocínio e critérios de domínio
A conserva es v2 enquanto válido; em60 a preferência sai da recuperação. O episódio falho continua falho no resumo, nunca vira acesso concluído.
A exclusão física retira preferência e registro derivado; esquecer A remove também episódio, resumo e sessão locais, inclusive referências obsoletas.
B/u1 continua com en, pois tenant faz parte do namespace. Backups e serviços externos não verificados permanecem fora da garantia do exemplo.
Evidências para autoavaliação ou revisão por pares
- Correção e expiração: A conserva es v2 enquanto válido; em60 a preferência sai da recuperação. O episódio falho continua falho no resumo, nunca vira acesso concluído.
- Remoção dos derivados: A exclusão física retira preferência e registro derivado; esquecer A remove também episódio, resumo e sessão locais, inclusive referências obsoletas.
- Isolamento e alcance: B/u1 continua com en, pois tenant faz parte do namespace. Backups e serviços externos não verificados permanecem fora da garantia do exemplo.
Um erro frequente
Memória confirma fatos atuais da conta.
Fatos atuais da conta vêm da fonte autorizada, não da lembrança.
Teste sua compreensão
Responda com suas palavras antes de abrir o comentário. Saber explicar uma decisão é parte do domínio.
1. Histórico inteiro deve virar memória durável?
2. TTL apaga automaticamente cópias em todos os sistemas?
3. Memória vetorial substitui autorização?
Não.
Filtros e permissões controlam acesso independentemente da proximidade.
Seu progresso fica salvo neste navegador. Concluir a leitura não substitui demonstrar o domínio nos exercícios.
Referências e aprofundamento
Documentação oficial e trabalhos originais. As referências registram o escopo e as limitações para você conferir o que sustentam.
- LangChain Memory overview
LangChain • consulta: 2026-10-06
FundamentosMemória curta e longa, semântica e episódica, perfis/coleções, atualizações e recuperação.
Limites: Taxonomia funcional, não equivalência com cognição humana; consolidar apenas fatos com proveniência e política definida.
- LangGraph Persistence
LangChain • consulta: 2026-10-06
LangGraphAgentesEstado, checkpoints, retomada e execução durável.
Limites: Reexecutar nós pode repetir efeitos; combinar persistência com idempotência e versões do estado.
- LangGraph Memory
LangChain • consulta: 2026-10-06
LangGraphAgentesPersistência de memória por thread/namespace, trimming, delete e summarization.
Limites: Memória deve ter identidade/tenant; apagamento efetivo precisa incluir índices, backups e traces conforme política da aplicação.
- pgvector README
pgvector contributors • consulta: 2026-10-06
PostgreSQLPostgreSQL com vetores, distâncias cosine/L2, índices HNSW/IVFFlat, filtragem e busca híbrida.
Limites: README atual mostra versão 0.8.7; performance, recall e ordem de filtros exigem benchmark no dataset.
- PostgreSQL Row Security Policies
PostgreSQL Global Development Group • consulta: 2026-10-06
PostgreSQLSegurançaProgramaçãoPolíticas por linha para isolamento de acesso à memória relacional.
Limites: Superusers e donos da tabela podem contornar RLS; testar roles, FORCE ROW LEVEL SECURITY e acesso real da aplicação.
- Effective context engineering for AI agents
Anthropic • consulta: 2026-10-06
AgentesIA & MLSeleção de contexto, orçamento de attention, context rot, recuperação just-in-time, compactação, notas e handoffs.
Limites: Context rot descreve efeito empírico, sem limite universal; compactação pode perder detalhes necessários.
- OpenAI Retrieval
OpenAI • consulta: 2026-10-06
OpenAIIngestion, chunking/overlap, metadata/filtros, ranking e reescrita de consultas em vector stores.
Limites: Implementação gerenciada OpenAI; defaults não são melhores escolhas universais para pgvector.
- Redis EXPIRE
Redis • consulta: 2026-10-06
RedisTTL, expiração de chaves e renovação de prazo.
Limites: TTL em Redis não apaga automaticamente cópias em vector store, banco, backups ou logs.
- Safety in building agents
OpenAI • consulta: 2026-10-06
OpenAIAgentesPrompt injection, vazamento de dados, entradas não confiáveis e aprovação de tools.
Limites: Prompt de segurança não substitui permissões da aplicação; guia pode mostrar ferramentas legadas, aplicar os princípios em stack atual.