A diferença entre um chatbot e um sistema de IA inteligente está na memória. Como estruturar contexto, construir RAG, escolher vector databases, e fazer agentes que lembram — com código real e decisões de arquitetura.
Um LLM sozinho não tem memória — ele processa o que está na janela de contexto e esquece tudo entre chamadas. Toda "memória" de um sistema de IA é uma construção de engenharia em torno do modelo. Existem quatro tipos fundamentais, cada um com trade-offs distintos.
Clientes dizem "o sistema lembrou de mim!" — o que realmente aconteceu é que o histórico da conversa foi armazenado num banco e reinjetado no contexto da chamada seguinte. LLMs não têm estado entre chamadas. Jamais. É tudo engenharia de contexto.
| Tipo | Quando usar | Custo | Latência | Exemplo prático |
|---|---|---|---|---|
| In-Context | Contexto imediato, curto histórico, documentos chave | Alto (tokens cobrados) | Nenhuma | System prompt com regras de negócio do cliente |
| External (Vector) | Base de conhecimento grande, documentos técnicos, FAQs | Baixo (só recuperado precisa ser pago) | ~50–200ms | Manual de COBOL de 800 páginas acessível por query |
| Episodic | Agentes de longa duração, suporte ao cliente recorrente | Médio (storage + sumarização) | ~100ms (lookup) | Agente que lembra dos tickets anteriores do usuário |
| Semantic | Personalização, preferências do usuário, contexto de domínio | Mínimo (poucos tokens de preferências) | Nenhuma (no system prompt) | "Kyol prefere exemplos com COBOL, usa z/OS 2.5" |
Contexto não é ilimitado — mesmo com 200K tokens, cada token tem custo e impacto na qualidade da atenção. Preencher a janela com texto irrelevante degrada a resposta. Gerenciar contexto é uma disciplina de engenharia.
Alta atenção do modelo. Ideal para: instruções críticas, identidade do agente, regras de negócio invioláveis, contexto do usuário.
Atenção degradada. Pesquisa (Liu et al.) mostra que informações no meio de contextos longos são sistematicamente menos utilizadas. Evite colocar informações críticas aqui.
Alta atenção do modelo. Ideal para: a pergunta/tarefa atual do usuário, instruções de formato de resposta, dados mais recentes.
Em ordem decrescente de importância no contexto: (1) tarefa atual → (2) regras do sistema → (3) memória semântica do usuário → (4) documentos RAG relevantes → (5) histórico recente → (6) histórico antigo sumarizado. Construa seu pipeline nessa ordem.
Claude Code usa um sistema de arquivos hierárquico para memória persistente de projetos. Entender essa estrutura é fundamental para construir agentes de coding que se comportam de forma consistente ao longo de sessões longas.
Arquivo de instruções permanentes do projeto — lido pelo Claude Code no início de cada sessão. Equivalente ao system prompt do projeto. Versionado com o código.
Diretório oculto com configurações locais. Contém: settings.json, memory files, histórico de sessão, preferências de ferramentas. Pode ser gitignored.
Arquivos .md gerados automaticamente pelo Claude durante sessões longas — insights sobre o código, decisões tomadas, padrões identificados. Base da memória episódica.
# CLAUDE.md — Sistema de Folha de Pagamento (FP-MAIN) ## Contexto do Projeto - Sistema legado em COBOL rodando em IBM z/OS 2.5 - DB2 v13 como banco de dados primário (esquema: FPROD.V_FUNCIONARIOS) - APIs REST em Python 3.11 + FastAPI fazendo ponte com o mainframe - Pipeline de integração via IBM MQ 9.3 ## Regras de Negócio Críticas - NUNCA modificar os copybooks sem aprovação do arquiteto COBOL - Campos de salário usam COMP-3 (packed decimal) — sempre validar antes de converter - Cálculo de INSS: tabela mensal em TABINSS-TABLE no programa FPINSS01 - Qualquer alteração em FPFOLHA00.cbl requer testes de regressão completos ## Stack e Convenções - COBOL: estilo IBM Enterprise COBOL 6.3, 80 colunas - Python: Black formatter, type hints obrigatórios, docstrings no padrão Google - Commits: Conventional Commits (feat/fix/refactor/docs) - Testes: pytest, cobertura mínima 85% ## Arquivos-chave - src/cobol/FPFOLHA00.cbl → programa principal de folha - src/cobol/copybooks/ → definições de dados compartilhadas - src/api/folha_router.py → endpoints REST de folha - docs/decisoes/ → ADRs (Architecture Decision Records) ## Contexto da Consultora - Kyol está refatorando a interface Python-COBOL - Preferência: exemplos com código real, sem simplificações - Objetivo atual: migrar lógica de cálculo de férias para microsserviço ## O que NÃO fazer - Não sugerir reescrita completa em Java/.NET sem discussão prévia - Não usar bibliotecas não aprovadas pelo comitê de arquitetura - Não alterar PROCEDURE DIVISION sem comentar o que mudou e por quê
Preferências globais do usuário. Lido em todas as sessões de qualquer projeto. Ex: "sempre responder em português", "usar Black para Python".
Instruções do projeto. Commitado no repositório. Lido ao entrar no diretório raiz. Regras de negócio, stack, arquivos-chave.
Instruções de subdiretório. Sobrescrevem/complementam a raiz. Ex: CLAUDE.md dentro de /cobol/ com convenções específicas de COBOL.
Coloque no CLAUDE.md da raiz: versão exata do compilador COBOL, dialectos usados (IBM vs MicroFocus), explicação dos níveis de dados customizados do seu sistema, e regras de negócio que não estão documentadas no código. Claude Code usa isso para gerar código correto no seu dialeto, não COBOL genérico de livro.
RAG (Retrieval-Augmented Generation) é a técnica que permite a um LLM responder com base em uma base de conhecimento externa — sem fine-tuning, sem reinserção manual. É o coração de qualquer assistente corporativo com acesso a documentos.
Converte query e documentos para vetores de embeddings e busca por similaridade semântica (cosine similarity). Encontra documentos semanticamente relacionados mesmo sem palavras em comum. Ideal para linguagem natural.
# Query: "Como calcular férias proporcionais?" # Encontra: documentos sobre "recesso", "dias de descanso", "art. 130 CLT" results = vector_db.similarity_search( query="férias proporcionais", k=5, score_threshold=0.75 )
Busca por frequência de palavras-chave, clássico da recuperação de informação. Muito eficaz para termos técnicos, siglas, IDs (ex: "FPFOLHA00", "DCLGEN", "SQLCODE -803"). Complementa o dense retrieval.
# BM25 — eficaz para termos exatos # Query: "SQLCODE -811" → encontra exatamente bm25 = BM25Okapi(tokenized_corpus) scores = bm25.get_scores( tokenized_query="SQLCODE -811".split() )
Combina dense + sparse via RRF (Reciprocal Rank Fusion). Melhor dos dois mundos: semântica para linguagem natural + precisão para termos técnicos. Padrão das implementações de produção em 2026.
# Reciprocal Rank Fusion — combina resultados def rrf(dense_results, sparse_results, k=60): scores = {} for rank, doc in enumerate(dense_results): scores[doc.id] = scores.get(doc.id, 0) + 1/(k + rank + 1) for rank, doc in enumerate(sparse_results): scores[doc.id] = scores.get(doc.id, 0) + 1/(k + rank + 1) return sorted(scores, key=lambda x: scores[x], reverse=True)
Após o retrieval inicial (top-20), um modelo de reranking (cross-encoder) re-avalia cada documento contra a query com mais precisão. Custo adicional de latência (~100ms), mas melhora significativa na qualidade dos top-3 chunks injetados.
# Reranker — Cohere, Jina, ou BGE-reranker reranker = CohereRerank(model="rerank-v3.5") reranked = reranker.rerank( query=query, documents=initial_results, top_n=5 )
A forma como você divide documentos em chunks é a decisão de arquitetura mais impactante em RAG. Chunk muito pequeno: perde contexto. Muito grande: injeta ruído. A estratégia certa depende do tipo de documento e do padrão de queries.
| Estratégia | Como funciona | Melhor para | Tamanho típico | Overlap |
|---|---|---|---|---|
| Fixed-size | Divide por número fixo de tokens, com overlap | Docs genéricos, prototipagem rápida | 256–512 tokens | 10–20% |
| Sentence-based | Divide em sentenças completas, agrupa até atingir tamanho | Textos narrativos, FAQs, artigos | 3–8 sentenças | 1 sentença |
| Semantic Best | Detecta quebras de tópico por similaridade de embeddings | Documentos técnicos longos, manuais | Variável | Lógico |
| Recursive | Tenta dividir por hierarquia: parágrafo → sentença → palavra | Uso geral — padrão LangChain/LlamaIndex | 512–1024 tokens | 50–100 tokens |
| Document-structure | Respeita headers, seções, tabelas do documento original | PDFs com estrutura, Markdown, DOCX | Por seção | Contexto de header |
| Code-aware COBOL | Divide por SECTION, PARAGRAPH, DIVISION do programa | Source code, scripts, COBOL, SQL | Por bloco lógico | Comentário de contexto |
Dividir programas COBOL por SECTION (IDENTIFICATION, DATA, ENVIRONMENT, PROCEDURE) e por PARAGRAPH nomeado dentro do PROCEDURE DIVISION é a abordagem mais eficaz. Adicione sempre o nome do PROGRAM-ID e da SECTION como metadado de cada chunk — o reranker usa isso para priorizar chunks do programa correto.
Um chunk de 1024 tokens sobre "folha de pagamento" é recuperado, mas 80% do conteúdo é irrelevante para a query específica sobre INSS. O modelo precisa filtrar mentalmente muito ruído.
Child chunk pequeno (128 tokens) é usado para o retrieval preciso. Parent chunk (512 tokens) é o que realmente é injetado no contexto — com contexto suficiente ao redor. Melhor precisão + melhor contexto.
Embeddings transformam texto em vetores numéricos onde proximidade = similaridade semântica. "férias proporcionais" e "art. 130 CLT" ficam próximos no espaço vetorial. Escolher o modelo de embedding certo impacta toda a qualidade do RAG.
| Modelo | Dimensões | MTEB Score | Max tokens | Custo | Ideal para |
|---|---|---|---|---|---|
| text-embedding-3-large (OpenAI) | 3072 | 64,6 | 8K | $0,13/MTok | Uso geral, qualidade máxima |
| voyage-3-large (Voyage AI) | 1024 | 68,1 | 32K | $0,18/MTok | Código + texto técnico (recomendado Anthropic) |
| text-embedding-3-small (OpenAI) | 1536 | 62,3 | 8K | $0,02/MTok | Volume alto, custo baixo |
| bge-m3 (FlagAI, open) | 1024 | 63,5 | 8K | Free (self-host) | Multilíngue, on-premise corporativo |
| e5-mistral-7b (Microsoft, open) | 4096 | 66,6 | 32K | Free (GPU) | Alta qualidade open-source |
Todos os documentos e todas as queries precisam usar o mesmo modelo de embedding. Vetores de modelos diferentes não são comparáveis — é como comparar coordenadas GPS com coordenadas geográficas. Se trocar de modelo, re-indexe toda a base.
Algoritmo exato: calcula distância cosine entre a query e todos os vetores do banco. Precisão perfeita, mas O(n) — inviável acima de ~1 milhão de documentos. Usado em bases pequenas ou em fase de testes.
Algoritmo de busca aproximada (ANN) usado em todos os vector DBs de produção. Constrói um grafo hierárquico de vizinhança. Complexidade O(log n) — escala para bilhões de vetores. Trade-off: 95–99% de recall vs 100% do k-NN exato.
Um vector database armazena embeddings e permite buscas de similaridade eficientes em escala. Escolher o certo depende de: escala esperada, necessidade de metadados, model de deploy (cloud vs. on-premise), e integração com stack existente.
pgvector + PostgreSQL é a escolha mais segura para empresas com restrições de data residency e stack legado. Mantém dados no ambiente já aprovado pelo jurídico/compliance, permite JOINs com tabelas existentes (ex: associar chunks à tabela de documentos do ERP), e não exige novo serviço de infra. Para escala >50M vetores, migrar para Qdrant ou Weaviate self-hosted.
-- Habilitar extensão (uma vez por banco) CREATE EXTENSION IF NOT EXISTS vector; -- Tabela de chunks com metadados do sistema COBOL CREATE TABLE documentos_cobol ( id SERIAL PRIMARY KEY, conteudo TEXT NOT NULL, embedding vector(1536), -- dimensão do modelo programa VARCHAR(8), -- ex: FPFOLHA00 secao VARCHAR(40), -- ex: PROCEDURE DIVISION paragraph VARCHAR(40), updated_at TIMESTAMP DEFAULT NOW() ); -- Índice HNSW para busca rápida CREATE INDEX ON documentos_cobol USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64); -- Query: encontrar chunks similares à pergunta do usuário SELECT conteudo, programa, secao, 1 - (embedding <=> '[0.12, 0.87, ...]'::vector) AS similaridade FROM documentos_cobol WHERE programa = 'FPFOLHA00' -- filtro por metadado ORDER BY embedding <=> '[0.12, 0.87, ...]'::vector LIMIT 5;
Um agente corporativo de longa duração precisa combinar todos os tipos de memória. Veja a arquitetura completa de um assistente com memória real — da query do usuário à resposta final, com todas as camadas de contexto.
from dataclasses import dataclass from typing import List, Optional import anthropic @dataclass class ContextParts: system_prompt: str semantic_memory: str rag_chunks: List[str] episode_summary: str recent_history: List[dict] class ContextBuilder: def __init__(self, max_tokens: int = 150_000): self.max_tokens = max_tokens self.token_budget = { "system": 5_000, # system prompt base "semantic": 3_000, # memória semântica do usuário "rag": 20_000, # chunks recuperados "episode": 5_000, # sumário de sessões passadas "history": 15_000, # histórico recente da conversa } def build(self, query: str, parts: ContextParts) -> dict: # 1. System prompt (início — alta atenção do modelo) system = self._build_system(parts) # 2. Histórico de mensagens com contexto injetado messages = [] # Injetar memória semântica como primeira mensagem humana if parts.semantic_memory: messages.append({ "role": "user", "content": f"[CONTEXTO DO USUÁRIO]\n{parts.semantic_memory}" }) messages.append({"role": "assistant", "content": "Entendido."}) # Sumário episódico se houver if parts.episode_summary: messages.append({ "role": "user", "content": f"[HISTÓRICO ANTERIOR]\n{parts.episode_summary}" }) messages.append({"role": "assistant", "content": "Ok, contexto registrado."}) # Histórico recente da conversa atual messages.extend(parts.recent_history) # Query com chunks RAG (no FIM — alta atenção) rag_context = "\n\n".join([ f"[DOCUMENTO {i+1}]\n{chunk}" for i, chunk in enumerate(parts.rag_chunks) ]) messages.append({ "role": "user", "content": f"{rag_context}\n\n[PERGUNTA]\n{query}" }) return {"system": system, "messages": messages} def _build_system(self, parts: ContextParts) -> str: return f"""Você é um assistente corporativo especializado. {parts.system_prompt} Responda sempre com base nos documentos fornecidos. Se não encontrar a informação, diga claramente que não sabe."""
Existe apenas durante a conversa ativa. Armazenada em memória da aplicação (Redis com TTL curto). Barata, rápida. Suficiente para chatbots de atendimento onde cada sessão é independente.
Use quando: cada conversa é autocontida, sem necessidade de continuidade.
Armazenada em banco permanente. Inclui histórico de sessões anteriores, preferências extraídas, contexto de longo prazo. Custo de storage + lógica de retrieval de qual memória é relevante agora.
Use quando: o agente precisa lembrar quem é o usuário, o que já foi discutido, o que o usuário prefere.
A Files API permite fazer upload de arquivos para a Anthropic e reutilizá-los em múltiplas chamadas sem re-enviar o conteúdo. Útil para documentos de referência permanentes que precisam estar disponíveis em toda chamada da API.
import anthropic client = anthropic.Anthropic() # 1. Upload do manual COBOL (uma vez) with open("manual_cobol_folha.pdf", "rb") as f: file_response = client.beta.files.upload( file=( "manual_cobol_folha.pdf", f, "application/pdf" ) ) file_id = file_response.id # file_id: "file_abc123..." — salvar no banco para reutilizar print(f"Upload: {file_id}") # 2. Usar o arquivo em qualquer chamada subsequente response = client.beta.messages.create( model="claude-sonnet-4-6", max_tokens=2048, messages=[{ "role": "user", "content": [ { "type": "document", "source": { "type": "file", "file_id": file_id # referência, não re-envio } }, { "type": "text", "text": "Como o programa FPINSS01 calcula a alíquota de INSS para salários acima do teto?" } ] }], betas=["files-api-2025-04-14"] ) # 3. Listar arquivos disponíveis files = client.beta.files.list() for f in files.data: print(f"{f.id} — {f.filename} — {f.size} bytes") # 4. Deletar quando não precisar mais client.beta.files.delete(file_id)
Use Files API para documentos pequenos-médios (<500 páginas) que precisam ser consultados integralmente frequentemente — o modelo vê o documento completo. Use RAG para bases grandes (>500 páginas, múltiplos documentos) onde recuperação seletiva é necessária. Para o melhor dos dois mundos: RAG para retrieval inicial, depois Files API para injetar o documento completo do chunk mais relevante.
Dois cenários completos mostrando como os conceitos se conectam em sistemas reais.
Time de desenvolvimento com 12 programadores precisa consultar documentação de 340 programas COBOL (8.000+ páginas) para manutenção. Hoje: busca manual em PDF demorada, conhecimento concentrado em 2 analistas sênior.
RAG sobre base de documentação. Chunking por SECTION/PARAGRAPH. Metadados: programa, DIVISION, data. Hybrid search (BM25 para nomes de programas + vector para semântica). Reranking por relevância.
Query: "Como o FPFOLHA00 trata erro de DB2 -811?" → resposta em <3s com o parágrafo ERR-DB2-HANDLER e código de exemplo. Memória semântica: "prefer COBOL examples with IBM Enterprise 6.3 syntax."
~2.800 chunks indexados. Latência média: 1,8s. Precisão (avaliada por analistas): 89%. Custo por query: ~$0,03 (Sonnet 4.6 + reranker). ROI: 2h de pesquisa manual → 30 segundos.
Cada sessão de suporte é salva. A cada 5 sessões, Haiku 4.5 sumariza: "Usuário frequentemente enfrenta erros de SQLCODE -904 no horário de batch. Ambiente: z/OS 2.5, DB2 v13, job BATFOL01."
Após 10 sessões, sistema extrai preferências: "Prefere diagnóstico antes de solução", "Usa mainframe z/OS, não Linux", "Já conhece COBOL — explicações sem básico". Injetadas no system prompt de todo chamado.
Após cada conversa: (1) salvar histórico em Postgres, (2) verificar se sumarização necessária, (3) extrair novos fatos semânticos via Haiku, (4) atualizar perfil. Tudo assíncrono — não bloqueia a resposta.
Memória semântica: ~300 tokens por usuário (quase gratuita). Sumário episódico: ~500 tokens (5 sessões sumarizadas). Custo de sumarização (Haiku 4.5): $0,002 por sessão processada. Total: <$0,01 por usuário/mês.
Todos os termos técnicos introduzidos neste módulo. Atenção especial aos termos de arquitetura — eles aparecem em todas as conversas sobre sistemas RAG com clientes.