AI Engineering Academy · Lektion

Eine automatisierte Evaluationsumgebung erstellen

Sie erstellen eine wiederholbare Evaluationspipeline, die Ihr vollständiges RAG-System anhand eines Testsatzes ausführt, alle Metriken berechnet und einen Bericht erzeugt, damit Sie Verbesserungen im Zeitverlauf verfolgen können.

Lektion 4 von 413 Schritte

Eine automatisierte Evaluationsumgebung erstellen ist eine kostenlose AI Engineering Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des AI Engineering Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.

Was ist ein Evaluierungs-Framework?

Ein Evaluierungs-Framework ist eine wiederholbare, automatisierte Pipeline, die Ihr vollständiges RAG-System anhand eines standardisierten Testsatzes ausführt, alle Metriken berechnet und einen Bericht erstellt. Das entscheidende Wort ist wiederholbar: Jedes Mal, wenn Sie Ihre Chunking-Strategie, Ihr Embedding-Modell, Ihren Prompt oder Ihr LLM ändern, führen Sie dasselbe Framework aus und vergleichen die Ergebnisse mit einer Baseline. Dadurch wird die RAG-Entwicklung von subjektivem Ausprobieren zu datengetriebenem Engineering.

Architektur des Frameworks

Ein gut konzipiertes Evaluierungs-Framework besteht aus vier Ebenen: Testdatenverwaltung (den Referenzdatensatz laden und versionieren), Pipeline-Ausführung (jede Testfrage durch die vollständige RAG-Pipeline leiten), Metrikberechnung (alle Retrieval- und Generierungsmetriken berechnen) und Berichterstellung (Ergebnisse mit Versionsinformationen speichern und einen Vergleich mit der vorherigen Baseline erstellen). Jede Ebene sollte unabhängig testbar und konfigurierbar sein.

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 metrics

Jeden Testfall ausführen

Führen Sie für jede Frage im Referenzdatensatz die vollständige RAG-Pipeline aus und erfassen Sie alle Zwischenergebnisse: die IDs und Scores der abgerufenen Chunks, den formatierten Kontext, die generierte Antwort und die Tokenanzahl. Das Speichern dieser Zwischenwerte ist für die Fehlersuche unerlässlich: Wenn eine Frage schlecht abschneidet, können Sie genau untersuchen, welche Chunks abgerufen wurden und warum die Antwort falsch war, ohne die teure Pipeline erneut auszuführen.

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

Alle Metriken in einem Durchlauf berechnen

Nachdem Sie die Ausgaben aller Testfälle gesammelt haben, berechnen Sie die vollständige Metriksuite in einem einzigen Durchlauf über die Ergebnisse. Trennen Sie Retrieval-Metriken (berechnet anhand der Chunk-IDs) von Generierungsmetriken (berechnet durch Aufrufe des LLM-Prüfers). Bündeln Sie die Aufrufe des LLM-Prüfers, um die Effizienz zu maximieren: Gruppieren Sie die Bewertungen der Faktentreue und senden Sie sie mit asyncio parallel statt nacheinander. Protokollieren Sie den Fortschritt, da die Generierungsmetriken bei mehr als 100 Testfällen mehrere Minuten dauern können.

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 metrics

Ergebnisse mit Versionsinformationen speichern

Jeder Evaluierungslauf sollte mit Versionsmetadaten gespeichert werden, damit Sie Ergebnisse über verschiedene Konfigurationen hinweg vergleichen können. Fügen Sie den Git-Commit-Hash des Codes, die Konfigurationsparameter (Embedding-Modell, Chunk-Größe, K, Schwellenwert, LLM-Modell), den Zeitstempel und eine verständliche Beschreibung des Laufs hinzu. Speichern Sie die Ergebnisse in einer JSON-Lines-Datei oder einer Datenbanktabelle. So entsteht eine dauerhafte Historie der Entwicklung Ihres Systems.

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

Mit der Baseline vergleichen

Vergleichen Sie nach jedem Lauf automatisch die Ergebnisse mit der vorherigen Baseline und kennzeichnen Sie Regressionen. Eine Regression liegt vor, wenn eine Metrik um mehr als einen festgelegten Schwellenwert sinkt (z. B. um 2 Prozentpunkte). Geben Sie eine Vergleichstabelle aus, die die Änderungen der Metriken zeigt. Wenn sich eine Metrik deutlich verschlechtert, sollte der Evaluierungslauf mit einem Exit-Code ungleich null fehlschlagen. Dadurch blockiert eine CI/CD-Pipeline die Bereitstellung dieser Änderung.

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) == 0

In CI/CD integrieren

Das Evaluierungs-Framework ist besonders leistungsfähig, wenn es in Ihre CI/CD-Pipeline integriert ist. Konfigurieren Sie es so, dass es automatisch bei jedem Pull Request ausgeführt wird, der die Chunking-Logik, die Konfiguration des Embedding-Modells, Prompt-Vorlagen oder Retrieval-Parameter ändert. Die Pipeline ist nur erfolgreich, wenn alle Metriken die Mindestschwellenwerte erreichen und keine Metrik gegenüber der Baseline des Main-Branches schlechter wird. So verhindern Sie, dass unbeabsichtigte Qualitätsverschlechterungen in den Produktivbetrieb gelangen.

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

