0Pricing
AI Engineering Academy · Aula

Métricas de recuperação: taxa de acerto, MRR e NDCG

Crie um conjunto de dados de referência com consultas e documentos relevantes e calcule a taxa de acerto, a classificação recíproca média e NDCG para medir com que frequência seu recuperador encontra as partes corretas.

Métricas de recuperação: taxa de acerto, MRR e NDCG é uma aula grátis de AI Engineering Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Engineering Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Engineering Academy inclui 4 aulas no total.

Por que usar métricas de recuperação diferentes?

A taxa de acerto informa se um trecho relevante apareceu em qualquer posição entre os K principais resultados, mas não informa onde ele apareceu na classificação. Um sistema que sempre coloca o melhor trecho na quinta posição é pior do que um que o coloca consistentemente na primeira posição, mesmo que ambos tenham a mesma taxa de acerto. Métricas mais detalhadas, como MRR e NDCG, capturam a qualidade da classificação e recompensam os sistemas que colocam os trechos mais relevantes no topo, onde o LLM e os usuários têm maior probabilidade de utilizá-los.

Taxa de acerto @K: revisão e implementação

A taxa de acerto@K é a métrica mais simples: para qual fração das consultas pelo menos um trecho relevante aparece entre os K principais resultados? Ela fornece um sinal binário por consulta e é fácil de interpretar. Calcule-a verificando a interseção entre os identificadores recuperados e os identificadores relevantes conhecidos. Use K=5 como padrão, pois a maioria dos sistemas RAG recupera 5 trechos. Compare a taxa de acerto@1, @3 e @5 para entender como a sensibilidade muda à medida que você amplia a janela de recuperação.

def hit_rate_at_k(golden_dataset, retriever, k=5):
    hits = 0
    for item in golden_dataset:
        retrieved = retriever.retrieve(item['question'], top_k=k)
        retrieved_ids = [r['id'] for r in retrieved[:k]]
        relevant_ids = set(item['relevant_chunk_ids'])
        if any(rid in relevant_ids for rid in retrieved_ids):
            hits += 1
    return hits / len(golden_dataset)

for k in [1, 3, 5, 10]:
    hr = hit_rate_at_k(golden_dataset, retriever, k=k)
    print(f'Hit rate@{k}: {hr:.1%}')

Classificação recíproca média (MRR)

MRR (Classificação recíproca média) mede a média do inverso da posição em que o primeiro trecho relevante aparece. Se o trecho relevante estiver na posição 1, a classificação recíproca será 1/1 = 1,0. Na posição 2, será 0,5; na posição 5, será 0,2. A MRR é calculada sobre todas as consultas. Uma MRR mais alta significa que o recuperador coloca consistentemente os trechos relevantes perto do topo, o que é importante porque o LLM presta mais atenção ao contexto posicionado no início do prompt.

def mean_reciprocal_rank(golden_dataset, retriever, top_k=10):
    reciprocal_ranks = []
    for item in golden_dataset:
        retrieved = retriever.retrieve(item['question'], top_k=top_k)
        retrieved_ids = [r['id'] for r in retrieved]
        relevant_ids = set(item['relevant_chunk_ids'])

        rr = 0.0
        for rank, rid in enumerate(retrieved_ids, start=1):
            if rid in relevant_ids:
                rr = 1.0 / rank
                break  # only the first relevant result counts
        reciprocal_ranks.append(rr)

    mrr = sum(reciprocal_ranks) / len(reciprocal_ranks)
    print(f'MRR@{top_k}: {mrr:.3f}')
    return mrr

Interpretação das pontuações de MRR

As pontuações de MRR têm interpretações intuitivas: MRR = 1,0 significa que o primeiro trecho relevante está sempre na posição 1 (perfeito). MRR = 0,5 significa que ele normalmente está na posição 2. MRR = 0,25 significa que ele normalmente está na posição 4 — a informação relevante aparece suficientemente abaixo para que possa ser truncada do contexto. Para RAG, a meta é MRR > 0,7, garantindo que seu trecho mais relevante esteja consistentemente entre as duas primeiras posições.

# MRR interpretation table
mrr_interpretations = {
    1.0:  'Perfect — relevant chunk always at rank 1',
    0.5:  'Good — typically at rank 2',
    0.33: 'Acceptable — typically at rank 3',
    0.25: 'Weak — typically at rank 4',
    0.1:  'Poor — relevant chunk rarely near the top'
}

for score, description in mrr_interpretations.items():
    print(f'MRR {score:.2f}: {description}')

Precisão @K

Precisão@K mede qual fração dos K trechos recuperados é realmente relevante. Diferentemente da taxa de acerto (que é binária), a precisão@K mede a relação sinal-ruído nos resultados da sua recuperação. Uma precisão baixa significa que o LLM recebe contexto irrelevante junto com os trechos relevantes, aumentando o risco de confusão ou injeção de prompt. Para RAG, uma meta saudável é precisão@5 > 0,6.

