Todo piloto de RAG (retrieval-augmented generation) impressiona na demo. Você sobe vinte PDFs, faz três perguntas preparadas, o modelo responde bem, todo mundo aplaude. Três meses depois, em produção, com oitenta mil documentos reais e usuários fazendo perguntas que ninguém previu, o mesmo sistema erra a maioria das respostas — e ninguém sabe exatamente por quê.
Isso não é falha do modelo. É falha de engenharia em três pontos específicos: chunking, retrieval e avaliação. Nesta ordem, porque cada um mascara o problema do anterior até o sistema desmoronar em produção.
O pipeline que funciona na demo
A arquitetura padrão de RAG é simples o suficiente para caber num quadro branco:
O problema é que essa arquitetura tem quatro decisões de projeto embutidas — como cortar o documento, como buscar, como reordenar, como avaliar — e a maioria dos times toma as quatro no piloto de fim de semana e nunca mais revisita nenhuma.
Chunking: o pecado original
A implementação mais comum que vejo em código de cliente é cortar o texto em blocos de tamanho fixo, geralmente por contagem de tokens, com uma sobreposição arbitrária:
def chunk_por_tamanho_fixo(texto: str, tamanho: int = 512, overlap: int = 50) -> list[str]:
palavras = texto.split()
chunks = []
passo = tamanho - overlap
for i in range(0, len(palavras), passo):
chunk = " ".join(palavras[i : i + tamanho])
if chunk:
chunks.append(chunk)
return chunksEssa função não sabe onde termina uma seção, uma tabela ou um parágrafo. Ela corta uma cláusula contratual no meio, separa uma pergunta da sua resposta em um FAQ, e transforma uma linha de tabela em texto solto sem cabeçalho. O embedding desse pedaço fica ambíguo — e ambiguidade no embedding vira erro de retrieval, não erro de geração.
A alternativa que funciona na prática é chunking estrutural: respeitar títulos, parágrafos e blocos semânticos do documento, e só cair no corte por tamanho fixo quando um bloco estrutural for grande demais para o contexto.
| Estratégia | Recall@10 (interno, corpus jurídico) | Custo de indexação | Quando usar |
|---|---|---|---|
| Tamanho fixo (512 tokens, overlap 50) | 61% | Baixo | Nunca como escolha final — só como baseline |
| Por parágrafo/seção (respeitando Markdown/HTML) | 78% | Baixo-médio | Documentação, contratos, manuais |
| Semântico (embedding de sentenças + clustering) | 84% | Alto | Corpus heterogêneo, sem estrutura confiável |
| Hierárquico (chunk pequeno pra busca, chunk grande pro contexto) | 87% | Médio-alto | Bases grandes com necessidade de precisão e contexto |
Os números acima são de um benchmark interno rodado sobre um corpus jurídico de ~40 mil páginas — não são universais, mas a ordem de grandeza da diferença entre "tamanho fixo" e qualquer alternativa estrutural se repete em praticamente todo projeto que já medimos.
Retrieval: recall importa mais que embedding chique
Boa parte do tempo dos times é gasto escolhendo o modelo de embedding "certo" — comparando benchmarks do MTEB, testando o mais novo lançamento. É otimização no lugar errado. A diferença entre um bom e um ótimo modelo de embedding, medida em recall final do sistema, costuma ser de poucos pontos percentuais. A diferença entre ter reranking e não ter costuma ser de vinte a trinta.
Só busca vetorial (top-k=10)
Rápido e barato, mas o ranking da busca vetorial otimiza similaridade de embedding, não relevância pra responder a pergunta. Documentos parecidos no espaço vetorial nem sempre são os mais úteis — e o LLM recebe o top-10 na ordem errada, com o pedaço certo às vezes na posição 8 ou 9, fora da parte do contexto que o modelo de fato usa.
Busca vetorial + reranking (top-50 → top-5)
Recupera um conjunto maior (top-50) com um filtro barato, depois usa um reranker — um modelo cross-encoder treinado especificamente pra estimar relevância pergunta-documento — pra reordenar e cortar pra top-5. Adiciona 80-150ms de latência e um custo de inferência pequeno, mas corrige o problema de ranking na raiz.
+29pp
ganho de recall@5 com reranking
benchmark interno, corpus jurídico
~120ms
latência adicional do reranker
cross-encoder, batch de 50
3x
chamadas de embedding por pergunta com HyDE
query expansion
Se você só vai implementar uma coisa depois de ler este artigo, que seja reranking. É a intervenção com melhor retorno sobre esforço que existe em RAG hoje.
Avaliação: se você não mede, está adivinhando
O erro mais caro que vi em projeto de RAG não foi técnico — foi organizacional: nenhum conjunto de avaliação. O time ajustava prompt, trocava chunk size, mudava o top_k, e validava "na mão", rodando as mesmas cinco perguntas de sempre. Cada mudança parecia uma melhoria, porque ninguém media a régua inteira.
Isso não é exagero de consultor. É o padrão que se repete em praticamente todo cliente sem processo de avaliação: decisões técnicas viram debate de opinião porque não existe número pra encerrar a discussão.
Sem um golden set, toda mudança em RAG é uma opinião. Com um golden set, é um número que você pode defender numa reunião de status.
Monte um conjunto de 50-200 perguntas reais (não inventadas), com a resposta esperada e, se possível, os documentos-fonte corretos. Registre cada execução:
create table rag_avaliacao (
id uuid primary key default gen_random_uuid(),
pergunta text not null,
resposta_ref text not null,
docs_ref text[] not null,
versao_pipeline text not null,
docs_retornados text[] not null,
resposta_gerada text not null,
recall_at_10 numeric(4,3),
avaliado_em timestamptz not null default now()
);
-- Consulta que todo relatório de regressão de RAG deveria rodar antes de um deploy
select
versao_pipeline,
avg(recall_at_10) as recall_medio,
count(*) filter (where recall_at_10 < 0.5) as perguntas_criticas
from rag_avaliacao
group by versao_pipeline
order by versao_pipeline desc;Com essa tabela, "melhorei o retrieval" vira uma comparação de duas linhas de resultado, não uma sensação. E quando o cliente perguntar por que uma resposta específica saiu errada, você tem o rastro completo — pergunta, documentos recuperados, resposta gerada — em vez de tentar reproduzir o bug reconstituindo de memória.
Custo: a conta que aparece no mês 3
O erro de estimativa mais comum é calcular custo pelo preço por token do modelo de geração e esquecer que RAG multiplica chamadas. Um pipeline com HyDE (gerar uma resposta hipotética pra melhorar a busca), reranking e uma etapa de verificação de alucinação facilmente faz 3-4 chamadas de LLM por pergunta do usuário, além da geração final — e o contexto recuperado (top-5 chunks de 1000 tokens) entra inteiro no prompt toda vez.
Antes de prometer um SLA de custo por interação para o cliente, calcule com o pipeline completo rodando, não com uma chamada isolada ao modelo de geração. É a diferença entre uma proposta comercial que fecha a conta e uma que estoura no primeiro mês de uso real.
O que realmente funciona
Depois de alguns projetos de RAG em produção, o checklist que efetivamente reduz risco é curto:
- Chunking estrutural antes de qualquer coisa — nunca corte por tamanho fixo como decisão final.
- Reranking sempre, mesmo que pareça complexidade desnecessária no início.
- Um golden set de avaliação antes do primeiro deploy, não depois do primeiro incidente.
- Logging estruturado de cada execução (pergunta, chunks recuperados, resposta) desde o dia um.
- Custo calculado sobre o pipeline completo, não sobre o preço por token anunciado pelo provedor do modelo.
Nenhum item dessa lista é sofisticado. O que separa os pilotos que viram produto dos que morrem na gaveta não é acesso a um modelo melhor — é disciplina de engenharia nas partes menos glamorosas do sistema.
Se o argumento que interessa pra sua empresa não é "como construir RAG" mas "o que priorizar quando a plataforma de modelo já não é mais diferencial", vale a leitura complementar sobre por que o modelo deixou de ser vantagem competitiva — que trata exatamente do outro lado dessa mesma decisão.