Quando um assistente baseado em RAG (geração aumentada por recuperação) responde algo errado, a reação comum é trocar o modelo ou reescrever o prompt. Na prática, boa parte desses erros acontece um passo antes: o trecho que continha a resposta nunca chegou ao modelo. Um modelo excelente com contexto errado produz uma resposta errada, só que mais bem escrita.
Por isso, a primeira coisa que medimos em um sistema RAG não é a resposta final. É a recuperação.
Separe o sistema em duas perguntas
Um pipeline RAG responde a duas perguntas diferentes, e cada uma precisa de uma métrica própria:
- A recuperação encontrou a evidência certa? Isso depende de chunking, embeddings, busca textual, filtros de permissão e reranking.
- A geração usou essa evidência corretamente? Isso depende do modelo, do prompt e das regras de citação.
Se você mede apenas a resposta final, não sabe qual das duas falhou. Uma queda de qualidade depois de mudar a estratégia de chunking aparece igual a uma queda causada por um prompt pior.
Monte o conjunto de avaliação antes do sistema
O conjunto de avaliação é uma lista de perguntas reais com a indicação de quais trechos dos documentos contêm a resposta. Ele não precisa ser enorme para ser útil: algumas dezenas de perguntas bem escolhidas já revelam a maioria das regressões, e ele cresce com o tempo.
Três cuidados fazem diferença:
- Perguntas de usuários reais, não perguntas escritas por quem conhece o documento de cor. Usuários usam sinônimos, abreviações e formulações vagas.
- Perguntas sem resposta. Inclua casos em que o documento não contém a informação. O comportamento correto é recusar, e isso também precisa ser medido.
- Identificadores estáveis. Cada trecho precisa de um ID que não mude quando você reprocessa os documentos, senão o conjunto de avaliação quebra a cada mudança de pipeline.
{"id": "q-017", "question": "Qual é a multa por rescisão antecipada?", "relevant": ["contrato-0442/§14.2"], "answerable": true}Métricas de recuperação
Com o conjunto em mãos, duas métricas simples cobrem a maior parte das necessidades.
Recall@k mede a fração de perguntas em que pelo menos um trecho relevante apareceu entre os k primeiros resultados. Se o recall@5 é 0,70, em 30% das perguntas o modelo nunca viu a evidência e, na melhor das hipóteses, vai recusar.
MRR (mean reciprocal rank) mede quão alto o primeiro trecho relevante aparece. Ele importa porque modelos dão mais peso ao que vem primeiro no contexto, e porque você pode querer reduzir k para economizar tokens.
def recall_at_k(results: dict[str, list[str]], gold: dict[str, set[str]], k: int) -> float:
hits = sum(1 for q, ranked in results.items() if gold[q] & set(ranked[:k]))
return hits / len(results)
def mean_reciprocal_rank(results: dict[str, list[str]], gold: dict[str, set[str]]) -> float:
total = 0.0
for q, ranked in results.items():
for position, chunk_id in enumerate(ranked, start=1):
if chunk_id in gold[q]:
total += 1.0 / position
break
return total / len(results)Calcule as métricas apenas sobre perguntas respondíveis. As não respondíveis entram na avaliação da geração.
Métricas de geração
Para a geração, três medidas cobrem os riscos principais:
- Fidelidade: cada afirmação da resposta é sustentada pelos trechos fornecidos? Pode ser avaliada por revisão humana em amostras e, em escala, por um modelo avaliador com instruções estritas.
- Validade das citações: toda citação aponta para um trecho que de fato foi enviado ao modelo? Isso é verificável por código, sem modelo nenhum, e deve bloquear a resposta quando falha.
- Taxa de recusa correta: nas perguntas sem resposta, o sistema recusou? E nas respondíveis, recusou indevidamente?
Avaliadores automáticos baseados em LLM são úteis, mas têm vieses: tendem a favorecer respostas longas e podem concordar com erros plausíveis. Calibre o avaliador contra uma amostra revisada por pessoas antes de confiar nos números.
Coloque a avaliação no CI
A avaliação só protege o sistema se rodar sempre. Tratamos o conjunto de avaliação como um teste de regressão: toda mudança em chunking, embeddings, modelo ou prompt executa a suíte e compara com a linha de base.
Dois detalhes evitam frustração:
- Limiares com margem. Pequenas variações são normais, especialmente na geração. Falhe o build em quedas relevantes, não em ruído.
- Relatório por pergunta. Uma média esconde onde está o problema. Guarde quais perguntas mudaram de acerto para erro, porque é ali que está o diagnóstico.
Quando o recall está baixo
Algumas causas aparecem com frequência:
- Termos exatos. Números de cláusula, códigos de produto e nomes próprios são mal representados por embeddings. Busca híbrida, combinando vetores com busca textual, costuma resolver.
- Chunks que cortam o conteúdo. Janelas fixas de tokens separam uma regra da sua exceção. Segmentar pela estrutura do documento ajuda.
- Filtros de permissão aplicados tarde. Se você filtra depois de recuperar os
kprimeiros, pode sobrar zero resultado. Aplique o filtro na própria consulta.
Resumo
Medir a recuperação separadamente transforma a melhoria de um sistema RAG de tentativa e erro em engenharia. Com um conjunto de avaliação versionado, métricas de recall e fidelidade e execução contínua, cada mudança vira uma decisão informada, e uma troca de modelo deixa de ser uma aposta.
Leituras relacionadas
- IA aplicada · 3 min de leitura
- Machine Learning · 4 min de leitura
- Machine Learning · 3 min de leitura