def precision_at_k(golden_dataset, retriever, k=5):
    precisions = []
    for item in golden_dataset:
        retrieved = retriever.retrieve(item['question'], top_k=k)
        retrieved_ids = [r['id'] for r in retrieved[:k]]
        relevant_ids = set(item['relevant_chunk_ids'])

        relevant_retrieved = sum(
            1 for rid in retrieved_ids if rid in relevant_ids
        )
        precision = relevant_retrieved / k
        precisions.append(precision)

    mean_precision = sum(precisions) / len(precisions)
    print(f'Precision@{k}: {mean_precision:.3f}')
    return mean_precision

Ganho cumulativo com desconto (DCG)

DCG é uma métrica de avaliação de listas classificadas que recompensa a colocação de trechos mais relevantes nas posições superiores. Ela soma as pontuações de relevância dos trechos recuperados, mas aplica um desconto logarítmico de acordo com a posição: a posição 1 recebe crédito integral, a posição 2 recebe o desconto de log(2), e assim por diante. Trechos mais relevantes no topo resultam em um DCG maior. A versão normalizada (NDCG) divide pelo DCG ideal (a melhor classificação possível) para produzir uma pontuação entre 0 e 1.

import math

def dcg_at_k(relevances, k):
    '''relevances[i] = 1 if chunk at rank i+1 is relevant, else 0'''
    dcg = 0.0
    for i, rel in enumerate(relevances[:k]):
        # rank is i+1, discount is log2(rank + 1)
        dcg += rel / math.log2(i + 2)
    return dcg

def ndcg_at_k(retrieved_ids, relevant_ids, k):
    relevances = [1 if rid in relevant_ids else 0
                  for rid in retrieved_ids[:k]]
    actual_dcg = dcg_at_k(relevances, k)
    ideal_dcg = dcg_at_k([1] * min(len(relevant_ids), k), k)
    return actual_dcg / ideal_dcg if ideal_dcg > 0 else 0.0

Cálculo do NDCG em todo o conjunto de dados

NDCG@K é a métrica de referência para recuperação em sistemas de busca. Ela captura simultaneamente a relevância e a posição na classificação. Um NDCG@5 de 0,85 significa que seu recuperador alcança, em média, 85% da melhor classificação teórica. O NDCG lida com casos em que há vários trechos relevantes por consulta (cada um recebe uma pontuação de relevância) e penaliza sistemas que encontram os trechos relevantes, mas os classificam em posições muito baixas.

def mean_ndcg_at_k(golden_dataset, retriever, k=5):
    ndcg_scores = []
    for item in golden_dataset:
        retrieved = retriever.retrieve(item['question'], top_k=k)
        retrieved_ids = [r['id'] for r in retrieved[:k]]
        relevant_ids = set(item['relevant_chunk_ids'])
        score = ndcg_at_k(retrieved_ids, relevant_ids, k)
        ndcg_scores.append(score)
    mean = sum(ndcg_scores) / len(ndcg_scores)
    print(f'NDCG@{k}: {mean:.4f}')
    return mean

# Compute all retrieval metrics together
hit_rate = hit_rate_at_k(golden_dataset, retriever, k=5)
mrr = mean_reciprocal_rank(golden_dataset, retriever, top_k=5)
ndcg = mean_ndcg_at_k(golden_dataset, retriever, k=5)

Uso do RAGAS para métricas automatizadas

A biblioteca RAGAS fornece uma estrutura de avaliação pronta para produção para sistemas RAG. Ela implementa métricas de precisão do contexto, revocação do contexto, fidelidade e relevância da resposta usando uma abordagem de LLM como avaliador. Forneça suas perguntas, respostas, contextos recuperados e respostas de referência ao RAGAS e receba um relatório completo de avaliação com pontuações para cada métrica. Essa é a maneira mais rápida de configurar um pipeline abrangente de avaliação de RAG.

from ragas import evaluate
from ragas.metrics import (
    context_precision,
    context_recall,
    faithfulness,
    answer_relevancy
)
from datasets import Dataset

eval_data = Dataset.from_list([
    {
        'question': item['question'],
        'answer': item['generated_answer'],
        'contexts': item['retrieved_texts'],
        'ground_truth': item['expected_answer']
    }
    for item in golden_dataset_with_answers
])

results = evaluate(
    eval_data,
    metrics=[context_precision, context_recall, faithfulness, answer_relevancy]
)
print(results)

Divisão das métricas por categoria de consulta

As médias gerais das métricas ocultam padrões importantes. Divida seu conjunto de dados dourado em categorias — consultas factuais, comparações, perguntas procedurais do tipo “como fazer” e perguntas fora do escopo — e calcule as métricas separadamente para cada uma. Você pode descobrir que a taxa de acerto é de 95% para consultas factuais, mas de apenas 60% para comparações com várias etapas. As métricas por categoria revelam os modos de falha específicos que as pontuações agregadas ocultam.