Verständliche Berichte erstellen

Erstellen Sie zusätzlich zu den Dateien mit den Rohmetriken einen menschenlesbaren HTML- oder Markdown-Bericht, den Ihr Team in Kommentaren zu Pull Requests prüfen kann. Fügen Sie eine Übersichtstabelle aller Metriken, eine Liste fehlgeschlagener Testfälle mit der Frage, der erwarteten Antwort, der generierten Antwort und den abgerufenen Chunks sowie ein Trenddiagramm mit den Metriken der letzten 10 Läufe hinzu. Visuelle Berichte helfen nichttechnischen Beteiligten zu verstehen, ob sich das System verbessert.

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)

Kosten pro Evaluierungslauf verfolgen

Evaluierungsläufe kosten Geld – sie rufen die Embedding-API, die LLM-API und das Prüf-LLM auf. Erfassen Sie die Kosten jedes Evaluierungslaufs zusammen mit den Qualitätsmetriken. Eine umfassende Evaluierung von 100 Testfällen kostet je nach verwendeten Modellen typischerweise 0,50 bis 2,00 $. Verwenden Sie günstigere Modelle für Aufrufe des Prüfers (GPT-4o-mini für die Bewertung der Faktentreue) und reservieren Sie teure Modelle für die Generierung. Nehmen Sie die geschätzten Kosten des Laufs in den gespeicherten Bericht auf, damit Sie Evaluierungen in Ihrem Entwicklungszyklus budgetieren können.

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

Geplante Evaluierung zur Überwachung des Produktivbetriebs

Führen Sie das Framework zusätzlich zu Evaluierungen bei Codeänderungen in CI/CD nach einem Zeitplan im Produktivbetrieb aus – täglich oder wöchentlich – und testen Sie es mit echten Benutzeranfragen, die aus Ihren Logs ausgewählt werden. Dadurch erkennen Sie Data Drift: Wenn sich der Dokumentbestand weiterentwickelt und sich die Muster der Benutzeranfragen verändern, kann die Systemqualität ohne jede Codeänderung abnehmen. Planen Sie wöchentliche Evaluierungsläufe, die 50 aktuelle Benutzeranfragen auswählen, bewerten und automatisch eine Qualitätszusammenfassung an den Slack-Kanal Ihres Teams senden.

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

Metriktrends im Zeitverlauf visualisieren

Rohdaten in einer JSONL-Datei sind auf einen Blick schwer zu interpretieren. Erstellen Sie eine einfache Trendvisualisierung, die jede Metrik über die letzten 20 Evaluierungsläufe in einem Liniendiagramm darstellt. Verwenden Sie den Zeitstempel des Laufs als x-Achse und den Metrik-Score als y-Achse. Zeichnen Sie eine horizontale Linie beim Mindestschwellenwert. Wenn eine Metrik unter diese Linie fällt, ist das Problem sofort sichtbar, ohne dass Sie die Rohdaten durchsuchen müssen. Tools wie Matplotlib oder ein einfaches Web-Dashboard (Grafana, Streamlit) eignen sich gut dafür.

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

Schnelltest

Testen Sie Ihr Verständnis der Konzepte aus dieser Lektion zur AI-Engineering.

Lektionsrückblick

In dieser Lektion haben Sie gelernt: wie Sie einen vollständigen Evaluierungs-Harness strukturieren – mit Testdatenverwaltung, Pipeline-Ausführung, Metrikberechnung und Berichtserstellung –, wie Sie Ausführungen mit einer Baseline vergleichen und CI/CD bei Regressionen fehlschlagen lassen, wie Sie für die Teamprüfung verständliche Berichte erstellen und wie Sie eine geplante Produktionsüberwachung ausführen, um Data Drift ohne Codeänderungen zu erkennen. Damit verfügen Sie nun über eine vollständige Grundlage zum Erstellen und Evaluieren von RAG-Systemen für den Produktionseinsatz.

Kostenlos starten

Lerne Python mit einem KI-Tutor — kostenlos

Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.

Kurse
30
Lektionen
120

Häufig gestellte Fragen

Ist die Lektion „Eine automatisierte Evaluationsumgebung erstellen“ kostenlos?

Ja — der vollständige Text von „Eine automatisierte Evaluationsumgebung erstellen“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des AI Engineering Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Eine automatisierte Evaluationsumgebung erstellen“?

Sie erstellen eine wiederholbare Evaluationspipeline, die Ihr vollständiges RAG-System anhand eines Testsatzes ausführt, alle Metriken berechnet und einen Bericht erzeugt, damit Sie Verbesserungen im… Du übst AI Engineering Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um AI Engineering Academy zu starten?

Keine Vorkenntnisse erforderlich. AI Engineering Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.

Wie lange dauert die Lektion „Eine automatisierte Evaluationsumgebung erstellen“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser AI Engineering Academy-Lektion Code schreiben und ausführen?

Ja. Jede AI Engineering Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Warum Evaluation bei RAG wichtig ist
  2. Retrieval-Metriken: Hit Rate, MRR und NDCG
  3. Generierungsmetriken: Faithfulness und Antwortrelevanz
  4. Eine automatisierte Evaluationsumgebung erstellen
← Zurück zu AI Engineering Academy