RAG Evaluation: Metriken und Testing für KI-Systeme

Foto von CHUTTERSNAP auf Unsplash
Du hast ein RAG-System gebaut, die ersten Antworten sehen vielversprechend aus, aber wie weißt du, ob es wirklich gut funktioniert? "Sieht gut aus" reicht nicht, wenn dein System in Produktion Kundenanfragen beantwortet oder medizinische Fachinformationen liefert.
In meiner Arbeit mit RAG-Systemen in Produktion habe ich gelernt: Ohne systematische Evaluation fliegst du blind. Dieser Artikel zeigt dir, wie du RAG-Systeme mit bewährten Frameworks und Metriken testest, von der ersten Evaluation bis zur CI/CD-Integration.
Warum RAG-Evaluation anders ist
Klassische Softwaretests prüfen deterministische Ausgaben: assert calculate_tax(100) == 19. Bei RAG-Systemen ist das fundamental anders:
- Nicht-deterministische Ausgaben: Das gleiche Query kann verschiedene, aber gleich korrekte Antworten liefern
- Zwei Fehlerquellen: Probleme können im Retrieval oder in der Generation liegen
- Semantische Korrektheit: "Berlin ist die Hauptstadt" und "Die Hauptstadt Deutschlands ist Berlin" sind beide korrekt. Ein String-Vergleich versagt hier
Das RAG-Triad
TruLens hat ein elegantes Modell für RAG-Qualität entwickelt: das RAG-Triad. Es prüft drei Dimensionen, die zusammen alle Fehlerquellen abdecken:
| Dimension | Prüft | Fehlerfall |
|---|---|---|
| Context Relevance | Sind die abgerufenen Chunks relevant zur Frage? | Irrelevanter Kontext → Halluzinations-Risiko |
| Groundedness | Basiert die Antwort auf dem abgerufenen Kontext? | Erfundene Fakten, nicht durch Quellen belegt |
| Answer Relevance | Beantwortet die Antwort tatsächlich die Frage? | Korrekte Info, aber am Thema vorbei |
Wenn alle drei Dimensionen positiv ausfallen, ist dein RAG-System nachweislich frei von Halluzinationen, bis an die Grenzen deiner Wissensbasis.
Die vier Kernmetriken
Die Open-Source-Frameworks RAGAS und DeepEval haben sich als Standard etabliert. Beide arbeiten mit vier Kernmetriken:
Faithfulness (Treue)
Was wird gemessen? Wie faktengetreu ist die generierte Antwort im Vergleich zum abgerufenen Kontext?
Wie funktioniert es?
- Die Antwort wird in einzelne Aussagen zerlegt
- Jede Aussage wird gegen den Kontext geprüft (NLI-basiert)
- Der Score ist das Verhältnis belegter zu gesamten Aussagen
Faithfulness = Belegte Aussagen / Gesamte Aussagen
Beispiel:
- Kontext: "Einstein wurde am 14. März 1879 in Deutschland geboren"
- Antwort A: "Einstein wurde am 14. März 1879 in Deutschland geboren" → 1.0 (alle Aussagen belegt)
- Antwort B: "Einstein wurde am 20. März 1879 in Deutschland geboren" → 0.5 (Datum nicht belegt)
Answer Relevancy (Antwortrelevanz)
Was wird gemessen? Wie relevant ist die Antwort in Bezug auf die gestellte Frage?
Eine hohe Faithfulness allein reicht nicht. Die Antwort muss auch die eigentliche Frage adressieren. Ein System könnte faktengetreue, aber völlig irrelevante Informationen liefern.
Beispiel:
- Frage: "Was passiert wenn die Schuhe nicht passen?"
- Antwort A: "Wir bieten 30 Tage Rückgaberecht ohne Zusatzkosten." → Hohe Relevanz
- Antwort B: "Unsere Schuhe gibt es in Größen 36-48." → Niedrige Relevanz (beantwortet nicht die Frage)
Context Precision (Kontext-Präzision)
Was wird gemessen? Sind relevante Chunks höher gerankt als irrelevante?
Diese Metrik bewertet die Qualität deines Retrievers und Rerankers. Ein irrelevanter Chunk auf Platz 1 reduziert die Precision auf ~0.5, während er auf Platz 2 kaum schadet.
Context Precision@K = Σ(Precision@k × v_k) / Relevante Items in Top-K
Context Recall (Kontext-Abdeckung)
Was wird gemessen? Wurden alle relevanten Informationen abgerufen?
Context Recall vergleicht die Fakten in der erwarteten Antwort (Ground Truth) mit den abgerufenen Chunks. Benötigt eine Referenzantwort.
| Metrik | Evaluiert | Braucht Ground Truth |
|---|---|---|
| Faithfulness | Generation | Nein |
| Answer Relevancy | Generation | Nein |
| Context Precision | Retrieval | Ja |
| Context Recall | Retrieval | Ja |
RAGAS in der Praxis
RAGAS (Retrieval Augmented Generation Assessment Score) ist das meistgenutzte Open-Source-Framework für RAG-Evaluation. Installation:
pip install ragas langchain-openai langchain-communityErstes Evaluation-Beispiel
from ragas import EvaluationDataset, SingleTurnSample, evaluate
from ragas.metrics import (
Faithfulness,
AnswerRelevancy,
ContextPrecision,
ContextRecall,
)
from ragas.llms import LangchainLLMWrapper
from ragas.embeddings import LangchainEmbeddingsWrapper
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
# Evaluator-LLM und Embeddings konfigurieren
evaluator_llm = LangchainLLMWrapper(
ChatOpenAI(model="gpt-4o-mini", temperature=0)
)
evaluator_embeddings = LangchainEmbeddingsWrapper(
OpenAIEmbeddings(model="text-embedding-3-small")
)
# Testdaten erstellen
samples = [
SingleTurnSample(
user_input="Was ist Retrieval-Augmented Generation?",
retrieved_contexts=[
"RAG kombiniert Informationsabruf mit Textgenerierung. "
"Relevante Dokumente werden aus einer Wissensbasis abgerufen "
"und dem LLM als Kontext übergeben.",
"RAG wurde 2020 von Meta AI vorgestellt und hat sich "
"als Standard für wissensbasierte KI-Systeme etabliert.",
],
response=(
"RAG (Retrieval-Augmented Generation) ist eine Technik, "
"die Informationsabruf mit Textgenerierung kombiniert. "
"Dabei werden relevante Dokumente aus einer Wissensbasis "
"abgerufen und einem LLM als Kontext übergeben."
),
reference=(
"RAG kombiniert Dokumentenabruf mit LLM-Generierung, "
"um Antworten auf Basis externer Wissensquellen zu liefern."
),
),
]
dataset = EvaluationDataset(samples=samples)
# Evaluation durchführen
results = evaluate(
dataset=dataset,
metrics=[
Faithfulness(llm=evaluator_llm),
AnswerRelevancy(llm=evaluator_llm, embeddings=evaluator_embeddings),
ContextPrecision(llm=evaluator_llm),
ContextRecall(llm=evaluator_llm),
],
)
# Ergebnisse anzeigen
df = results.to_pandas()
print(df[[
"faithfulness",
"answer_relevancy",
"context_precision",
"context_recall",
]])Typische Ausgabe:
| faithfulness | answer_relevancy | context_precision | context_recall |
|---|---|---|---|
| 1.00 | 0.92 | 1.00 | 0.85 |
Ergebnisse interpretieren
| Score-Bereich | Bewertung | Handlung |
|---|---|---|
| 0.8 bis 1.0 | Gut | Monitoring beibehalten |
| 0.6 bis 0.8 | Akzeptabel | Optimierung empfohlen |
| < 0.6 | Kritisch | Sofortiger Handlungsbedarf |
Niedrige Faithfulness? → Dein LLM halluziniert. Prüfe die Prompt-Vorlage, reduziere die Temperatur, setze Guardrails ein.
Niedrige Context Precision? → Dein Retriever liefert irrelevante Chunks. Verbessere die Embedding-Qualität oder füge einen Reranker hinzu.
Niedrige Context Recall? → Relevante Informationen werden nicht gefunden. Prüfe deine Chunking-Strategie und Embedding-Abdeckung.
Synthetische Testdaten generieren
Manuell Hunderte Test-Fragen zu schreiben ist aufwändig. RAGAS kann synthetische Testdaten direkt aus deinen Dokumenten generieren:
from langchain_community.document_loaders import DirectoryLoader
from ragas.testset import TestsetGenerator
from ragas.llms import LangchainLLMWrapper
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from ragas.embeddings import LangchainEmbeddingsWrapper
# Dokumente laden
loader = DirectoryLoader("./knowledge_base/", glob="**/*.md")
docs = loader.load()
# Generator konfigurieren
generator_llm = LangchainLLMWrapper(
ChatOpenAI(model="gpt-4o")
)
generator_embeddings = LangchainEmbeddingsWrapper(
OpenAIEmbeddings(model="text-embedding-3-small")
)
generator = TestsetGenerator(
llm=generator_llm,
embedding_model=generator_embeddings,
)
# Testset aus Dokumenten generieren
testset = generator.generate_with_langchain_docs(
documents=docs,
testset_size=50,
)
# Als CSV exportieren für Versionierung
df = testset.to_pandas()
df.to_csv("tests/golden_dataset.csv", index=False)
print(f"{len(df)} Testfragen generiert")Der Generator erstellt verschiedene Fragetypen: einfache Fakten-Fragen, Multi-Hop-Fragen (die mehrere Chunks erfordern) und Reasoning-Fragen. Das ergibt ein ausgewogenes Testset.
DeepEval: pytest für LLMs
Während RAGAS hervorragend für Ad-hoc-Evaluation geeignet ist, glänzt DeepEval bei der Integration in bestehende Test-Workflows. Es funktioniert wie pytest, nur für LLMs.
pip install deepevalTest-Cases definieren
# tests/test_rag_quality.py
import pytest
from deepeval import assert_test
from deepeval.test_case import LLMTestCase
from deepeval.metrics import (
AnswerRelevancyMetric,
FaithfulnessMetric,
ContextualPrecisionMetric,
)
# Metriken mit Schwellenwerten definieren
faithfulness = FaithfulnessMetric(threshold=0.8)
relevancy = AnswerRelevancyMetric(threshold=0.7)
precision = ContextualPrecisionMetric(threshold=0.65)
# Testdaten
TEST_CASES = [
{
"input": "Was ist der Unterschied zwischen RAG und Fine-Tuning?",
"expected": "RAG ruft externe Dokumente ab, Fine-Tuning passt Modellgewichte an.",
},
{
"input": "Welche Metriken gibt es für RAG-Evaluation?",
"expected": "Faithfulness, Answer Relevancy, Context Precision und Context Recall.",
},
]
def get_rag_response(query: str) -> tuple[str, list[str]]:
"""Dein RAG-System aufrufen."""
# Hier dein tatsächliches RAG-System einbinden
from your_rag_system import query_rag
result = query_rag(query)
return result["answer"], result["source_chunks"]
@pytest.mark.parametrize("test_data", TEST_CASES)
def test_rag_pipeline(test_data):
actual_output, retrieval_context = get_rag_response(test_data["input"])
test_case = LLMTestCase(
input=test_data["input"],
actual_output=actual_output,
retrieval_context=retrieval_context,
expected_output=test_data["expected"],
)
assert_test(test_case, [faithfulness, relevancy, precision])Ausführen mit:
deepeval test run tests/test_rag_quality.pyCI/CD-Integration
DeepEval integriert sich nahtlos in GitHub Actions:
# .github/workflows/rag-eval.yml
name: RAG Evaluation
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
evaluate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Python Setup
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install Dependencies
run: pip install deepeval -r requirements.txt
- name: RAG Evaluation
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: deepeval test run tests/test_rag_quality.pyJeder Push oder Pull Request löst automatisch die RAG-Evaluation aus. Wenn Metriken unter die definierten Schwellenwerte fallen, schlägt der Build fehl, genau wie bei fehlschlagenden Unit-Tests.
Golden Datasets aufbauen
Die Qualität deiner Evaluation steht und fällt mit deinen Testdaten. Ein Golden Dataset ist eine kuratierte, versionierte Sammlung von Fragen mit erwarteten Antworten und relevantem Kontext.
Drei-Stufen-Strategie
| Stufe | Quelle | Aufwand | Qualität |
|---|---|---|---|
| Silver | RAGAS TestsetGenerator | Niedrig | Mittel |
| Gold | Von Domänenexperten validiert | Mittel | Hoch |
| Production | Echte Nutzeranfragen annotiert | Hoch | Sehr hoch |
Empfehlung: Starte mit 50 Silver-Datensätzen, lass sie von einem Domänenexperten validieren, und ergänze laufend mit echten Produktionsanfragen.
Struktur und Versionierung
[
{
"query": "Was ist der Unterschied zwischen RAG und Fine-Tuning?",
"ground_truth": "RAG ruft externe Dokumente ab und nutzt sie als Kontext. Fine-Tuning passt die Modellgewichte an.",
"relevant_doc_ids": ["doc_042", "doc_117"],
"question_type": "comparison",
"difficulty": "medium",
"annotator": "domain_expert_1",
"annotation_date": "2026-02-15"
}
]Versioniere das Golden Dataset zusammen mit deinem Code im Git-Repository. So ist bei jedem Commit nachvollziehbar, welche Testdaten verwendet wurden.
LLM-as-a-Judge
Warum nicht einfach BLEU oder ROUGE verwenden? Diese Token-Overlap-Metriken korrelieren schlecht mit menschlicher Bewertung. LLM-basierte Evaluation erreicht 15 bis 20% höhere Korrelation, weil sie semantische Äquivalenz versteht.
Custom Evaluatoren
Manchmal reichen die Standard-Metriken nicht aus. Für domänenspezifische Anforderungen kannst du eigene Evaluatoren bauen:
import json
from openai import AsyncOpenAI
client = AsyncOpenAI()
JUDGE_PROMPT = """Du bist ein Evaluierungsexperte für RAG-Systeme.
Bewerte die folgende Antwort auf einer Skala von 1-5.
Frage: {query}
Kontext: {context}
Antwort: {response}
Kriterien:
- Treue: Ist die Antwort durch den Kontext belegt?
- Relevanz: Beantwortet die Antwort die Frage?
- Vollständigkeit: Sind alle relevanten Informationen enthalten?
Antworte in JSON-Format:
{{"treue": <1-5>, "relevanz": <1-5>, "vollstaendigkeit": <1-5>, "begruendung": "<Text>"}}"""
async def llm_judge(query: str, context: str, response: str) -> dict:
result = await client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": JUDGE_PROMPT.format(
query=query, context=context, response=response
),
}],
response_format={"type": "json_object"},
temperature=0,
)
scores = json.loads(result.choices[0].message.content)
return {
"treue": scores["treue"] / 5.0,
"relevanz": scores["relevanz"] / 5.0,
"vollstaendigkeit": scores["vollstaendigkeit"] / 5.0,
"begruendung": scores["begruendung"],
}Dieser Custom Judge bewertet auf Deutsch, mit domänenspezifischen Kriterien und liefert eine nachvollziehbare Begründung.
RAG-Testing in der CI/CD-Pipeline
Eine produktionsreife Evaluation-Pipeline kombiniert alle bisherigen Bausteine:
# tests/conftest.py
import pytest
from deepeval.metrics import (
FaithfulnessMetric,
AnswerRelevancyMetric,
ContextualPrecisionMetric,
)
# Quality Gates: Pipeline schlägt fehl wenn unterschritten
THRESHOLDS = {
"faithfulness": 0.80,
"relevancy": 0.70,
"precision": 0.65,
}
@pytest.fixture(scope="session")
def rag_metrics():
return [
FaithfulnessMetric(threshold=THRESHOLDS["faithfulness"]),
AnswerRelevancyMetric(threshold=THRESHOLDS["relevancy"]),
ContextualPrecisionMetric(threshold=THRESHOLDS["precision"]),
]Empfohlene Schwellenwerte für den Start:
| Metrik | Minimum | Zielwert | Kritisch |
|---|---|---|---|
| Faithfulness | 0.80 | 0.90 | < 0.70 |
| Answer Relevancy | 0.70 | 0.85 | < 0.60 |
| Context Precision | 0.65 | 0.80 | < 0.50 |
| Context Recall | 0.60 | 0.80 | < 0.45 |
Starte konservativ und ziehe die Schwellenwerte schrittweise an, wenn dein System reift.
Framework-Vergleich
Welches Framework passt zu dir?
| Framework | Stärke | Ideal für |
|---|---|---|
| RAGAS | Forschungsnah, flexible Metriken | Custom Evaluation, Forschung |
| DeepEval | pytest-Integration, CI/CD | Engineering-Teams, Automatisierung |
| LangSmith | Tracing + Debugging | LangChain-Nutzer, Observability |
| Arize Phoenix | Framework-agnostisch, OpenTelemetry | Heterogene Tech-Stacks |
| TruLens | RAG-Triad-Methodik | Halluzinations-Erkennung |
Meine Empfehlung: RAGAS für die erste Evaluation, DeepEval für CI/CD. Beide sind Open Source und ergänzen sich hervorragend.
Fazit
RAG-Evaluation ist kein optionales Extra, es ist die Qualitätssicherung deiner KI-Anwendung. Mit den richtigen Tools und Metriken wird sie so selbstverständlich wie Unit-Tests in der klassischen Softwareentwicklung.
Dein Einstieg in 3 Schritten:
- Metriken verstehen: Faithfulness und Answer Relevancy sind deine wichtigsten Indikatoren
- Golden Dataset aufbauen: 50 validierte Testfragen sind besser als 500 ungepflegte
- CI/CD integrieren: Automatische Evaluation bei jedem Deployment
Die hier vorgestellten Frameworks, insbesondere RAGAS und DeepEval, machen den Einstieg einfach. Beide lassen sich mit wenigen Zeilen Code in bestehende Projekte integrieren.
Wenn du RAG-Systeme baust, die in Produktion laufen, ist systematische Evaluation keine Option, sondern eine Pflicht. Die Werkzeuge dafür sind ausgereift, Open Source und bereit für den Einsatz.
Dieser Artikel ist Teil meiner RAG-Serie. Für den Einstieg in RAG empfehle ich Einführung in RAG und die CRAG-Architektur. Für fortgeschrittene Architekturen: Agentic RAG und GraphRAG. Und wenn du ein RAG-System in Produktion bringen willst: RAG in Produktion.