- RAG = Busca vetorial + LLM: o modelo responde com base nos seus documentos, não no treinamento geral
- Três problemas que RAG resolve e LLM puro não: dados proprietários, atualização contínua e citação de fontes
- Stack mínima viável: LlamaIndex + OpenAI Embeddings (text-embedding-3-small) + Pinecone + GPT-4o
- Semana 1: ingestão, chunking e indexação; Semana 2: API de query + interface + monitoramento
- Custo mensal para 500 docs + 5.000 queries: R$ 80-200. Para 5.000 docs + 50.000 queries: R$ 500-1.500
- Avalie qualidade com 3 métricas: Faithfulness, Relevance e Context Precision — framework RAGAS automatiza
O que é RAG e por que toda empresa com dados internos precisa considerar
RAG (Retrieval-Augmented Generation) é a técnica de conectar um LLM a uma base de documentos externa para que as respostas sejam baseadas no conteúdo real da empresa — não no conhecimento de treinamento do modelo.
O problema que RAG resolve é simples de entender: LLMs como GPT-4o ou Claude sabem muito sobre o mundo geral, mas nada sobre sua empresa. Se você perguntar "qual a política de reembolso da NuPtechs?", o modelo vai inventar uma resposta plausível — com linguagem confiante, formatação impecável, e informação completamente fabricada. Isso é alucinação, e é o maior risco de usar LLMs em ambiente corporativo sem RAG.
Com RAG, o fluxo muda fundamentalmente:
- Indexação (offline): Seus documentos (PDFs, manuais, contratos, wiki, emails) são divididos em blocos (chunks), transformados em vetores numéricos via modelo de embedding, e armazenados em um banco vetorial (Pinecone, pgvector, Weaviate).
- Retrieval (em tempo real): A pergunta do usuário também vira um vetor. O banco vetorial retorna os K documentos/chunks mais similares semanticamente.
- Generation (em tempo real): O LLM recebe a pergunta + os documentos relevantes no contexto e gera uma resposta fundamentada, citando as fontes.
RAG vs. Fine-tuning vs. Contexto direto
| Abordagem | Para que serve | Custo | Atualização |
|---|---|---|---|
| RAG | Respostas sobre dados que mudam frequentemente | Baixo (embedding + query) | Instantânea (re-indexe o doc) |
| Fine-tuning | Mudar o estilo/comportamento do modelo | Alto ($500-5.000/treino) | Lenta (retreino completo) |
| Contexto direto | Poucos docs (<20 páginas) | Mínimo | Instantânea |
Regra prática: Se tem menos de 20 páginas de conteúdo, cole tudo no contexto do prompt (sem RAG). Se tem 20-100.000 páginas, use RAG. Se quer mudar como o modelo escreve ou raciocina (não o que sabe), fine-tuning.
Fine-tuning muda o comportamento do modelo (como ele responde). RAG muda o conteúdo que ele conhece. Para dados empresariais em mudança contínua, RAG é 10× mais prático e 100× mais barato do que fine-tuning.
Quando RAG é a solução certa (e quando não é)
RAG é ideal quando:
- Dados proprietários: Manuais técnicos, contratos, políticas internas, base de conhecimento de suporte, documentação de produtos, regulamentações setoriais específicas.
- Atualização frequente: Adicionar ou atualizar documentos é instantâneo (re-indexe o doc específico). Re-treinar um modelo leva semanas e custa milhares de dólares.
- Transparência exigida: O usuário precisa ver de onde veio a informação. RAG cita as fontes (nome do arquivo, página, seção). LLM puro não consegue.
- Compliance e auditoria: Regulações exigem rastreabilidade das respostas — "por que o sistema disse isso?". Com RAG, a resposta é: "porque está na página 47 do contrato X".
- Volume médio-alto de docs: De 20 a 100.000 documentos. Acima disso, técnicas adicionais (hierarquias, roteamento) são necessárias.
RAG NÃO é a solução certa quando:
- Volume muito baixo: Menos de 20 páginas de conteúdo — cole tudo no contexto do prompt. Mais simples, mais barato, melhor resultado.
- Dados não-textuais sem OCR: Imagens, vídeos, plantas técnicas. RAG trabalha com texto. Para imagens, precisa OCR/descrição primeiro.
- Cálculos e raciocínio complexo: RAG recupera informação, não calcula. Para "calcule o reajuste do contrato X", integre com código de cálculo, não com RAG.
- Dados estruturados em banco SQL: Se os dados estão em tabelas SQL, uma query direta ou text-to-SQL é mais eficiente que vetorizar rows.
- Quando a resposta precisa ser exata: RAG introduz variabilidade na geração. Para respostas que precisam ser letra por letra iguais (disclaimer legal, dosagem médica), use busca exata, não RAG.
50 documentos limpos, bem formatados e atualizados produzem RAG melhor do que 5.000 com ruído, duplicatas e versões conflitantes. Curadoria é 60% do sucesso de um RAG.
Arquitetura de produção: componentes e decisões
Stack mínima viável (MVP)
| Componente | Opção recomendada | Alternativas | Custo mensal |
|---|---|---|---|
| Framework | LlamaIndex | LangChain, Haystack | Grátis (open source) |
| Embeddings | text-embedding-3-small (OpenAI) | Cohere embed-v3, Voyage AI | ~R$ 5 (até 5M tokens/mês) |
| Vector Store | Pinecone Serverless | pgvector, Weaviate, Qdrant | R$ 0-50 (até 1M vetores) |
| LLM | GPT-4o mini | Claude 3.5 Haiku, Gemini Flash | R$ 30-100 (5k queries) |
| API | FastAPI (Python) | Flask, Express.js | R$ 50 (servidor básico) |
| Interface | Streamlit (interno) ou Next.js (produção) | Gradio, Chainlit | R$ 0-50 |
Stack de produção (alta disponibilidade)
Para uso com mais de 50 usuários simultâneos e documentos críticos:
- Fila de ingestão: Redis ou SQS para processar uploads de documentos assincronamente
- Cache de queries: Redis com TTL (queries frequentes não precisam re-consultar o LLM)
- Re-ranker: Cohere Rerank ou cross-encoder local para reordenar os chunks após a busca vetorial
- Fallback de LLM: Se GPT-4o estiver fora, redirecionar para Claude ou vice-versa automaticamente
- Monitoramento: Log de cada query, chunks retornados, resposta gerada, e score de similaridade
Decisão: Pinecone vs. pgvector
Pinecone: Gerenciado, escala automaticamente, sem operação. Ideal quando não quer gerenciar infra de banco vetorial. Custo a partir de R$ 0 (free tier) até R$ 500+/mês em volume alto.
pgvector: Extensão do PostgreSQL. Se já usa PostgreSQL, adiciona busca vetorial ao mesmo banco. Ideal quando quer simplificar a stack e já tem expertise em PostgreSQL. Performance excelente para até ~5M vetores.
Recomendação: Comece com Pinecone para velocidade. Migre para pgvector quando quiser consolidar infra ou quando o custo de Pinecone superar o de gerenciar pgvector.
Avalie seu RAG semanalmente com 3 métricas: Faithfulness (resposta sustentada pelos docs?), Relevance (responde a pergunta?) e Context Precision (chunks retornados corretos?). RAGAS automatiza — não dependa de avaliação manual.
Semana 1: Ingestão, chunking e indexação de documentos
Dia 1-2: Setup do ambiente e loader de documentos
Instale LlamaIndex e configure os loaders para os formatos da sua base:
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
from llama_index.vector_stores.pinecone import PineconeVectorStore
# Suporta PDF, Word, TXT, Markdown, HTML, CSV, JSON
documents = SimpleDirectoryReader(
"./docs",
recursive=True,
filename_as_id=True, # ID do doc = nome do arquivo
required_exts=[".pdf", ".docx", ".md", ".txt"]
).load_data()
print(f"Carregados {len(documents)} documentos")Dia 3-4: Chunking — a decisão mais impactante na qualidade
Chunking é dividir documentos em blocos menores para indexação. A qualidade do RAG depende diretamente da qualidade do chunking:
- Chunks muito grandes (2000+ tokens): Diluem o significado. A busca vetorial retorna chunks parcialmente relevantes, o LLM tem que filtrar ruído.
- Chunks muito pequenos (50-100 tokens): Perdem contexto. Uma frase isolada pode ser ambígua sem as frases anteriores.
- Sweet spot: 256-512 tokens com overlap de 50-100 tokens
Estratégias de chunking por tipo de documento
| Tipo de documento | Estratégia | Chunk size |
|---|---|---|
| Manuais técnicos | Por seção/heading (chunk por H2/H3) | Variável (respeita seções) |
| Contratos jurídicos | Por cláusula (separação por numeração) | 256-512 tokens |
| Emails/tickets de suporte | Cada email/ticket = 1 chunk | Variável (por mensagem) |
| FAQs/Knowledge base | Cada pergunta+resposta = 1 chunk | Variável (por par Q&A) |
| Documentos longos (relatórios) | Token-based com overlap | 512 tokens, 100 overlap |
Dia 5: Embedding e indexação
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core.node_parser import SentenceSplitter
# Chunking
parser = SentenceSplitter(chunk_size=512, chunk_overlap=100)
nodes = parser.get_nodes_from_documents(documents)
# Embedding + Indexação
embed_model = OpenAIEmbedding(model="text-embedding-3-small")
vector_store = PineconeVectorStore(pinecone_index=pinecone_index)
index = VectorStoreIndex(
nodes,
vector_store=vector_store,
embed_model=embed_model,
show_progress=True
)
print(f"Indexados {len(nodes)} chunks")Para 500 documentos de ~10 páginas cada: indexação em ~15 minutos, custo de embeddings ~R$ 5.
Dia 5 (continuação): Metadados — o segredo da precisão
Não indexe apenas texto. Adicione metadados a cada chunk:
- Obrigatórios: nome do arquivo, data de criação/atualização, seção/capítulo
- Recomendados: autor, departamento, tipo de documento, nível de confidencialidade
- Avançados: versão do documento, tags temáticas, idioma
Metadados permitem filtros na query: "busque apenas em contratos do departamento jurídico atualizados nos últimos 6 meses".
Sem similarity cutoff (≥0.72), o sistema retorna chunks para TODA query — mesmo sem resposta na base. Resultado: alucinação com citação de fonte incorreta. Sempre defina cutoff mínimo.
Semana 2: API de query, interface e go-live
Dia 1-2: API de query com controles de qualidade
from llama_index.core.postprocessor import SimilarityPostprocessor
query_engine = index.as_query_engine(
similarity_top_k=5,
response_mode="compact",
node_postprocessors=[
SimilarityPostprocessor(similarity_cutoff=0.72)
]
)
response = query_engine.query("Qual o prazo de garantia dos contratos?")
print(response.response) # resposta gerada
print(response.source_nodes) # chunks citados com score
Parâmetros-chave:
- similarity_top_k=5: Retorna os 5 chunks mais similares. Mais chunks = mais contexto mas mais custo de tokens.
- similarity_cutoff=0.72: Ignora chunks com score abaixo de 0.72. Sem cutoff, o sistema retorna chunks irrelevantes com aparência de confiança.
- response_mode="compact": Sumariza a resposta dos chunks. Alternativa: "tree_summarize" para queries complexas sobre muitos documentos.
Dia 3: Interface para usuários
Para uso interno (5-20 usuários): Streamlit resolve em 2-4h. Chat interface com histórico, display de fontes citadas, e filtros por tipo de documento.
Para uso em produção (50+ usuários): API FastAPI com autenticação + frontend React/Next.js. Adicione: rate limiting, cache de queries frequentes, e logging de interações.
Para integração com WhatsApp: n8n com nó HTTP Request chama a API FastAPI. O bot recebe mensagem → envia query à API RAG → retorna resposta formatada para WhatsApp.
Dia 4: Monitoramento e feedback loop
Implemente desde o dia 1:
- Log de queries: Registre toda query, os chunks retornados, os scores, e a resposta gerada. Isso é ouro para melhorar o sistema.
- Queries sem resposta: Quando o score máximo dos chunks está abaixo do cutoff, registre a query como "gap na base". Essas são documentos que faltam.
- Feedback do usuário: Botões simples (👍/👎) na resposta. Feedback negativo = chunk errado ou resposta mal formulada.
- Dashboard: Queries/dia, taxa de resposta (% de queries com score acima do cutoff), queries mais frequentes, docs mais citados.
Dia 5: Testes e go-live
Antes de liberar para todos os usuários:
- Crie um conjunto de 30 perguntas de teste com respostas esperadas
- Execute todas as queries e compare respostas geradas vs. esperadas
- Meça: Faithfulness (resposta tem suporte nos docs?), Relevance (responde a pergunta?), Context Precision (docs retornados são os certos?)
- Ajuste parâmetros (chunk size, top_k, cutoff, response_mode) até atingir qualidade aceitável
- Go-live com 10% dos usuários → coleta de feedback → ajustes → 100%