RAGAS : Open-Source-Framework zur Evaluierung von RAG
Beherrschen Sie RAGAS, um Ihre RAG-Systeme automatisch zu bewerten. Installation, Metriken, synthetische Datensätze und CI/CD-Integration.
RAGAS : Open-Source RAG-Bewertungsframework
RAGAS (Retrieval Augmented Generation Assessment) ist zum De-facto-Standard geworden, um RAG-Systeme zu bewerten. Dieses Open-Source-Framework bietet automatisierte Metriken, die die Qualität von retrieval und der Generierung messen, ohne ein vollständiges Ground Truth zu benötigen. Dieser Leitfaden führt Sie von der Installation bis zur Integration in die Produktion.
Warum RAGAS?
Manuelle Evaluation von RAG-Systemen ist zeitaufwändig und nicht reproduzierbar. RAGAS löst dieses Problem mit automatisch berechenbaren Metriken:
| Ansatz | Zeit/100 Samples | Reproduzierbarkeit | Kosten |
|---|---|---|---|
| Menschliche Bewertung | 4-8 Stunden | Gering | Hoch |
| Manuelle Tests | 1-2 Stunden | Mittel | Mittel |
| Automatisiertes RAGAS | 5-15 Minuten | Perfekt | Gering |
Vorteile von RAGAS
- Open-source : Code auditierbar, kein Vendor Lock-in
- LLM-as-judge : Nutzt ein LLM, um Antworten zu bewerten
- Ohne Ground Truth : Einige Metriken benötigen keine Referenz
- CI/CD-integrierbar : Vollständige Automatisierung der Bewertungen
- Granulare Metriken : Identifiziert gezielt Schwachstellen
Installation und Konfiguration
Grundlegendes Setup
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 # Konfiguration des Evaluator-LLM os.environ["OPENAI_API_KEY"] = "sk-..." # LLM für die Evaluierung (gpt-4 für Präzision empfohlen) llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
Erweiterte Konfiguration
DEVELOPERpythonfrom ragas.llms import LangchainLLMWrapper from ragas.embeddings import LangchainEmbeddingsWrapper # Wrapper, um andere LLMs zu verwenden 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): """Konfiguriert die Metriken mit dem benutzerdefinierten LLM""" metrics = [faithfulness, answer_relevancy, context_recall] for metric in metrics: metric.llm = self.llm if hasattr(metric, 'embeddings'): metric.embeddings = self.embeddings return metrics
Die RAGAS-Metriken im Detail
1. Faithfulness (Faktentreue)
Misst, ob die generierte Antwort dem bereitgestellten Kontext treu bleibt, ohne Halluzinationen.
DEVELOPERpythonfrom ragas.metrics import faithfulness from datasets import Dataset # Evaluierungsdaten eval_data = { "question": ["Wie lautet die Rückgabepolitik?"], "answer": ["Sie haben 30 Tage Zeit, um ein ungenutztes Produkt zurückzugeben."], "contexts": [["Unsere Rückgabepolitik erlaubt die Rückgabe jedes ungeöffneten Produkts innerhalb von 30 Tagen."]] } dataset = Dataset.from_dict(eval_data) # Faktentreue bewerten result = evaluate(dataset, metrics=[faithfulness]) print(f"Faithfulness: {result['faithfulness']:.3f}")
Interne Funktionsweise :
- Extrahiert die Aussagen aus der Antwort
- Prüft jede Aussage gegen den Kontext
- Score = gestützte Aussagen / Gesamtzahl der Aussagen
| Score | Interpretation | Aktion |
|---|---|---|
| > 0,9 | Exzellent | Beibehalten |
| 0,7-0,9 | Akzeptabel | Prompts verbessern |
| < 0,7 | Problematisch | Pipeline überprüfen |
2. Answer Relevancy (Relevanz)
Bewertet, ob die Antwort die gestellte Frage tatsächlich beantwortet.
DEVELOPERpythonfrom ragas.metrics import answer_relevancy eval_data = { "question": ["Wie setze ich mein Passwort zurück?"], "answer": ["Um Ihr Passwort zurückzusetzen, klicken Sie auf der Anmeldeseite auf 'Passwort vergessen', geben Sie Ihre E-Mail-Adresse ein und folgen Sie dem erhaltenen Link."], "contexts": [["Anmeldeleitfaden: Die Schaltfläche 'Passwort vergessen' sendet eine E-Mail zur Zurücksetzung."]] } dataset = Dataset.from_dict(eval_data) result = evaluate(dataset, metrics=[answer_relevancy]) print(f"Answer Relevancy: {result['answer_relevancy']:.3f}")
Interne Funktionsweise :
- Generiert Fragen ausgehend von der Antwort
- Vergleicht diese Fragen mit der ursprünglichen Frage (Kosinus-Ähnlichkeit)
- Score = durchschnittliche Ähnlichkeit der generierten Fragen
3. Context Recall
Misst, ob der abgerufene Kontext die zur Beantwortung notwendigen Informationen enthält.
DEVELOPERpythonfrom ragas.metrics import context_recall eval_data = { "question": ["Welche Zahlungsmethoden werden akzeptiert?"], "contexts": [["Wir akzeptieren Visa, Mastercard und PayPal. Ratenzahlung in 3 Raten ohne Gebühren ist verfügbar."]], "ground_truth": ["Die akzeptierten Zahlungsmethoden sind Visa, Mastercard, PayPal und die gebührenfreie 3-Raten-Zahlung."] } dataset = Dataset.from_dict(eval_data) result = evaluate(dataset, metrics=[context_recall]) print(f"Context Recall: {result['context_recall']:.3f}")
4. Context Precision
Bewertet, ob die relevanten Kontexte gut oben in den Ergebnissen platziert sind.
DEVELOPERpythonfrom ragas.metrics import context_precision eval_data = { "question": ["Wie lange dauert die Lieferung?"], "contexts": [[ "Standardversand: 3-5 Werktage. Express: 24 Stunden.", "Unser Kundenservice ist rund um die Uhr erreichbar.", "Kostenloser Versand ab 50 EUR." ]], "ground_truth": ["Standardversand in 3-5 Tagen, Express in 24 Stunden, kostenlos ab 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
Kombiniert semantische und faktische Ähnlichkeit für eine vollständige Bewertung.
DEVELOPERpythonfrom ragas.metrics import answer_correctness eval_data = { "question": ["Wie viel kostet das Premium-Abonnement?"], "answer": ["Das Premium-Abonnement kostet 29,99 EUR pro Monat."], "ground_truth": ["Das Premium-Abonnement kostet 29,99 EUR/Monat bei jährlicher Bindung."] } dataset = Dataset.from_dict(eval_data) result = evaluate(dataset, metrics=[answer_correctness]) print(f"Answer Correctness: {result['answer_correctness']:.3f}")
Erstellung eines Evaluierungsdatensatzes
Automatische Generierung mit 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 # Dokumente laden loader = DirectoryLoader("./documents/", glob="**/*.md") documents = loader.load() # In Chunks aufteilen splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200) chunks = splitter.split_documents(documents) # Testdatensatz generieren 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())
Struktur des generierten Datensatzes
| Spalte | Beschreibung | Beispiel |
|---|---|---|
| question | Generierte Frage | "Wie konfiguriere ich die API?" |
| contexts | Quell-Chunks | ["API-Doku: Zum Konfigurieren..."] |
| ground_truth | Erwartete Antwort | "Erstellen Sie einen API-Schlüssel in..." |
| evolution_type | Fragetyp | simple, reasoning, multi_context |
Vollständige Evaluierungspipeline
Produktionsreife Evaluierungsklasse
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)
CI/CD-Integration
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 und Debugging
Problematische Samples identifizieren
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 mit geringer Faktentreue: {len(analysis['low_faithfulness'])}")
Tracking-Dashboard
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
Best Practices
Evaluierungs-Checkliste
| Schritt | Aktion | Häufigkeit |
|---|---|---|
| Dataset | 100+ repräsentative Samples pflegen | Monatlich |
| Validierung | 10 % des Ground Truth erneut prüfen | Monatlich |
| Schwellenwerte | An die Domäne anpassen | Vierteljährlich |
| CI/CD | PRs unterhalb der Schwellenwerte blockieren | Bei jedem PR |
| Monitoring | Trends nachverfolgen | Wöchentlich |
Grenzen von RAGAS
- LLM-Kosten : Die Evaluierung nutzt LLM-Aufrufe
- Bias des Judges : Das evaluierende LLM kann eigene Verzerrungen haben
- Kein UX-Test : Misst nicht die tatsächliche Nutzerzufriedenheit
Weiterführende Informationen
- Menschliche Evaluierung - RAGAS durch menschliche Bewertung ergänzen
- RAG-Metriken - Überblick über die Metriken
- RAG-Generierung - Antworten verbessern
FAQ
Automatisierte Evaluierung mit Ailog
Die Implementierung von RAGAS erfordert Konfiguration und Wartung. Mit Ailog profitieren Sie von einer integrierten Evaluierung:
- Metriken-Dashboard in Echtzeit
- Alerts bei Qualitätsverschlechterung
- Verlauf der Evaluierungen
- Automatische Verbesserungsvorschläge
- Vorkonfigurierte CI/CD-Integration
Kostenlos testen und die Qualität Ihres RAG-Systems mühelos messen.
Tags
Verwandte Artikel
Menschliche Evaluation: Methodik und Werkzeuge
Ergänzen Sie die automatisierte Bewertung durch menschliche Expertise. Annotation protocols, inter-annotator agreement und Labeling-Tools für RAG.
LLM-Routing: Die geheime Architektur die KI-Kosten um 60% senkt (ohne Qualitätsverlust)
Kompletter Leitfaden zum LLM-Routing für Kostenoptimierung: Komplexitätsbasiertes Routing, Kaskaden-Routing, Konsens-Routing. Vergleich von Martian, Unify, OpenRouter. Code und Architektur für einen eigenen Router.
Prompt Caching: Der Trick der Ihre LLM-Kosten durch 10 teilt (Anthropic, OpenAI, Google)
Kompletter Leitfaden zum Prompt Caching zur Reduzierung Ihrer LLM-Kosten: Funktionsweise des Prefix Matching, Strategien pro Anbieter (Anthropic, OpenAI, Google), Einsparungsberechnungen und RAG-Optimierung.