Construire un banc d’évaluation automatisé
Créez un pipeline d’évaluation reproductible qui exécute votre système RAG complet sur un jeu de test, calcule toutes les mesures et génère un rapport afin de suivre les progrès au fil du temps.
Construire un banc d’évaluation automatisé est une leçon AI Engineering Academy gratuite sur CoddyKit. Ceci est la leçon 4 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.
Qu’est-ce qu’un dispositif d’évaluation ?
Un dispositif d’évaluation est un pipeline automatisé et reproductible qui exécute l’ensemble de votre système RAG sur un jeu de tests standardisé, calcule toutes les métriques et produit un rapport. Le mot essentiel est reproductible : chaque fois que vous modifiez votre stratégie de découpage, votre modèle de plongements, votre prompt ou votre LLM, vous exécutez le même dispositif et comparez les résultats à une référence. Le développement de RAG passe ainsi d’un tâtonnement subjectif à une démarche d’ingénierie fondée sur les données.
Architecture du dispositif
Un dispositif d’évaluation bien conçu comporte quatre couches : la gestion des données de test (charger et versionner le jeu de données de référence), l’exécution du pipeline (faire passer chaque question de test dans l’ensemble du pipeline RAG), le calcul des métriques (calculer toutes les métriques de récupération et de génération) et la génération du rapport (enregistrer les résultats avec les informations de version et produire une comparaison avec la référence précédente). Chaque couche doit pouvoir être testée et configurée indépendamment.
class RAGEvaluationHarness:
def __init__(self, retriever, llm_client, config):
self.retriever = retriever
self.llm_client = llm_client
self.config = config # chunk_size, top_k, model, threshold, etc.
self.results = []
def run(self, golden_dataset):
for item in golden_dataset:
result = self._evaluate_single(item)
self.results.append(result)
metrics = self._compute_metrics()
self._save_report(metrics)
return metricsExécuter chaque cas de test
Pour chaque question du jeu de données de référence, exécutez l’ensemble du pipeline RAG et capturez toutes les sorties intermédiaires : les identifiants et les scores des segments récupérés, le contexte mis en forme, la réponse générée et le nombre de jetons. L’enregistrement de ces valeurs intermédiaires est essentiel pour déboguer les échecs : lorsqu’une question obtient un score faible, vous pouvez examiner exactement quels segments ont été récupérés et pourquoi la réponse était incorrecte, sans réexécuter le pipeline coûteux.
import time
def _evaluate_single(self, item):
start = time.perf_counter()
query_vector = embed_query(item['question'])
chunks = self.retriever.retrieve(query_vector, top_k=self.config['top_k'])
filtered_chunks = filter_by_score(chunks, self.config['threshold'])
context = format_context(filtered_chunks)
answer_result = generate_answer(item['question'], context, self.llm_client)
latency_ms = (time.perf_counter() - start) * 1000
return {
'question': item['question'],
'expected_answer': item['answer'],
'generated_answer': answer_result['answer'],
'retrieved_chunk_ids': [c['id'] for c in filtered_chunks],
'retrieved_scores': [c['score'] for c in filtered_chunks],
'relevant_chunk_ids': item['relevant_chunk_ids'],
'context_texts': [c['text'] for c in filtered_chunks],
'tokens_used': answer_result['tokens_used'],
'latency_ms': round(latency_ms)
}Calculer toutes les métriques en un seul passage
Après avoir recueilli les sorties de tous les cas de test, calculez l’ensemble des métriques en un seul passage sur les résultats. Séparez les métriques de récupération (calculées à partir des identifiants de segments) des métriques de génération (calculées en appelant le LLM évaluateur). Regroupez les appels au LLM évaluateur pour maximiser l’efficacité — regroupez les évaluations de fidélité et envoyez-les en parallèle avec asyncio plutôt que séquentiellement. Consignez la progression, car le calcul des métriques de génération peut prendre plusieurs minutes pour plus de 100 cas de test.
def _compute_metrics(self):
# Retrieval metrics (no LLM calls needed)
hit_rates = []
mrr_scores = []
for r in self.results:
retrieved = r['retrieved_chunk_ids']
relevant = set(r['relevant_chunk_ids'])
hit = any(rid in relevant for rid in retrieved)
hit_rates.append(1.0 if hit else 0.0)
for rank, rid in enumerate(retrieved, 1):
if rid in relevant:
mrr_scores.append(1.0 / rank)
break
else:
mrr_scores.append(0.0)
metrics = {
'hit_rate_at_5': sum(hit_rates) / len(hit_rates),
'mrr': sum(mrr_scores) / len(mrr_scores),
'mean_latency_ms': sum(r['latency_ms'] for r in self.results) / len(self.results),
'mean_tokens': sum(r['tokens_used'] for r in self.results) / len(self.results)
}
return metricsEnregistrer les résultats avec les informations de version
Chaque exécution d’évaluation doit être enregistrée avec des métadonnées de version afin que vous puissiez comparer les résultats entre les configurations. Incluez le hachage de validation git du code, les paramètres de configuration (modèle de plongements, taille des segments, K, seuil, modèle de LLM), l’horodatage et une description lisible de l’exécution. Stockez les résultats dans un fichier JSONL ou dans une table de base de données. Vous conserverez ainsi un historique permanent de l’évolution de votre système.
import json
import subprocess
from datetime import datetime
def _save_report(self, metrics):
git_hash = subprocess.check_output(
['git', 'rev-parse', '--short', 'HEAD']
).decode().strip()
report = {
'run_id': datetime.utcnow().strftime('%Y%m%d_%H%M%S'),
'git_commit': git_hash,
'config': self.config,
'metrics': metrics,
'n_test_cases': len(self.results),
'timestamp': datetime.utcnow().isoformat()
}
with open('eval_history.jsonl', 'a') as f:
f.write(json.dumps(report) + '\n')
print(f'Saved evaluation run: {report["run_id"]}')
print(json.dumps(metrics, indent=2))Comparer à la référence
Après chaque exécution, comparez automatiquement les résultats à la référence précédente et signalez les régressions. Une régression correspond à toute métrique qui diminue de plus d’un seuil donné (par exemple, 2 points de pourcentage). Affichez un tableau de comparaison présentant l’évolution des métriques. Si une métrique régresse de manière importante, l’exécution d’évaluation doit échouer avec un code de sortie différent de zéro, ce qui amènera le pipeline CI/CD à bloquer le déploiement de cette modification.
def compare_to_baseline(current_metrics, baseline_file='best_eval.json'):
import json
from pathlib import Path
if not Path(baseline_file).exists():
print('No baseline yet. Saving current as baseline.')
Path(baseline_file).write_text(json.dumps(current_metrics, indent=2))
return True
baseline = json.loads(Path(baseline_file).read_text())
regressions = []
print('\nMetric comparison (current vs baseline):')
for metric, current_val in current_metrics.items():
baseline_val = baseline.get(metric, 0)
delta = current_val - baseline_val
status = 'OK' if delta >= -0.02 else 'REGRESSION'
print(f' {metric}: {current_val:.3f} vs {baseline_val:.3f} ({delta:+.3f}) {status}')
if status == 'REGRESSION':
regressions.append(metric)
return len(regressions) == 0Intégrer à CI/CD
Le dispositif d’évaluation est particulièrement puissant lorsqu’il est intégré à votre pipeline CI/CD. Configurez-le pour qu’il s’exécute automatiquement à chaque demande de fusion qui modifie la logique de découpage, la configuration du modèle de plongements, les modèles de prompt ou les paramètres de récupération. Le pipeline ne réussit que si toutes les métriques atteignent les seuils minimaux et qu’aucune métrique ne régresse par rapport à la référence de la branche principale. Cela empêche la mise en production de régressions accidentelles de la qualité.
# GitHub Actions workflow (eval.yml)
# on:
# pull_request:
# paths:
# - 'rag/**'
# - 'prompts/**'
# - 'config/**'
# jobs:
# evaluate:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v3
# - name: Install dependencies
# run: pip install -r requirements.txt
# - name: Run evaluation harness
# run: |
# python eval/run_harness.py \
# --test-set eval/golden_dataset.json \
# --config config/rag_config.yaml \
# --fail-on-regression
# env:
# OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}Générer des rapports lisibles par l’être humain
En plus des fichiers de métriques brutes, générez un rapport HTML ou textuel lisible par l’être humain que votre équipe pourra examiner dans les commentaires des demandes de fusion. Incluez un tableau récapitulatif de toutes les métriques, une liste des cas de test échoués avec la question, la réponse attendue, la réponse générée et les segments récupérés, ainsi qu’un graphique de tendance montrant les métriques des 10 dernières exécutions. Les rapports visuels aident les parties prenantes non techniques à comprendre si le système s’améliore.
def generate_markdown_report(metrics, failed_cases, run_id):
lines = [
f'# RAG Evaluation Report — {run_id}\n',
'## Summary Metrics',
'| Metric | Score | Target |',
'|--------|-------|--------|',
f'| Hit Rate@5 | {metrics["hit_rate_at_5"]:.1%} | > 80% |',
f'| MRR | {metrics["mrr"]:.3f} | > 0.70 |',
f'| Mean Latency | {metrics["mean_latency_ms"]:.0f}ms | < 500ms |',
'',
f'## Failed Cases ({len(failed_cases)} failures)'
]
for case in failed_cases[:10]: # show first 10
lines += [
f'**Q:** {case["question"]}',
f'**Expected:** {case["expected_answer"]}',
f'**Generated:** {case["generated_answer"]}\n'
]
return '\n'.join(lines)Suivre le coût de chaque exécution d’évaluation
Les exécutions d’évaluation ont un coût : elles appellent l’API de plongements, l’API du LLM et le LLM évaluateur. Suivez le coût de chaque exécution d’évaluation en parallèle des métriques de qualité. Une évaluation complète de 100 cas de test coûte généralement de 0,50 $ à 2,00 $, selon les modèles utilisés. Utilisez des modèles moins coûteux pour les appels d’évaluation (GPT-4o-mini pour évaluer la fidélité) et réservez les modèles coûteux à la génération. Incluez l’estimation du coût de l’exécution dans le rapport enregistré afin de pouvoir intégrer le coût des évaluations à votre cycle de développement.
def estimate_run_cost(results, config):
# Embedding cost
embed_tokens = sum(len(r['question'].split()) * 1.3 for r in results)
embed_cost = (embed_tokens / 1_000_000) * 0.02 # $0.02/1M tokens
# Generation cost
total_gen_tokens = sum(r['tokens_used'] for r in results)
gen_cost = (total_gen_tokens / 1_000_000) * 5.0 # gpt-4o approx
# Judge cost (faithfulness evals)
judge_cost = len(results) * 0.001 # ~$0.001 per eval with gpt-4o-mini
total = embed_cost + gen_cost + judge_cost
print(f'Evaluation cost estimate: ${total:.2f}')
print(f' Embedding: ${embed_cost:.3f}')
print(f' Generation: ${gen_cost:.3f}')
print(f' Judgment: ${judge_cost:.3f}')
return totalÉvaluation planifiée pour surveiller la production
Au-delà de l’évaluation CI/CD déclenchée par les modifications du code, exécutez le dispositif selon un planning en production — quotidien ou hebdomadaire — en effectuant des tests sur de vraies requêtes d’utilisateurs échantillonnées dans vos journaux. Cela permet de détecter la dérive des données : à mesure que le corpus documentaire évolue et que les habitudes de requête des utilisateurs changent, la qualité du système peut se dégrader sans aucune modification du code. Planifiez des évaluations hebdomadaires qui échantillonnent 50 requêtes récentes d’utilisateurs, les évaluent et envoient automatiquement un récapitulatif de la qualité au canal de discussion de votre équipe.
# Example scheduled evaluation (cron job or scheduled cloud function)
import random
def sample_production_queries(query_log_file, n=50):
with open(query_log_file) as f:
all_queries = [json.loads(line) for line in f]
sample = random.sample(all_queries, min(n, len(all_queries)))
# Convert to golden dataset format (without expected answers — use LLM judge)
return [
{'question': q['user_question'], 'relevant_chunk_ids': []}
for q in sample
]
# Run weekly evaluation against production queries
if __name__ == '__main__':
prod_queries = sample_production_queries('/var/log/rag_queries.jsonl')
harness = RAGEvaluationHarness(retriever, llm_client, config)
metrics = harness.run(prod_queries)
send_slack_digest(metrics)Visualiser l’évolution des métriques au fil du temps
Les nombres bruts dans un fichier JSONL sont difficiles à interpréter en un coup d’œil. Créez une visualisation simple des tendances qui représente chaque métrique sur les 20 dernières exécutions d’évaluation dans un graphique linéaire. Utilisez l’horodatage de l’exécution comme axe des abscisses et le score de la métrique comme axe des ordonnées. Tracez une ligne horizontale au niveau du seuil minimal acceptable. Lorsqu’une métrique passe sous cette ligne, le problème devient immédiatement visible, sans avoir à parcourir les données brutes. Des outils de visualisation comme une bibliothèque de graphiques ou un tableau de bord web simple conviennent très bien.
import json
import matplotlib.pyplot as plt
from pathlib import Path
def plot_metric_trends(history_file='eval_history.jsonl', metric='hit_rate_at_5'):
records = [
json.loads(line)
for line in Path(history_file).read_text().strip().split('\n')
]
timestamps = [r['timestamp'][:10] for r in records[-20:]]
scores = [r['metrics'].get(metric, 0) for r in records[-20:]]
plt.figure(figsize=(10, 4))
plt.plot(timestamps, scores, marker='o', label=metric)
plt.axhline(y=0.80, color='r', linestyle='--', label='Min threshold')
plt.title(f'{metric} over last 20 evaluations')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig(f'eval_trend_{metric}.png')
print(f'Saved trend chart for {metric}')Vérification rapide
Vérifiez 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 à structurer un dispositif d’évaluation complet avec la gestion des données de test, l’exécution du pipeline, le calcul des métriques et la génération de rapports ; à comparer les exécutions à une référence et à faire échouer CI/CD en cas de régression ; à générer des rapports lisibles par l’être humain pour l’examen par l’équipe ; et à planifier la surveillance de la production afin de détecter la dérive des données sans modifier le code. Vous disposez maintenant d’une base complète pour créer et évaluer des systèmes RAG en production.
Apprends Python avec un tuteur IA — gratuit
Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.
- Cours
- 30
- Leçons
- 120
Questions Fréquemment Posées
La leçon « Construire un banc d’évaluation automatisé » est-elle gratuite ?
Oui — le texte complet de « Construire un banc d’évaluation automatisé » 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 « Construire un banc d’évaluation automatisé » ?
Créez un pipeline d’évaluation reproductible qui exécute votre système RAG complet sur un jeu de test, calcule toutes les mesures et génère un rapport afin de suivre les progrès au fil du temps. 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 4 sur 4.
Combien de temps prend la leçon « Construire un banc d’évaluation automatisé » ?
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
- Pourquoi l’évaluation est importante dans RAG
- Mesures de récupération : taux de réussite, MRR et NDCG
- Mesures de génération : fidélité et pertinence des réponses
- Construire un banc d’évaluation automatisé