RAG em produção: busca híbrida, eval e quando não usar
A maioria dos tutoriais de RAG para em “embute chunks, similaridade de cosseno, cola no prompt”. Isso funciona no notebook. Em produção falha em silêncio: a resposta soa confiante, a citação está errada, a latência dispara na segunda-feira e ninguém sabe se foi a última mudança de prompt ou o último reindex.
Este estudo trata da camada de engenharia depois do demo: desenho de retrieval, busca híbrida, harness de avaliação e a decisão de não usar RAG.
O que o RAG realmente compra
RAG não é “o modelo conhece seus documentos”. É injeção de contexto limitada: na hora da resposta você busca um conjunto pequeno de passagens e pede ao modelo que se mantenha nelas. Você troca:
- Prós: conhecimento mais fresco sem fine-tune completo, fontes auditáveis, isolamento por tenant no índice.
- Contras: erro de retrieval vira erro de resposta; orçamento de tokens limita o que entra; embedding e chunking fazem parte do produto.
Chunking é decisão de produto
Não existe tamanho universal de chunk. O que você otimiza depende de como o usuário pergunta.
| Estratégia | Bom quando | Modo de falha | |------------|------------|---------------| | Janelas fixas de tokens | Docs uniformes, perguntas estilo FAQ | Parte tabelas e procedimentos no meio do passo | | Parágrafo / heading-aware | Políticas, runbooks, KB em markdown | Seções curtas sem contexto local | | Parent–child (retrieve pequeno, ler grande) | PDFs longos, texto legal ou spec | Mais storage e join na leitura | | Chunks com metadata (produto, região, versão) | Suporte multi-catálogo | Metadata ruim → escopo errado em silêncio |
Overlap ajuda continuidade; também multiplica o índice e pode duplicar parágrafos contraditórios de versões diferentes do doc. Versionar documentos fonte e reindexar de forma idempotente (apagar vetores antigos do document_id, depois inserir) vence caos append-only.
Regra prática: registre os chunk ids que entraram no prompt. Quando o suporte diz “o bot mentiu sobre garantia”, você reproduz esse trace em minutos.
Drift de embedding sem drama
Mesmo texto, novo modelo de embedding, novo espaço vetorial — vetores antigos e novos não devem coexistir no mesmo índice a menos que haja dual-write e cutover explícito. Checklist de produção:
1. Fixar id do modelo de embedding na config (text-embedding-3-small, etc.).
2. Job de reindex observável: documentos/hora, falhas, guardas de dimensão.
3. Limiares de similaridade são por corpus, não copiados de artigo. Limiar 0,55 não significa nada sem a distribuição de scores do seu índice.
Quando a qualidade cai após update do vendor, assuma que o retrieval se moveu antes de reescrever o system prompt.
Busca híbrida: quando vetor sozinho não basta
Retrieval denso puro perde tokens exatos: SKUs, códigos de erro, nomes internos de projeto, “seção 4.2.1”. Padrões híbridos que aguentam:
- Denso + BM25 (ou
tsvectorno Postgres) com reciprocal rank fusion ou pesos aprendidos. - Pré-filtro em metadata (
organization_id,product_line,doc_status=published) antes da similaridade — RAG multi-tenant que pula isso vaza contexto entre orgs de formas sutis. - Reescrita de query (HyDE, sub-queries) só depois de medir recall baseline; LLM extra adiciona latência e novos modos de falha.
Grounding e abstinência
Retriever que não acha nada útil não deve disparar completion criativa. Padrões que passam em auditoria:
- Ramo explícito “sem fontes relevantes”: handoff humano ou pergunta de esclarecimento, não chute.
- Exigir que o modelo cite chunk ids ou títulos de fonte em ferramentas internas; rejeitar respostas que citam ids fora do bloco de contexto (checagem programática onde couber).
- Limitar tamanho do contexto injetado; truncar com estrutura (“Fonte 1: …”) para referência consistente.
Avaliação antes e depois de cada mudança
Se você só avalia lendo dez chats no Slack, vai shippar regressão. Loop mínimo de eval:
1. Golden set: perguntas reais (redigidas) + doc ids de suporte esperados ou rubrica de resposta. 2. Métricas de retrieval: recall@k, MRR em pares q→doc rotulados; separado da qualidade de geração. 3. Métricas de geração: LLM-as-judge com spot-check humano, ou só humano em domínios de risco. 4. Gate de CI: golden set pequeno em PRs que mexem em chunking, embeddings ou SQL de retrieval.
Regressão em recall@5 é blocker; ajustar prompt para “soar melhor” com recall em queda é como times perdem confiança.
Quando não usar RAG
RAG é ferramenta errada quando:
- O conhecimento é pequeno e estável — cabe no system prompt ou schema de tool compilado.
- Você precisa de cálculo determinístico (preço, elegibilidade) — use código ou motor de regras; LLM explica o resultado.
- SLO de latência apertado e corpus enorme — considere resumos pré-computados, roteamento para sub-agentes ou modelos pequenos fine-tuned em snapshot congelado.
- Classificação de segurança impede misturar passagens num prompt — particione índices e roteie a query antes.
Operar o stack
O que times sênior instrumentam:
- p95 de latência de retrieval e duração de batch de embedding
- Taxa de hit vazio e abaixo do limiar por org
- Contagem de tokens do contexto montado vs limite do modelo
- Traces ligando
request_id→ chunk ids → id da completion
Encerramento
RAG em produção é engenharia de busca + política + observabilidade, com um LLM no fim. Chunking, retrieval híbrido, filtros seguros por tenant, abstinência e golden set separam demo de algo que jurídico e ops rodam.
Se você já opera um stack específico de produto (voz, inbox, workers no Kafka), mantenha uma espinha de retrieval e pendure canais nela — retriever duplicado por superfície é onde a divergência começa.