Startseite / Artikel / Praktische Hinweise: Die AI-Serie: Der schwierigste Teil von RAG, Teil 2 – Warum perfekt

Praktische Hinweise: Die AI-Serie: Der schwierigste Teil von RAG, Teil 2 – Warum perfekt

Schritt-für-Schritt-Anleitung zu den Praktischen Hinweisen: Die AI-Reihe – Der schwierigste Teil von RAG, Teil 2 – Warum perfekt: Verträge, Überprüfungen sowie Code-Blöcke für Teams, die dieses Muster einsetzen.

1548 Wörter

Dieser Leitfaden zeigt Schritt für Schritt den Weg von Rohstoffen bis zu einem funktionsfähigen System für: The AI Series: Der schwierigste Teil von RAG, Teil 2 – Warum perfekte Fragmente dennoch zu schlechten Suchergebnissen führen. Der Fokus liegt auf ausführbaren Schritten, expliziten Überprüfungen sowie Code, den man ohne Rückschluss auf die Absicht in ein Repository einfügen kann. In der Übersichtsphase sollten Eingaben, Verantwortliche für die Schritte sowie Abbruchkriterien definiert werden, bevor Code geändert wird. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Erhalten Sie neben den funktionalen Ergebnissen auch Aufzeichnungen der Laufzeiten sowie der Kosten pro Token oder Abfrage. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Prozess von einer Demo in gemeinsam genutzte Umgebungen übergeht.

Zuerst: Was ist eigentlich ein Embedding?

Beim Bearbeiten der ersten Phase „Was ist das?“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikatoren sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gesammelt sein, den Betreiber überprüfen können, ohne den gesamten Codeverlauf durchlesen zu müssen. Messen Sie die Trefferquote anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragen anpassen. Eine Änderung der Anfragen behebt selten ein schwaches Retrieval-System.

"How do I reset my password?"     → [0.81, 0.12, -0.44, 0.09]
"Steps to change your password"   → [0.79, 0.15, -0.41, 0.11]
"How do I cancel my subscription?"→ [0.22, 0.68, 0.05, -0.39]
from numpy import dot
from numpy.linalg import norm

def cosine_similarity(a, b):
    return dot(a, b) / (norm(a) * norm(b))

query = [0.80, 0.13, -0.42, 0.10]  # "reset my password"

print(cosine_similarity(query, [0.81, 0.12, -0.44, 0.09]))  # 0.998 - very close
print(cosine_similarity(query, [0.22, 0.68, 0.05, -0.39]))  # 0.310 - far apart

Warum das Retrieval tatsächlich schwierig ist

Wenn Sie die Phase „Warum ist das Abrufen tatsächlich möglich?“ durchgehen, notieren Sie zunächst den Vertrag: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Wiederherstellungsprozess. Wiederholte Versuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen. Messen Sie die Erinnerungsfähigkeit anhand eines festgelegten Fragebogens, bevor Sie die Anfragen anpassen – eine häufige Änderung der Anfragen behebt selten ein schwaches Abrufverhalten.

Wie ein echter Abrufpipeline aussieht

Beim Arbeiten an der Phase „Was ist eine echte Informationsabrufung?“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgszeichen sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor großen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Messen Sie die Erinnerungsrate anhand eines festgelegten Fragekatalogs, bevor Sie die Anfragen anpassen. Häufige Änderungen der Anfragen beheben selten ein schwaches Informationsabrufsystem. Beim Arbeiten an der Phase „Was ist eine echte Informationsabrufung?“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgszeichen sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Notieren Sie die Laufzeiten sowie die Kosten pro Token oder Anfrage neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Prozess von einer Demo-Umgebung in gemeinsam genutzte Umgebungen übergeht.

Hybride Suche: Warum Vektor-Suche allein nicht ausreicht

Die hybride Suche funktioniert am besten, wenn sie als messbare Struktur betrachtet wird. Erfassen Sie ein gelungenes Beispiel, einen Fehlfall sowie die Notizen zur Rücksetzung, bevor Sie den Umfang erweitern. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gesammelt sein, den Betreuer ohne Durchsicht des gesamten Systems prüfen können. Trennen Sie die Chunking-Strategie von der Abrufstrategie. Ein Änderung in einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.

from collections import defaultdict

def reciprocal_rank_fusion(result_lists, k=60):
    scores = defaultdict(float)
    for result_list in result_lists:
        for rank, doc_id in enumerate(result_list):
            scores[doc_id] += 1 / (k + rank + 1)
    return sorted(scores, key=scores.get, reverse=True)

vector_ids = [d.metadata["chunk_id"] for d in vector_store.similarity_search(query, k=20)]
bm25_ids = [d.metadata["chunk_id"] for d in bm25_index.search(query, k=20)]

final_ranking = reciprocal_rank_fusion([vector_ids, bm25_ids])

Reranking – der Schritt, den niemand zweimal überspringt

Die Reranking-Phase funktioniert am besten, wenn sie als messbare Größe betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein erfolgreiches Beispiel, einen Fehlerfall sowie die Notizen zur Rücksetzung. Dokumentieren Sie gleichzeitig den erfolgreichen Ablauf und den Wiederherstellungsprozess. Wiederholversuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen. Trennen Sie die Strategie zur Aufteilung in Blöcke von der Strategie zur Abrufung. Ein Änderungsbedarf bei einer dieser Strategien sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.