from collections import defaultdict

def evaluate_by_category(golden_dataset, retriever):
    by_category = defaultdict(list)
    for item in golden_dataset:
        category = item.get('category', 'unknown')
        retrieved = retriever.retrieve(item['question'], top_k=5)
        retrieved_ids = {r['id'] for r in retrieved}
        hit = bool(retrieved_ids & set(item['relevant_chunk_ids']))
        by_category[category].append(hit)

    print('Hit rate by category:')
    for cat, hits in sorted(by_category.items()):
        hr = sum(hits) / len(hits)
        print(f'  {cat}: {hr:.1%} ({sum(hits)}/{len(hits)})')

Quando as métricas divergem

Às vezes, as métricas enviam sinais conflitantes. Você pode melhorar o NDCG (melhor classificação) enquanto a taxa de acerto permanece estável (o mesmo número de falhas). Isso acontece quando a otimização move trechos relevantes da posição 6 para a posição 2 sem trazer para o top 5 consultas que antes não obtinham resultados relevantes. Nesses casos, verifique se sua otimização ajudou nas consultas que já estavam funcionando e negligenciou as que falhavam. Sempre examine exemplos individuais de falha junto com as métricas agregadas.

def analyze_failures(golden_dataset, retriever, top_k=5):
    failures = []
    for item in golden_dataset:
        retrieved = retriever.retrieve(item['question'], top_k=top_k)
        retrieved_ids = {r['id'] for r in retrieved}
        relevant_ids = set(item['relevant_chunk_ids'])
        if not (retrieved_ids & relevant_ids):
            failures.append({
                'question': item['question'],
                'expected_chunks': list(relevant_ids),
                'retrieved_chunks': [r['id'] for r in retrieved],
                'top_score': retrieved[0]['score'] if retrieved else None
            })
    print(f'Failures: {len(failures)}/{len(golden_dataset)}')
    return failures

Revocação @K: completude da recuperação

Revocação@K mede qual fração de todos os trechos relevantes foi recuperada entre os K principais resultados. Se uma pergunta tiver 3 trechos relevantes no índice e seu recuperador retornar 2 deles entre os 5 principais, a revocação@5 será 2/3 = 0,67. Uma revocação alta é importante quando o LLM precisa de várias evidências para sintetizar uma resposta completa — a ausência de um único trecho essencial pode tornar a resposta incompleta. Equilibre precisão e revocação ajustando K: um K maior melhora a revocação, mas reduz a precisão.

def recall_at_k(golden_dataset, retriever, k=5):
    recalls = []
    for item in golden_dataset:
        retrieved = retriever.retrieve(item['question'], top_k=k)
        retrieved_ids = set(r['id'] for r in retrieved[:k])
        relevant_ids = set(item['relevant_chunk_ids'])
        if not relevant_ids:
            continue  # skip items with no annotated relevant chunks
        retrieved_relevant = retrieved_ids & relevant_ids
        recall = len(retrieved_relevant) / len(relevant_ids)
        recalls.append(recall)
    mean_recall = sum(recalls) / len(recalls)
    print(f'Recall@{k}: {mean_recall:.3f}')
    return mean_recall

Verificação rápida

Teste sua compreensão dos conceitos de Engenharia de IA desta lição.

Recapitulação da lição

Nesta lição, você aprendeu: a taxa de acerto@K como métrica binária de presença; MRR para medir a posição média do primeiro trecho relevante; precisão@K para medir a relação sinal-ruído da recuperação; NDCG@K como métrica de referência para listas classificadas; e a biblioteca RAGAS para automatizar a avaliação de RAG com precisão do contexto, revocação, fidelidade e relevância da resposta. Em seguida, aprofundaremos as métricas de geração e a medição da fidelidade.

Perguntas Frequentes

A aula “Métricas de recuperação: taxa de acerto, MRR e NDCG” é grátis?

Sim — o texto completo de “Métricas de recuperação: taxa de acerto, MRR e NDCG” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Engineering Academy, atualize para CoddyKit PRO. O curso de AI Engineering Academy inclui 4 aulas no total.

O que vou aprender em “Métricas de recuperação: taxa de acerto, MRR e NDCG”?

Crie um conjunto de dados de referência com consultas e documentos relevantes e calcule a taxa de acerto, a classificação recíproca média e NDCG para medir com que frequência seu recuperador encontra… Você pratica AI Engineering Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar AI Engineering Academy?

Nenhuma experiência prévia é necessária. AI Engineering Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Métricas de recuperação: taxa de acerto, MRR e NDCG”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de AI Engineering Academy?

Sim. Cada aula de AI Engineering Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Por que a avaliação é importante em RAG
  2. Métricas de recuperação: taxa de acerto, MRR e NDCG
  3. Métricas de geração: fidelidade e relevância da resposta
  4. Criando uma estrutura automatizada de avaliação
← Voltar para AI Engineering Academy