Veröffentlichungsdatum: 30. Mai 2026 | Autor: HolySheep AI Tech Blog | Lesezeit: 18 Minuten

Inhaltsverzeichnis

1. Einführung: Was ist RAG und warum 2026?

Stellen Sie sich vor, Sie haben eine riesige Bibliothek mit Millionen von Dokumenten – Handbücher, Verträge, Wissensdatenbanken – und Ihre KI soll trotzdem präzise Antworten auf jede Frage geben. Genau dafür gibt es Retrieval-Augmented Generation (RAG).

Als ich vor zwei Jahren zum ersten Mal mit RAG experimentierte, habe ich Stunden damit verbracht, die falschen Modelle zu nutzen und unnötig hohe Kosten zu produzieren. Heute zeige ich Ihnen, wie Sie diese Fehler vermeiden und mit HolySheep AI Ihr RAG-System effizient aufbauen.

Was Sie in diesem Tutorial lernen:

2. RAG-Grundlagen für Einsteiger

Bevor wir in die technischen Details einsteigen, klären wir die Grundlagen. RAG ist wie ein intelligenten Bibliothekar, der:

  1. Relevante Dokumente findet (Retrieval) – basierend auf der Benutzerfrage
  2. Kontext bereitstellt – die gefunden Dokumente werden als Kontext dem LLM übergeben
  3. Präzise Antwort generiert – das LLM beantwortet die Frage mit dem bereitgestellten Kontext

Architektur-Übersicht

+------------------+     +-------------------+     +------------------+
|   Dokumente      | --> |  Embedding-Modell | --> |  Vektor-Datenbank |
+------------------+     +-------------------+     +------------------+
                                                          |
                                                          v
+------------------+     +-------------------+     +------------------+
|  Benutzerfrage   | --> |  Ähnlichkeitssuche | <-- |  Top-K Ergebnisse |
+------------------+     +-------------------+     +------------------+
                                                          |
                                                          v
                                                 +------------------+
                                                 |   Reranker       |
                                                 +------------------+
                                                          |
                                                          v
                                                 +------------------+
                                                 |  LLM (Antwort)   |
                                                 +------------------+

3. Embedding-Modell richtig auswählen

Das Embedding-Modell wandelt Ihre Dokumente und Fragen in numerische Vektoren um. Die Wahl des richtigen Modells bestimmt 70% Ihrer RAG-Performance.

Die 3 wichtigsten Kriterien bei der Modellauswahl:

Embedding-Modelle im Vergleich 2026

Modell Dimensionalität Kontext Sprachen Preis pro 1M Tokens MT5-Latenz
text-embedding-3-small 1536 (kürzbar) 8.191 Tokens Multilingual $0.02 ~35ms
text-embedding-3-large 3072 (kürzbar) 8.191 Tokens Multilingual $0.13 ~45ms
embed-multilingual-v3.0 1024 8.192 Tokens 100+ Sprachen $0.04 ~28ms
bge-m3 1024 8.192 Tokens 100+ Sprachen $0.03 ~32ms
m3e-base 768 512 Tokens Chinesisch + Englisch $0.01 ~20ms

Praktische Empfehlung für Einsteiger

Für die meisten Anwendungsfälle empfehle ich text-embedding-3-small oder embed-multilingual-v3.0. Beide bieten:

4. Multi-Modell-Reranking实战

Reranking ist der geheime Boost für Ihre RAG-Performance. Nach der initialen Vektor-Suche werden die Ergebnisse von einem spezialisierten Modell neu sortiert.

Warum Multi-Modell-Reranking?

# Beispiel: Suche nach "Verspätung Lieferung Garantie"

Ohne Reranking (Vektor-Suche allein):

Ergebnis 1: Lieferadresse ändern ✓✓✓

Ergebnis 2: Verspätung und Garantiebedingungen ✓✓✓✓✓

Ergebnis 3: Lagerstandorte ✓

Mit Reranking:

Ergebnis 1: Verspätung und Garantiebedingungen ✓✓✓✓✓

Ergebnis 2: Lieferadresse ändern ✓✓

Ergebnis 3: Rückgabe und Erstattung ✓

Multi-Modell-Reranking Strategie

Die Idee ist einfach: Kombinieren Sie verschiedene Reranker-Modelle für maximale Genauigkeit.