from sentence_transformers import CrossEncoder

reranker = CrossEncoder("BAAI/bge-reranker-base")

def rerank(query, candidates, top_n=5):
    pairs = [(query, c["text"]) for c in candidates]
    scores = reranker.predict(pairs)
    for c, s in zip(candidates, scores):
        c["rerank_score"] = float(s)
    return sorted(candidates, key=lambda c: c["rerank_score"], reverse=True)[:top_n]

Die Frage beheben – nicht nur den Index

Die Phase „The Fixing the Question Not“ funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes Transkript“, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Ziehen Sie kleine, testbare Einheiten vor umfangreichen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf einen verworrenen Ablauf. Trennen Sie die Aufteilungspolitik von der Abrufpolitik. Eine Änderung sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern. Die Phase „The Fixing the Question Not“ funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes Transkript“, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Erhalten Sie neben den funktionalen Ergebnissen auch Aufzeichnungen zu Laufzeiten sowie Kosten pro Token oder Abfrage. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Prozess von einer Demo in gemeinsame Umgebungen übergeht.

def hyde_retrieve(query, llm, vector_store, k=5):
    hypothetical = llm.invoke(f"Write a short passage answering: {query}")
    return vector_store.similarity_search(hypothetical, k=k)

Messen statt Schätzen

Für die Phase „Messen anstelle von“ sollten Eingabedaten, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Die Konfiguration sollte außerhalb des Anwendungscode gespeichert werden. Umgebungsdateien, Geheimdatenspeicher sowie Feature-Flags sollten an einem Ort zusammengefasst sein, den die Operator überprüfen können, ohne den gesamten Ablauf durchzulesen. Zitieren Sie die Passagen, die tatsächlich die Antwort begründen. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.

def recall_at_k(retrieved_ids, relevant_ids, k):
    top_k = set(retrieved_ids[:k])
    return len(top_k & relevant_ids) / len(relevant_ids) if relevant_ids else 0.0

Was Sie jemandem raten würden, der heute damit beginnt

Zur Phase „Was Sie sagen würden“ sollten Sie die Eingabedaten, den Verantwortlichen für den Schritt sowie die Abbruchkriterien definieren, bevor Sie Code ändern. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckten Zuständen schließen zu müssen. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholungsversuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen. Zitieren Sie die Passagen, die tatsächlich die Antwort untermauern. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Lücken in der Indizierung unterscheiden.

Die unangenehme Wahrheit über RAG

Für die Phase „The Uncomfortable Truth About“ sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Bevorzugen Sie kleine, testbare Einheiten vor umfangreichen Skripten. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren. Zitieren Sie die Passagen, die tatsächlich die Antwort untermauern. Ohne Zitate können die Operator nicht zwischen Halluzinationen und Indexierungsfehlern unterscheiden. Für die Phase „The Uncomfortable Truth About“ sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Erhalten Sie neben den funktionalen Ergebnissen auch Aufzeichnungen der Laufzeiten sowie der Kosten für Tokens oder Abfragen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Ablauf von einer Demo in eine gemeinsame Nutzung übergeht.

Umgebungen.

Betriebskontrollliste

Die Phase der Betriebskontrollliste funktioniert am besten, wenn sie als messbarer Rahmen betrachtet wird. Erfassen Sie eine „goldene“ Transkription, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern.

Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab.

Trennen Sie die Strategie zur Aufteilung in Blöcke von der Strategie zum Abrufen. Ein Änderungs an einer sollte nicht dazu führen, dass die andere neu geschrieben werden muss, wenn sich die Qualitätsmetriken ändern.

Bewerten Sie Einzelantworten sowie mehrstufige Abläufe getrennt voneinander. Die Aggregation der Chat-Bewertungen verschleiert Fehler im Tool-Loop-Prozess.

Schreiben Sie ein kurzes Handbuch: Wie man Schlüssel rotiert, wie man die Warteschlange leert und wie man den letzten Eingang rückgängig macht.

Dokumentieren Sie den erfolgreichen Ablauf sowie den Wiederherstellungsprozess gemeinsam. Versuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen.

Vor der Einführung des gesamten Systems sollten Sie Versionen einfrieren, ein „goldenes Transkript“ für den kritischen Ablauf erstellen und die Schritte zur Rücksetzung überprüfen. In gemeinsam genutzten Umgebungen sind Rate Limits, Überprüfungen der Nutzerrechte sowie ein klarer Verantwortliche für den Umtausch von Geheimnissen erforderlich. Ziehen Sie langweilige Zuverlässigkeit einer cleveren, einmaligen Demonstration vor.

Batch-Hinweis für da3fc7392f6d: Halten Sie die Anbieter-Schlüssel außerhalb des Repositories, legen Sie eine Obergrenze für Session-Tokens fest und speichern Sie die Transkripte neben den Evaluierungs-Dateien, damit spätere Modellwechsel vergleichbar bleiben.