RAGAS : Framework d'évaluation RAG open-source
Maîtrisez RAGAS pour évaluer automatiquement vos systèmes RAG. Installation, métriques, datasets synthétiques et intégration CI/CD.
RAGAS : Framework d'évaluation RAG open-source
RAGAS (Retrieval Augmented Generation Assessment) est devenu le standard de facto pour évaluer les systèmes RAG. Ce framework open-source offre des métriques automatisées qui mesurent la qualité du retrieval et de la génération sans nécessiter de ground truth exhaustif. Ce guide vous accompagne de l'installation à l'intégration en production.
Pourquoi RAGAS ?
L'évaluation manuelle des systèmes RAG est chronophage et non reproductible. RAGAS résout ce problème avec des métriques calculables automatiquement :
| Approche | Temps/100 samples | Reproductibilité | Coût |
|---|---|---|---|
| Évaluation humaine | 4-8 heures | Faible | Élevé |
| Tests manuels | 1-2 heures | Moyenne | Moyen |
| RAGAS automatisé | 5-15 minutes | Parfaite | Faible |
Avantages de RAGAS
- Open-source : Code auditable, pas de vendor lock-in
- LLM-as-judge : Utilise un LLM pour évaluer les réponses
- Sans ground truth : Certaines métriques ne nécessitent pas de référence
- Intégrable CI/CD : Automatisation complète des évaluations
- Métriques granulaires : Identifie précisément les points faibles
Installation et configuration
Setup de base
DEVELOPERpython# Installation # pip install ragas langchain-openai datasets from ragas import evaluate from ragas.metrics import ( faithfulness, answer_relevancy, context_recall, context_precision, answer_correctness, answer_similarity ) from langchain_openai import ChatOpenAI, OpenAIEmbeddings import os # Configuration du LLM évaluateur os.environ["OPENAI_API_KEY"] = "sk-..." # LLM pour l'évaluation (gpt-4 recommandé pour la précision) llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
Configuration avancée
DEVELOPERpythonfrom ragas.llms import LangchainLLMWrapper from ragas.embeddings import LangchainEmbeddingsWrapper # Wrapper pour utiliser d'autres LLMs class CustomEvaluator: def __init__(self, llm_model: str = "gpt-4o-mini"): self.llm = LangchainLLMWrapper( ChatOpenAI(model=llm_model, temperature=0) ) self.embeddings = LangchainEmbeddingsWrapper( OpenAIEmbeddings(model="text-embedding-3-small") ) def configure_metrics(self): """Configure les métriques avec le LLM custom""" metrics = [faithfulness, answer_relevancy, context_recall] for metric in metrics: metric.llm = self.llm if hasattr(metric, 'embeddings'): metric.embeddings = self.embeddings return metrics
Les métriques RAGAS en détail
1. Faithfulness (Fidélité)
Mesure si la réponse générée est fidèle au contexte fourni, sans hallucination.
DEVELOPERpythonfrom ragas.metrics import faithfulness from datasets import Dataset # Données d'évaluation eval_data = { "question": ["Quelle est la politique de retour ?"], "answer": ["Vous avez 30 jours pour retourner un produit non utilisé."], "contexts": [["Notre politique de retour permet le retour de tout produit non ouvert dans un délai de 30 jours."]] } dataset = Dataset.from_dict(eval_data) # Évaluer la fidélité result = evaluate(dataset, metrics=[faithfulness]) print(f"Faithfulness: {result['faithfulness']:.3f}")
Fonctionnement interne :
- Extrait les affirmations de la réponse
- Vérifie chaque affirmation contre le contexte
- Score = affirmations supportées / total affirmations
| Score | Interprétation | Action |
|---|---|---|
| > 0.9 | Excellent | Maintenir |
| 0.7-0.9 | Acceptable | Améliorer prompts |
| < 0.7 | Problématique | Revoir le pipeline |
2. Answer Relevancy (Pertinence)
Évalue si la réponse répond effectivement à la question posée.
DEVELOPERpythonfrom ragas.metrics import answer_relevancy eval_data = { "question": ["Comment réinitialiser mon mot de passe ?"], "answer": ["Pour réinitialiser votre mot de passe, cliquez sur 'Mot de passe oublié' sur la page de connexion, entrez votre email, et suivez le lien reçu."], "contexts": [["Guide de connexion : Le bouton 'Mot de passe oublié' envoie un email de réinitialisation."]] } dataset = Dataset.from_dict(eval_data) result = evaluate(dataset, metrics=[answer_relevancy]) print(f"Answer Relevancy: {result['answer_relevancy']:.3f}")
Fonctionnement interne :
- Génère des questions à partir de la réponse
- Compare ces questions avec la question originale (similarité cosinus)
- Score = similarité moyenne des questions générées
3. Context Recall
Mesure si le contexte récupéré contient les informations nécessaires pour répondre.
DEVELOPERpythonfrom ragas.metrics import context_recall eval_data = { "question": ["Quels sont les moyens de paiement acceptés ?"], "contexts": [["Nous acceptons Visa, Mastercard et PayPal. Le paiement en 3x sans frais est disponible."]], "ground_truth": ["Les moyens de paiement acceptés sont Visa, Mastercard, PayPal, et le paiement en 3x sans frais."] } dataset = Dataset.from_dict(eval_data) result = evaluate(dataset, metrics=[context_recall]) print(f"Context Recall: {result['context_recall']:.3f}")
4. Context Precision
Évalue si les contextes pertinents sont bien classés en haut des résultats.
DEVELOPERpythonfrom ragas.metrics import context_precision eval_data = { "question": ["Quels sont les délais de livraison ?"], "contexts": [[ "Livraison standard : 3-5 jours ouvrés. Express : 24h.", "Notre service client est disponible 24/7.", "Livraison gratuite à partir de 50 EUR." ]], "ground_truth": ["Livraison standard en 3-5 jours, express en 24h, gratuite dès 50 EUR."] } dataset = Dataset.from_dict(eval_data) result = evaluate(dataset, metrics=[context_precision]) print(f"Context Precision: {result['context_precision']:.3f}")
5. Answer Correctness
Combine similarité sémantique et factuelle pour une évaluation complète.
DEVELOPERpythonfrom ragas.metrics import answer_correctness eval_data = { "question": ["Quel est le prix de l'abonnement Premium ?"], "answer": ["L'abonnement Premium coûte 29,99 EUR par mois."], "ground_truth": ["L'abonnement Premium est à 29,99 EUR/mois avec engagement annuel."] } dataset = Dataset.from_dict(eval_data) result = evaluate(dataset, metrics=[answer_correctness]) print(f"Answer Correctness: {result['answer_correctness']:.3f}")
Création d'un dataset d'évaluation
Génération automatique avec RAGAS
DEVELOPERpythonfrom ragas.testset.generator import TestsetGenerator from ragas.testset.evolutions import simple, reasoning, multi_context from langchain_community.document_loaders import DirectoryLoader from langchain.text_splitter import RecursiveCharacterTextSplitter # Charger les documents loader = DirectoryLoader("./documents/", glob="**/*.md") documents = loader.load() # Découper en chunks splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200) chunks = splitter.split_documents(documents) # Générer le dataset de test generator = TestsetGenerator.from_langchain( generator_llm=ChatOpenAI(model="gpt-4o-mini"), critic_llm=ChatOpenAI(model="gpt-4o-mini"), embeddings=OpenAIEmbeddings() ) testset = generator.generate_with_langchain_docs( documents=chunks, test_size=50, distributions={ simple: 0.5, reasoning: 0.25, multi_context: 0.25 } ) testset_df = testset.to_pandas() print(testset_df.head())
Structure du dataset généré
| Colonne | Description | Exemple |
|---|---|---|
| question | Question générée | "Comment configurer l'API ?" |
| contexts | Chunks sources | ["Doc API: Pour configurer..."] |
| ground_truth | Réponse attendue | "Créez une clé API dans..." |
| evolution_type | Type de question | simple, reasoning, multi_context |
Pipeline d'évaluation complet
Classe d'évaluation production-ready
DEVELOPERpythonfrom dataclasses import dataclass from datetime import datetime import json @dataclass class EvalConfig: metrics: list llm_model: str = "gpt-4o-mini" batch_size: int = 10 save_results: bool = True output_dir: str = "./eval_results" class RAGASEvaluator: def __init__(self, config: EvalConfig): self.config = config self.llm = ChatOpenAI(model=config.llm_model, temperature=0) self.embeddings = OpenAIEmbeddings() self._configure_metrics() def _configure_metrics(self): for metric in self.config.metrics: metric.llm = LangchainLLMWrapper(self.llm) if hasattr(metric, 'embeddings'): metric.embeddings = LangchainEmbeddingsWrapper(self.embeddings) async def evaluate_rag_system( self, rag_system, eval_dataset: Dataset, version: str = None ) -> dict: questions = eval_dataset["question"] ground_truths = eval_dataset["ground_truth"] answers = [] contexts = [] for question in questions: result = await rag_system.query(question) answers.append(result["answer"]) contexts.append(result["contexts"]) eval_data = { "question": questions, "answer": answers, "contexts": contexts, "ground_truth": ground_truths } dataset = Dataset.from_dict(eval_data) results = evaluate( dataset, metrics=self.config.metrics, llm=self.llm, embeddings=self.embeddings ) output = { "version": version or datetime.now().isoformat(), "timestamp": datetime.now().isoformat(), "sample_count": len(questions), "metrics": { metric.name: float(results[metric.name]) for metric in self.config.metrics }, "per_sample": results.to_pandas().to_dict(orient="records") } if self.config.save_results: self._save_results(output) return output def _save_results(self, results: dict): import os os.makedirs(self.config.output_dir, exist_ok=True) filename = f"eval_{results['version']}.json" filepath = os.path.join(self.config.output_dir, filename) with open(filepath, 'w') as f: json.dump(results, f, indent=2, default=str)
Intégration CI/CD
GitHub Actions
DEVELOPERyamlname: RAG Evaluation on: pull_request: paths: - 'rag/**' - 'prompts/**' schedule: - cron: '0 6 * * 1' jobs: evaluate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.11' - name: Install dependencies run: pip install ragas langchain-openai datasets - name: Run RAGAS evaluation env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} run: python scripts/run_ragas_eval.py - name: Check thresholds run: | python -c " import json with open('eval_results/latest.json') as f: results = json.load(f) thresholds = {'faithfulness': 0.8, 'answer_relevancy': 0.75} for metric, threshold in thresholds.items(): if results['metrics'].get(metric, 0) < threshold: exit(1) "
Analyse et debugging
Identifier les samples problématiques
DEVELOPERpythonimport pandas as pd def analyze_failures(results_df: pd.DataFrame, threshold: float = 0.7) -> dict: analysis = {"low_faithfulness": [], "low_relevancy": [], "patterns": {}} low_faith = results_df[results_df["faithfulness"] < threshold] for _, row in low_faith.iterrows(): analysis["low_faithfulness"].append({ "question": row["question"], "answer": row["answer"], "score": row["faithfulness"] }) low_rel = results_df[results_df["answer_relevancy"] < threshold] for _, row in low_rel.iterrows(): analysis["low_relevancy"].append({ "question": row["question"], "score": row["answer_relevancy"] }) return analysis results_df = pd.DataFrame(results["per_sample"]) analysis = analyze_failures(results_df) print(f"Samples avec faible fidélité: {len(analysis['low_faithfulness'])}")
Dashboard de suivi
DEVELOPERpythonclass EvalDashboard: def __init__(self, results_dir: str = "./eval_results"): self.results_dir = Path(results_dir) def load_history(self) -> pd.DataFrame: records = [] for file in self.results_dir.glob("eval_*.json"): with open(file) as f: data = json.load(f) records.append({ "version": data["version"], "timestamp": data["timestamp"], **data["metrics"] }) return pd.DataFrame(records).sort_values("timestamp") def generate_report(self) -> str: df = self.load_history() latest = df.iloc[-1] report = f"# RAG Evaluation Report\n\n## Version: {latest['version']}\n\n" for metric in ["faithfulness", "answer_relevancy", "context_recall"]: report += f"| {metric} | {latest[metric]:.3f} |\n" return report
Bonnes pratiques
Checklist d'évaluation
| Étape | Action | Fréquence |
|---|---|---|
| Dataset | Maintenir 100+ samples représentatifs | Mensuelle |
| Validation | Relire 10% du ground truth | Mensuelle |
| Thresholds | Ajuster selon le domaine | Trimestrielle |
| CI/CD | Bloquer les PR sous les seuils | Chaque PR |
| Monitoring | Tracker les tendances | Hebdomadaire |
Limitations de RAGAS
- Coût LLM : L'évaluation utilise des appels LLM
- Biais du juge : Le LLM évaluateur peut avoir ses propres biais
- Pas de test UX : Ne mesure pas la satisfaction utilisateur réelle
Pour aller plus loin
- Évaluation humaine - Compléter RAGAS par l'humain
- Métriques RAG - Vue d'ensemble des métriques
- Génération RAG - Améliorer les réponses
FAQ
Évaluation automatisée avec Ailog
Implémenter RAGAS demande configuration et maintenance. Avec Ailog, bénéficiez d'une évaluation intégrée :
- Dashboard métriques temps réel
- Alertes sur dégradation de qualité
- Historique des évaluations
- Suggestions d'amélioration automatiques
- Intégration CI/CD préconfigurée
Testez gratuitement et mesurez la qualité de votre RAG sans effort.
Tags
Articles connexes
Évaluer un système RAG : Métriques et méthodologies
Guide complet pour mesurer la performance de votre RAG : faithfulness, relevancy, recall, et frameworks d'évaluation automatisée.
Réduire la Latence RAG : De 2000ms à 200ms
RAG 10x Plus Rapide : Récupération Parallèle, Réponses en Streaming et Optimisations Architecturales pour une Latence Inférieure à 200ms.
Stratégies de Mise en Cache pour Réduire la Latence et le Coût RAG
Réduisez les Coûts de 80% : Implémentez la Mise en Cache Sémantique, la Mise en Cache d'Embeddings et la Mise en Cache de Réponses pour un RAG Production.