0Pricing
AI Engineering Academy · Leçon

Mesures de récupération : taux de réussite, MRR et NDCG

Créez un jeu de données de référence composé de requêtes et de documents pertinents, puis calculez le taux de réussite, le rang réciproque moyen et le NDCG pour mesurer la fréquence à laquelle votre système de récupération trouve les bons segments.

Mesures de récupération : taux de réussite, MRR et NDCG est une leçon AI Engineering Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Engineering Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Engineering Academy comprend 4 leçons au total.

Pourquoi différentes métriques de récupération ?

Le taux de réussite vous indique si un segment pertinent apparaît quelque part parmi les K premiers résultats, mais il ne vous dit pas à quelle position il apparaît. Un système qui place toujours le meilleur segment au rang 5 est moins performant qu'un système qui le place systématiquement au rang 1, même si les deux ont le même taux de réussite. Des métriques plus nuancées comme MRR et NDCG évaluent la qualité du classement et favorisent les systèmes qui placent les segments les plus pertinents en tête, là où le LLM et les utilisateurs sont le plus susceptibles de les exploiter.

Taux de réussite@K : révision et implémentation

Le taux de réussite@K est la métrique la plus simple : pour quelle proportion de requêtes au moins un segment pertinent apparaît-il parmi les K premiers résultats ? Il fournit un signal binaire pour chaque requête et est facile à interpréter. Calculez-le en vérifiant l'intersection entre l'ensemble des identifiants récupérés et celui des identifiants pertinents connus. Utilisez K=5 par défaut, car la plupart des systèmes RAG récupèrent 5 segments. Comparez les taux de réussite@1, @3 et @5 pour comprendre comment la sensibilité évolue lorsque vous élargissez la fenêtre de récupération.

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%}')

Rang réciproque moyen (MRR)

MRR (rang réciproque moyen) mesure la moyenne de l'inverse du rang auquel apparaît le premier segment pertinent. Si le segment pertinent est au rang 1, le rang réciproque vaut 1/1 = 1,0. Au rang 2, il vaut 0,5 ; au rang 5, 0,2. La MRR est calculée sur l'ensemble des requêtes. Une MRR élevée signifie que le système de récupération place systématiquement les segments pertinents près du début, ce qui est important, car le LLM accorde davantage d'attention au contexte placé au début de l'invite.

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

Interpréter les scores MRR

Les scores MRR s'interprètent intuitivement : MRR = 1,0 signifie que le premier segment pertinent est toujours au rang 1 (résultat parfait). MRR = 0,5 signifie qu'il se trouve généralement au rang 2. MRR = 0,25 signifie qu'il se trouve généralement au rang 4 : les informations pertinentes apparaissent suffisamment bas pour risquer d'être tronquées dans le contexte. Pour RAG, visez une MRR > 0,7 afin de garantir que votre segment le plus pertinent se trouve systématiquement parmi les deux premières positions.

# 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}')

Précision@K

La précision@K mesure la proportion des K segments récupérés qui sont réellement pertinents. Contrairement au taux de réussite, qui est binaire, la précision@K mesure le rapport signal/bruit de vos résultats de récupération. Une faible précision signifie que le LLM reçoit un contexte non pertinent en plus des segments pertinents, ce qui accroît le risque de confusion ou d'injection d'invite. Pour RAG, une précision@5 > 0,6 constitue un objectif sain.

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

Gain cumulatif actualisé (DCG)

DCG est une métrique d'évaluation des listes classées qui récompense le placement des segments les plus pertinents en haut de la liste. Elle additionne les scores de pertinence des segments récupérés, tout en les actualisant logarithmiquement selon leur position : le rang 1 reçoit le crédit complet, le rang 2 reçoit une actualisation log(2), et ainsi de suite. Des segments plus pertinents en tête produisent une DCG plus élevée. La version normalisée (NDCG) divise la DCG par la DCG idéale, c'est-à-dire le meilleur classement possible, afin de produire un score compris entre 0 et 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

Calculer la NDCG sur l'ensemble des données

La NDCG@K est la métrique de référence pour évaluer la récupération dans les systèmes de recherche. Elle prend simultanément en compte la pertinence et la position dans le classement. Une NDCG@5 de 0,85 signifie que votre système de récupération atteint en moyenne 85 % du meilleur classement théorique. La NDCG gère les cas où plusieurs segments sont pertinents pour une même requête (chacun reçoit un score de pertinence) et pénalise les systèmes qui trouvent les segments pertinents mais les classent trop bas.

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)

