RAG: por que "só jogar tudo no LLM" não funciona
- ⬜⚙️ Transformers e Mecanismo de Atenção(Fundamentos da IA)
- ⬜🔧 Tool Calling e Agentes(IA Além do LLM)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
"Mas por que não jogo o documento todo no contexto do LLM?" é a primeira pergunta de quem começa a trabalhar com IA em produção. A resposta envolve três limites duros — cutoff de treino, janela de contexto, alucinação — que juntos formam a parede onde RAG (Retrieval-Augmented Generation) se encaixa como solução. Este é o mapa do território.
Os três limites que criam a necessidade de RAG
| Limite | O que é | Por que quebra na prática |
|---|---|---|
| Cutoff de treino | Modelo só sabe o que existia até a data em que o dataset foi congelado | Pergunta sobre evento de ontem? Ele inventa. Dados internos do seu sistema? Nunca viu. |
| Janela de contexto | Limite físico de tokens por request (200k, 1M, 2M — depende do modelo) | Sua base tem 10GB. Mesmo modelo de 2M tokens não encaixa. E custo cresce linear no input. |
| Alucinação | LLM gera texto plausível, não verdadeiro. Sem âncora factual, inventa. | Respostas confiantes e erradas. Em suporte, compliance ou medicina, isso é inaceitável. |
A arquitetura em dois estágios
RAG separa duas responsabilidades. Primeiro, recupera os trechos relevantes à pergunta a partir de uma base indexada. Depois, gera a resposta usando esses trechos como contexto. O modelo vira um raciocinador sobre evidência fornecida, não uma enciclopédia.
┌──────────────────────┐
│ Pergunta do usuário │
└─────────┬────────────┘
│
▼
┌──────────────────────┐
│ 1. Retrieve │
│ embed → vector DB │
│ top-k trechos │
└─────────┬────────────┘
│
▼
┌──────────────────────┐
│ 2. Augment Prompt │
│ [pergunta + trechos]│
└─────────┬────────────┘
│
▼
┌──────────────────────┐
│ 3. Generate (LLM) │
│ resposta + citações │
└──────────────────────┘
Pipeline de indexação (offline)
Antes que qualquer pergunta seja feita, a base precisa ser preparada. Isso roda em batch — hora em hora, diário, ou via event-driven quando documentos mudam.
Documento → Parser → Chunker → Embedding → Vector DB
(.pdf, (texto (pedaços (modelo (pgvector,
.md, html) limpo) com overlap) de embedding) Pinecone,
Qdrant,
Weaviate)
RAG vs Fine-tuning: quando usar cada um
📋 Time quer atualizar respostas com base em documentos que mudam toda semana
Atualizar RAG = re-indexar. Barato, rápido, sem downtime. Fine-tuning para base que muda semanalmente é retraining contínuo — caro e frágil.
Alt: Fine-tuning — desatualiza junto com o modelo; custo por release
Alt: Longo contexto direto — só funciona se a base cabe em contexto e custo por query compensa
📋 Produto precisa de tom específico ("responda como um médico sênior, formal e cauteloso")
Tom e formato são skill, não fato. Fine-tuning com exemplos de estilo grava o comportamento no modelo. RAG para tom é prompt-engineering frágil.
Alt: System prompt detalhado — funciona para estilo simples; degrada com complexidade
Alt: RAG — errada — tom não é conteúdo recuperável
📋 Assistente de suporte com base de conhecimento interna + tom de marca
LoRA captura tom da marca e formato das respostas (skill). RAG fornece conteúdo atualizado da base (fato). Separação clara de responsabilidades.
Por que naive RAG (top-k + embedding) falha em produção
| Problema | Sintoma | Mitigação |
|---|---|---|
| Chunks do tamanho errado | Resposta falta contexto (chunk pequeno) ou dilui o sinal (chunk grande) | Recursive chunking + contextual retrieval (Anthropic) |
| Embedding ignora intenção | "Cancelar conta" e "Criar conta" têm similaridade alta | Hybrid search (BM25 + vector) com RRF |
| Top-k fixo | Documento denso devolve 5 chunks quase idênticos | MMR (maximal marginal relevance) para diversidade |
| Sem reranking | Posição 1-5 tem ruído misturado com relevante | Cross-encoder rerank (Cohere, Voyage, Jina) |
| Query ambígua | "Como isso funciona?" sem contexto volta tudo genérico | HyDE, query expansion, multi-query |
Código mínimo: naive RAG em Python
Exemplo pedagógico — serve para ver o fluxo, não para produção.
# Pipeline mínimo: docs → embeddings → query → LLM
from anthropic import Anthropic
import numpy as np
from sentence_transformers import SentenceTransformer
client = Anthropic()
embedder = SentenceTransformer("BAAI/bge-m3")
# 1. Indexação (offline)
docs = [
"Para cancelar conta, acesse Configurações → Conta → Encerrar.",
"Para criar conta nova, vá em cadastrar.com/novo e preencha email.",
"Senha esquecida? Use o link 'recuperar' na tela de login.",
]
doc_vecs = embedder.encode(docs, normalize_embeddings=True)
# 2. Retrieval (online)
def retrieve(query: str, k: int = 2) -> list[str]:
q_vec = embedder.encode(query, normalize_embeddings=True)
scores = doc_vecs @ q_vec # cosine (vetores já normalizados)
top_idx = np.argsort(-scores)[:k]
return [docs[i] for i in top_idx]
# 3. Generate
def answer(query: str) -> str:
context = "\n\n".join(retrieve(query))
msg = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=512,
messages=[{
"role": "user",
"content": f"Responda a partir do contexto. Se não estiver no contexto, diga que não sabe.\n\nContexto:\n{context}\n\nPergunta: {query}"
}],
)
return msg.content[0].text
print(answer("Esqueci minha senha, o que faço?"))Perguntas típicas
❓ RAG funciona com modelo local (Llama, Mistral)?
❓ Janela de contexto grande (1M+ tokens) mata RAG?
❓ Preciso de vector DB dedicado (Pinecone, Weaviate, Qdrant) ou pgvector serve?
pgvector no Postgres que você já tem é quase sempre o certo. Acima disso, ou se precisar de filtragem/metadata muito complexa, vector DB dedicada ganha. Não comece com Pinecone "só porque" — custo e vendor lock-in sem justificativa.❓ E se a pergunta exige sintetizar 30 documentos? Top-k=5 não basta.
Quiz rápido
4 perguntas · Acerte tudo e ganhe o badge 🎯 Gabarito