Strategie = {
    "Stufe 1": {
        "Modell": "bge-reranker-base",
        "Top-K": 50,
        "Zweck": "Breite Vorauswahl"
    },
    "Stufe 2": {
        "Modell": "bge-reranker-large", 
        "Top-K": 10,
        "Zweck": "Feinjustierung"
    },
    "Stufe_3": {
        "Modell": "cross-encoder-ms-marco",
        "Top-K": 3,
        "Zweck": "Finale Auswahl"
    }
}

5. Retrieval-Kosten治理完整指南

In meiner Praxis habe ich erlebt, wie RAG-Systeme von 500€/Monat auf unter 50€/Monat optimiert wurden – ohne Qualitätseinbußen. Hier ist meine bewährte Strategie:

5.1 Dokumentvorverarbeitung optimieren

# ❌ Vorher: Unoptimierte Chunk-Strategie
chunks = []
for doc in documents:
    chunks.extend(split_by_tokens(doc, chunk_size=512))  # 512 Tokens pro Chunk

✅ Nachher: Adaptive Chunking mit Overlap

chunks = [] for doc in documents: # Verschiedene Chunk-Größen für verschiedene Dokumenttypen if doc.type == "Gesetzestext": chunk_size = 1024 overlap = 128 elif doc.type == "Support-FAQ": chunk_size = 512 overlap = 64 else: chunk_size = 768 overlap = 96 chunks.extend(split_by_tokens(doc, chunk_size=chunk_size, overlap=overlap))

5.2 Caching-Strategie implementieren

import hashlib
from functools import lru_cache

class EmbeddingCache:
    def __init__(self, ttl_seconds=86400):  # 24 Stunden Cache
        self.cache = {}
        self.ttl = ttl_seconds
    
    def _get_key(self, text: str) -> str:
        return hashlib.sha256(text.encode()).hexdigest()
    
    def get(self, text: str):
        key = self._get_key(text)
        if key in self.cache:
            import time
            if time.time() - self.cache[key]["timestamp"] < self.ttl:
                return self.cache[key]["embedding"]
        return None
    
    def set(self, text: str, embedding):
        key = self._get_key(text)
        import time
        self.cache[key] = {
            "embedding": embedding,
            "timestamp": time.time()
        }

Usage: Reduziert API-Aufrufe um 60-80% bei wiederholten Fragen

cache = EmbeddingCache()

5.3 Hybride Suche für Balance

Kombinieren Sie semantische Suche (Embedding) mit Keyword-Suche (BM25), um die Anzahl der benötigten Embedding-Queries zu reduzieren.

Suchstrategie = {
    "Hybrid_Suche": {
        "semantic_weight": 0.7,  # 70% Gewichtung Vektor-Suche
        "keyword_weight": 0.3,   # 30% Gewichtung BM25
        "Kostenreduktion": "~40%"
    },
    "Nur_semantisch": {
        "semantic_weight": 1.0,
        "keyword_weight": 0.0,
        "Kostenreduktion": "0%"
    }
}

6. Komplette Code-Implementierung mit HolySheep

Jetzt wird es praktisch! Im folgenden Code sehen Sie eine vollständige RAG-Pipeline mit HolySheep AI.

6.1 Installation und Setup

# Installation der benötigten Pakete
pip install requests numpy scikit-learn

Import und Konfiguration

import requests import numpy as np from typing import List, Dict, Tuple

============================================

HOLYSHEEP AI KONFIGURATION

============================================

⚠️ WICHTIG: Ersetzen Sie durch Ihren echten API-Key

Registrieren Sie sich hier: https://www.holysheep.ai/register