Utiliser RAGAS pour automatiser les métriques

La bibliothèque RAGAS fournit un cadre d'évaluation prêt pour la production des systèmes RAG. Elle implémente les métriques de précision du contexte, de rappel du contexte, de fidélité et de pertinence de la réponse selon une approche où un LLM joue le rôle d'évaluateur. Transmettez vos questions, réponses, contextes récupérés et réponses de référence à RAGAS pour recevoir un rapport d'évaluation complet avec un score pour chaque métrique. C'est le moyen le plus rapide de mettre en place une chaîne d'évaluation RAG complète.

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)

Ventiler les métriques par catégorie de requête

Les moyennes globales des métriques masquent des tendances importantes. Répartissez votre jeu de données de référence en catégories — recherches factuelles, comparaisons, questions procédurales et questions hors périmètre — puis calculez les métriques séparément pour chacune. Vous pourriez constater que le taux de réussite atteint 95 % pour les recherches factuelles, mais seulement 60 % pour les comparaisons à plusieurs étapes. Les métriques par catégorie révèlent les modes d'échec précis que les scores agrégés dissimulent.

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)})')

Lorsque les métriques sont contradictoires

Il arrive que les métriques envoient des signaux contradictoires. Vous pouvez améliorer la NDCG (meilleur classement) tandis que le taux de réussite reste stable (même nombre d'échecs). Cela se produit lorsque l'optimisation fait passer des segments pertinents du rang 6 au rang 2 sans faire entrer dans les cinq premiers résultats des requêtes auparavant manquées. Dans ce cas, vérifiez si votre optimisation a amélioré les requêtes qui réussissaient déjà tout en négligeant celles qui échouaient. Examinez toujours des exemples d'échecs individuels en parallèle des métriques agrégées.

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

Rappel@K : exhaustivité de la récupération

Le rappel@K mesure la proportion de tous les segments pertinents récupérés parmi les K premiers résultats. Si une question possède 3 segments pertinents dans l'index et que votre système de récupération en renvoie 2 parmi les 5 premiers, le rappel@5 vaut 2/3 = 0,67. Un rappel élevé est important lorsque le LLM a besoin de plusieurs éléments de preuve pour synthétiser une réponse complète : l'absence d'un seul segment clé peut rendre la réponse incomplète. Équilibrez précision et rappel en réglant K : une valeur de K plus élevée améliore le rappel, mais réduit la précision.

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

Vérification rapide

Testez votre compréhension des concepts d'ingénierie de l'IA présentés dans cette leçon.

Récapitulatif de la leçon

Dans cette leçon, vous avez appris : le taux de réussite@K comme métrique binaire de présence, MRR pour mesurer la position moyenne du premier segment pertinent, la précision@K pour mesurer le rapport signal/bruit de la récupération, la NDCG@K comme métrique de classement de référence, et la bibliothèque RAGAS pour automatiser l'évaluation de RAG avec la précision du contexte, le rappel, la fidélité et la pertinence de la réponse. Nous allons ensuite approfondir les métriques de génération et la mesure de la fidélité.

Questions Fréquemment Posées

La leçon « Mesures de récupération : taux de réussite, MRR et NDCG » est-elle gratuite ?

Oui — le texte complet de « Mesures de récupération : taux de réussite, MRR et NDCG » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Engineering Academy, passe à CoddyKit PRO. Le cours AI Engineering Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Mesures de récupération : taux de réussite, MRR et NDCG » ?

Créez un jeu de données de référence composé de requêtes et de documents pertinents, puis calculez le taux de réussite, le rang réciproque moyen et le NDCG pour mesurer la fréquence à laquelle votre… Tu pratiques AI Engineering Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer AI Engineering Academy ?

Aucune expérience préalable n'est requise. AI Engineering Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Mesures de récupération : taux de réussite, MRR et NDCG » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon AI Engineering Academy ?

Oui. Chaque leçon AI Engineering Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Pourquoi l’évaluation est importante dans RAG
  2. Mesures de récupération : taux de réussite, MRR et NDCG
  3. Mesures de génération : fidélité et pertinence des réponses
  4. Construire un banc d’évaluation automatisé
← Retour à AI Engineering Academy