HOLYSHEEP_CONFIG = { "base_url": "https://api.holysheep.ai/v1", "api_key": "YOUR_HOLYSHEEP_API_KEY", # ← Hier Ihren Key eintragen "model": "text-embedding-3-small", "reranker_model": "bge-reranker-base" } def holysheep_embedding(texts: List[str]) -> List[List[float]]: """ Embedding-Vektoren mit HolySheep AI generieren. Preis: $0.02 pro 1M Tokens (85%+ günstiger als OpenAI) Latenz: <50ms Args: texts: Liste von Texten zur Embedding-Generierung Returns: Liste von Embedding-Vektoren """ headers = { "Authorization": f"Bearer {HOLYSHEEP_CONFIG['api_key']}", "Content-Type": "application/json" } payload = { "input": texts, "model": HOLYSHEEP_CONFIG["model"] } response = requests.post( f"{HOLYSHEEP_CONFIG['base_url']}/embeddings", headers=headers, json=payload ) if response.status_code != 200: raise Exception(f"Embedding-Fehler: {response.status_code} - {response.text}") data = response.json() return [item["embedding"] for item in data["data"]] def holysheep_rerank(query: str, documents: List[str], top_k: int = 5) -> List[Dict]: """ Dokumente mit HolySheep Reranker neu sortieren. Args: query: Die Benutzerfrage documents: Liste der zu bewertenden Dokumente top_k: Anzahl der zurückgegebenen Top-Ergebnisse Returns: Liste von Dict mit {'index', 'document', 'score'} """ headers = { "Authorization": f"Bearer {HOLYSHEEP_CONFIG['api_key']}", "Content-Type": "application/json" } payload = { "query": query, "documents": documents, "top_n": top_k, "model": HOLYSHEEP_CONFIG["reranker_model"] } response = requests.post( f"{HOLYSHEEP_CONFIG['base_url']}/rerank", headers=headers, json=payload ) if response.status_code != 200: raise Exception(f"Reranker-Fehler: {response.status_code} - {response.text}") return response.json()["results"] print("✅ HolySheep API erfolgreich konfiguriert!")

6.2 Vollständige RAG-Pipeline

import hashlib
from datetime import datetime, timedelta

class HolySheepRAGPipeline:
    """
    Vollständige RAG-Pipeline mit HolySheep AI.
    
    Features:
    - Embedding-Caching für Kostenreduktion
    - Multi-Stage Retrieval
    - Reranking für höhere Qualität
    """
    
    def __init__(self, api_key: str):
        self.config = HOLYSHEEP_CONFIG.copy()
        self.config["api_key"] = api_key
        self.vector_store = []  # In Produktion: FAISS, Pinecone, etc.
        self.embedding_cache = {}
        self.cache_ttl = timedelta(hours=24)
        
    def index_documents(self, documents: List[str]) -> Dict:
        """
        Dokumente für die Suche indizieren.
        
        Args:
            documents: Liste der zu indizierenden Dokumente
            
        Returns:
            Statistiken über den Indexierungsvorgang
        """
        start_time = datetime.now()
        embeddings = []
        
        # Chunking der Dokumente
        chunks = []
        for i, doc in enumerate(documents):
            # Einfaches Chunking: 500 Zeichen pro Chunk
            for j in range(0, len(doc), 500):
                chunk = doc[j:j+500]
                if len(chunk) > 50:  # Nur Chunks > 50 Zeichen
                    chunks.append({
                        "text": chunk,
                        "doc_index": i,
                        "chunk_index": j // 500
                    })
        
        # Embeddings generieren (mit Cache-Prüfung)
        for chunk in chunks:
            cache_key = hashlib.md5(chunk["text"].encode()).hexdigest()
            
            if cache_key in self.embedding_cache:
                embedding = self.embedding_cache[cache_key]
                cache_hit = True
            else:
                embedding = holysheep_embedding([chunk["text"]])[0]
                self.embedding_cache[cache_key] = embedding
                cache_hit = False
            
            self.vector_store.append({
                "text": chunk["text"],
                "embedding": embedding,
                "doc_index": chunk["doc_index"],
                "chunk_index": chunk["chunk_index"],
                "cached": cache_hit
            })
            embeddings.append(embedding)
        
        elapsed = (datetime.now() - start_time).total_seconds()
        
        return {
            "total_documents": len(documents),
            "total_chunks": len(chunks),
            "cache_hits": sum(1 for v in self.vector_store if v.get("cached")),
            "api_calls": len(documents) - sum(1 for v in self.vector_store if v.get("cached")),
            "processing_time_seconds": elapsed,
            "avg_latency_ms": (elapsed / len(chunks) * 1000) if chunks else 0
        }
    
    def search(self, query: str, top_k: int = 10, rerank: bool = True) -> List[Dict]:
        """
        Relevante Dokumente für eine Query finden.
        
        Args:
            query: Die Suchanfrage
            top_k: Anzahl der zurückzugebenden Ergebnisse
            rerank: Ob Reranking aktiviert werden soll
            
        Returns:
            Liste der relevanten Dokumente mit Konfidenzwerten
        """
        # 1. Query embedden
        query_embedding = holysheep_embedding([query])[0]
        
        # 2. Vektor-Suche (Cosine Similarity)
        scores = []
        for item in self.vector_store:
            similarity = self._cosine_similarity(query_embedding, item["embedding"])
            scores.append({
                "text": item["text"],
                "score": similarity,
                "doc_index": item["doc_index"]
            })
        
        # Sortieren und Top-K auswählen
        scores.sort(key=lambda x: x["score"], reverse=True)
        initial_results = scores[:top_k * 2]  # Mehr holen für Reranking
        
        # 3. Optional: Reranking
        if rerank and len(initial_results) > 3:
            reranked = holysheep_rerank(
                query, 
                [r["text"] for r in initial_results],
                top_k=top_k
            )
            
            # Ergebnisse aktualisieren mit Reranker-Scores
            final_results = []
            for r in reranked:
                result = initial_results[r["index"]].copy()
                result["rerank_score"] = r["relevance_score"]
                final_results.append(result)
            
            return final_results[:top_k]
        
        return initial_results[:top_k]
    
    def _cosine_similarity(self, vec1: List[float], vec2: List[float]) -> float:
        """Cosine Similarity zwischen zwei Vektoren berechnen."""
        dot_product = sum(a * b for a, b in zip(vec1, vec2))
        norm1 = sum(a * a for a in vec1) ** 0.5
        norm2 = sum(b * b for b in vec2) ** 0.5
        return dot_product / (norm1 * norm2) if norm1 and norm2 else 0
    
    def generate_answer(self, query: str, context_documents: List[str]) -> Dict:
        """
        Antwort mit Kontext generieren (RAG).
        
        Nutzt HolySheep LLM für die Antwortgenerierung.
        """
        # Kontext zusammenfügen
        context = "\n\n---\n\n".join(context_documents)
        
        prompt = f"""Basierend auf den folgenden Dokumenten beantworten Sie die Frage.

Dokumente:
{context}

Frage: {query}

Antwort (bitte nur die relevanten Informationen aus den Dokumenten verwenden):"""

        headers = {
            "Authorization": f"Bearer {self.config['api_key']}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "model": "gpt-4.1",  # $8/MTok bei HolySheep
            "messages": [
                {"role": "user", "content": prompt}
            ],
            "temperature": 0.3,
            "max_tokens": 1000
        }
        
        response = requests.post(
            f"{self.config['base_url']}/chat/completions",
            headers=headers,
            json=payload
        )
        
        if response.status_code != 200:
            raise Exception(f"Generierungsfehler: {response.status_code}")
        
        result = response.json()
        return {
            "answer": result["choices"][0]["message"]["content"],
            "usage": result.get("usage", {}),
            "model": payload["model"]
        }


============================================

BEISPIEL-NUTZUNG

============================================

#.pipeline = HolySheepRAGPipeline(api_key="YOUR_HOLYSHEEP_API_KEY")

Beispieldokumente (in Produktion: echte Dokumente laden)

beispiel_dokumente = [ "Die Garantie für elektronische Geräte beträgt 24 Monate ab Kaufdatum. Diese deckt Herstellungsfehler und Materialschäden ab.", "Für Rücksendungen haben Sie 14 Tage Zeit. Die Ware muss unbenutzt und in Originalverpackung sein.", "Unser Kundenservice ist von Montag bis Freitag von 9:00 bis 18:00 Uhr erreichbar unter [email protected].", "Verspätete Lieferungen werden nach dem 5. Werktag automatisch mit 5€ pro Tag erstattet, maximal 50€.", "Die Lieferung erfolgt innerhalb von 3-5 Werktagen innerhalb Deutschlands. Expresslieferung gegen Aufpreis möglich." ]

Dokumente indizieren

print("🔄 Dokumente werden indiziert...") stats = pipeline.index_documents(beispiel_dokumente) print(f"✅ Indizierung abgeschlossen:") print(f" - Dokumente: {stats['total_documents']}") print(f" - Chunks: {stats['total_chunks']}") print(f" - Cache-Treffer: {stats['cache_hits']}") print(f" - API-Aufrufe: {stats['api_calls']}")

Frage stellen

print("\n🔍 Suche nach Antwort...") results = pipeline.search("Was passiert wenn meine Lieferung zu spät kommt?") print("📋 Top-Ergebnisse:") for i, r in enumerate(results, 1): print(f" {i}. Score: {r.get('rerank_score', r['score']):.4f}") print(f" {r['text'][:80]}...")

Antwort generieren

context = [r['text'] for r in results[:3]] antwort = pipeline.generate_answer( "Was passiert wenn meine Lieferung zu spät kommt?", context ) print(f"\n💬 Generierte Antwort:") print(f" {antwort['answer']}")

7. Häufige Fehler und Lösungen

In meiner täglichen Arbeit mit RAG-Systemen sehe ich immer wieder die gleichen Fehler. Hier sind meine Top 5 mit konkreten Lösungen:

Fehler 1: Falsche Chunk-Größe

❌ Fehler ✅ Lösung
Zu kleine Chunks (100 Tokens) Zu viel Kontextverlust, wichtige Informationen werden getrennt
Zu große Chunks (2000 Tokens) Zu viel Rauschen, niedrige Embedding-Genauigkeit
Optimale Größe: 500-800 Tokens Mit 10-15% Overlap zwischen Chunks
# Optimale Chunking-Konfiguration
CHUNKING_CONFIG = {
    "chunk_size": 768,          # Tokens
    "chunk_overlap": 128,       # Tokens Overlap (ca. 17%)
    "min_chunk_length": 100,    # Minimale Zeichen
    "max_chunk_length": 1500,   # Maximale Zeichen
    "respect_sentences": True,  # An Satzgrenzen aufteilen
    "preserve_formatting": True # Listen, Tabellen intakt halten
}

def smart_chunk(text: str, config: dict = CHUNKING_CONFIG) -> List[str]:
    """
    Intelligentes Chunking mit Overlap und Formatierungserhaltung.
    """
    from typing import List
    
    chunks = []
    
    # Erst an Absätzen orientieren
    paragraphs = text.split('\n\n')
    
    current_chunk = ""
    for para in paragraphs:
        if len(current_chunk) + len(para) < config["max_chunk_length"]:
            current_chunk += para + "\n\n"
        else:
            if current_chunk.strip():
                chunks.append(current_chunk.strip())
            # Overlap: Letzten Satz des alten Chunks behalten
            sentences = current_chunk.split('.')
            overlap = '.'.join(sentences[-2:]) if len(sentences) > 1 else ""
            current_chunk = overlap + para + "\n\n"
    
    if current_chunk.strip():
        chunks.append(current_chunk.strip())
    
    return chunks

Fehler 2: Keine Query-Transformation

❌ Problem ✅ Lösung
Benutzer gibt umgangssprachliche Fragen ein Query wird nicht optimal zu Embedding-Vektoren passen
"Ich will mein Geld zurück" vs. "Rückerstattung" Query-Expansion und Synonym-Ersetzung nutzen
def expand_query(query: str) -> List[str]:
    """
    Query für bessere Retrieval-Ergebnisse erweitern.
    """
    # Synonyme und verwandte Begriffe hinzufügen
    expansions = {
        "geld zurück": ["Rückerstattung", "Erstattung", "Refund"],
        "kaputt": ["defekt", "beschädigt", "nicht funktionsfähig"],
        "lieferung": ["Versand", "Zustellung", "Paket"],
        "garantie": ["Gewährleistung", "Reklamation", "Mangel"]
    }
    
    expanded = [query]
    
    # Query in Wörter aufteilen
    words = query.lower().split()
    
    # Für jeden bekannten Begriff Synonyme hinzufügen
    for word in words:
        for key, synonyms in expansions.items():
            if key in word:
                for syn in synonyms:
                    expanded.append(query.replace(key, syn))
    
    # Duplikate entfernen
    return list(set(expanded))

Beispiel

original = "Ich will mein geld zurück" queries = expand_query(original) print(f"Original: {original}") print(f"Erweitert: {queries}")

Ausgabe: ['Ich will mein geld zurück',

'Ich will mein Rückerstattung',

'Ich will mein Erstattung']

Fehler 3: Fehlende Fehlerbehandlung bei API-Aufrufen

import time
import logging
from requests.exceptions import RequestException

logger = logging.getLogger(__name__)

class HolySheepRetryHandler:
    """
    Robuste Fehlerbehandlung mit automatischen Retry für HolySheep API.
    """
    
    def __init__(self, max_retries: int = 3, base_delay: float = 1.0):
        self.max_retries = max_retries
        self.base_delay = base_delay
    
    def call_with_retry(self, func, *args, **kwargs):
        """
        Funktion mit Retry-Logik aufrufen.
        """
        last_exception = None
        
        for attempt in range(self.max_retries):
            try:
                return func(*args, **kwargs)
                
            except RequestException as e:
                last_exception = e
                status_code = e.response.status_code if hasattr(e, 'response') else None
                
                # Keine Wiederholung bei Authentifizierungsfehlern
                if status_code in [401, 403]:
                    logger.error(f"Authentifizierungsfehler: {e}")
                    raise
                
                # Rate-Limit: Länger warten
                if status_code == 429:
                    wait_time = self.base_delay * (2 ** attempt) * 2
                else:
                    wait_time = self.base_delay * (2 ** attempt)
                
                logger.warning(
                    f"Attempt {attempt + 1}/{self.max_retries} fehlgeschlagen: {e}. "
                    f"Erneuter Versuch in {wait_time}s..."
                )
                time.sleep(wait_time)
                
            except ValueError as e:
                # Ungültige Eingabe - nicht wiederholen
                logger.error(f"Ungültige Eingabe: {e}")
                raise
        
        # Alle Versuche fehlgeschlagen
        logger.error(f"API-Aufruf nach {self.max_retries} Versuchen fehlgeschlagen")
        raise last_exception

Usage

handler = HolySheepRetryHandler(max_retries=3)

Sichere API-Aufruf

try: embeddings = handler.call_with_retry( holysheep_embedding, ["Mein Text"] ) except Exception as e: logger.error(f"Kritischer Fehler: {e}") # Fallback-Strategie implementieren embeddings = get_fallback_embeddings(["Mein Text"])

Fehler 4: Mangelnde Evaluation

❌ Problem ✅ Metrik
Keine Messung der Retrieval-Qualität Recall@K, MRR, NDCG implementieren
Subjektive Einschätzung Automatisierte Tests mit Ground Truth
from typing import List, Dict, Tuple
import numpy as np

class RAGEvaluator:
    """
    Automatisierte Evaluation von RAG-Systemen.
    """
    
    def __init__(self):
        self.results = []
    
    def calculate_recall_at_k(
        self, 
        retrieved: List[str], 
        relevant: List[str], 
        k: int = 10
    ) -> float:
        """
        Recall@K: Wie viele relevante Dokumente wurden gefunden?
        
        Beispiel: 3 relevante, 2 in Top-10 → Recall@10 = 0.67
        """
        retrieved_top_k = retrieved[:k]
        relevant_set = set(relevant)
        
        if not relevant_set:
            return 0.0
        
        hits = sum(1 for doc in retrieved_top_k if doc in relevant_set)
        return hits / len(relevant_set)
    
    def calculate_mrr(self, retrieved: List[str], relevant: List[str]) -> float:
        """
        Mean Reciprocal Rank: Position des ersten relevanten Dokuments.
        
        Beispiel: Erstes relevantes bei Position 3 → MRR = 1/3 ≈ 0.33
        """
        for i, doc in enumerate(retrieved, 1):
            if doc in relevant:
                return 1.0 / i
        return 0.0
    
    def evaluate_pipeline(
        self,
        test_queries: List[Dict],  # [{query, relevant_docs}]
        pipeline_func
    ) -> Dict:
        """
        Komplette Pipeline-Evaluation durchführen.
        """
        recalls = []
        mrrs = []
        
        for test_case in test_queries:
            query = test_case["query"]
            relevant = test_case["relevant_docs"]
            
            # Retrieval durchführen
            retrieved = pipeline_func(query)
            
            # Metriken berechnen
            recall = self.calculate_recall_at_k(retrieved, relevant)
            mrr = self.calculate_mrr(retrieved, relevant)
            
            recalls.append(recall)
            mrrs.append(mrr)
        
        return {
            "mean_recall_at_10": np.mean(recalls),
            "mean_mrr": np.mean(mrrs),
            "num_queries": len(test_queries),
            "sample_results": list(zip(recalls, mrrs))
        }

Usage

evaluator = RAGEvaluator() test_set = [ { "query": "Garantiebedingungen für Elektronik", "relevant_docs": ["Die Garantie beträgt 24 Monate..."] }, { "query": "Rückgabefrist", "relevant_docs": ["14 Tage Zeit für Rücksendungen..."] } ] results = evaluator.evaluate_pipeline(test_set,