Blogs / RAG in der Produktion: Demo funktioniert, Live scheitert

RAG in der Produktion: Demo funktioniert, Live scheitert

Veröffentlicht
26. Juli 2026
Autor
Faizan Nadeem
Tags
RAG AI Engineering Backend Development LLM
Abstrakte Visualisierung miteinander verbundener Datenknoten, die eine Retrieval-Pipeline darstellen
Foto von Steve A Johnson auf Unsplash

Die Demo funktioniert immer. Sie betten ein paar Dutzend Dokumente ein, stellen eine Frage, und das Modell beantwortet sie sofort korrekt, mit einer sauberen Quellenangabe. Sie zeigen es Ihrem Team. Alle sind beeindruckt. Dann richten Sie es auf den echten Dokumentensatz, ein paar Tausend Seiten statt ein paar Dutzend, und setzen es echten Nutzern vor, und plötzlich zerfĂ€llt alles. Antworten werden vage. Die Latenz schleicht ĂŒber drei Sekunden. Das Modell verweist mit voller Überzeugung auf den falschen Abschnitt. Jemand stellt eine Frage mit einem exakten Produktcode darin, und das System liefert fĂŒnf Chunks zurĂŒck, die zwar thematisch verwandt, aber völlig nutzlos sind.

Die meisten Entwickler behandeln RAG wie einen einzelnen Haken auf einer Checkliste: „Haben wir eine Vektordatenbank hinzugefĂŒgt?“ Das ist der Fehler. Eine Vektordatenbank ist eine Komponente in einer Pipeline, nicht die Pipeline selbst. Die LĂŒcke zwischen einer funktionierenden Demo und einem Produktionssystem ist kein klĂŒgeres Modell und kein besserer Prompt, sondern fast immer die darunterliegende Retrieval-Schicht, und ganz konkret drei Dinge, die die meisten Tutorials auslassen: wie Sie Ihre Dokumente chunkieren, wie Sie darin suchen und wie Sie vermeiden, dieselbe teure Arbeit zweimal zu machen. Beheben Sie diese drei Punkte, und alles, was danach kommt, wird einfacher.

Sie lernen:

  • Warum Chunking mit fester GrĂ¶ĂŸe die Retrieval-QualitĂ€t stillschweigend verschlechtert und was semantisches Chunking behebt
  • Warum reine Vektorsuche Exact-Match-Abfragen verpasst und wie Hybrid Retrieval (Vektor + BM25) diese LĂŒcke schließt
  • Wie Query-Caching sowohl die Latenz als auch die LLM-Kosten senkt, ohne veraltete Antworten auszuliefern
  • Wie man eine einzelne Anfrage durch eine produktionsreife Pipeline von Anfang bis Ende nachverfolgt
  • Was zuerst kaputtgeht, wenn Ihr Dokumentensatz und Ihr Traffic tatsĂ€chlich skalieren
  • Welche Retrieval-Fehler leicht zu machen und teuer zu ignorieren sind

Inhaltsverzeichnis

  1. Die Grundlagen
  2. Die vollstÀndige Architektur
  3. Die Kernschichten erklÀrt
  4. End-to-End-Durchlauf
  5. SonderfÀlle
  6. Skalierung & Produktionsherausforderungen
  7. Codebeispiele
  8. HĂ€ufige Fallstricke
  9. Best Practices fĂŒr die Produktion

Die Grundlagen

Was RAG tatsÀchlich abdeckt

Retrieval-Augmented Generation muss fĂŒr jede einzelne Anfrage vier Fragen korrekt und in der richtigen Reihenfolge beantworten: Was meint der Nutzer eigentlich? Welche Teile Ihrer Dokumente sind fĂŒr diese Bedeutung relevant? Wie bekommen Sie nur die nĂŒtzlichen Teile in ein begrenztes Kontextfenster? Und wie erzeugen Sie eine Antwort, die in dem verankert ist, was Sie abgerufen haben, statt in dem, was das Modell bereits zu „wissen“ glaubt?

Die meisten Menschen, die ihr erstes RAG-Feature bauen, lösen nur die dritte und vierte Frage: Sie verdrahten einen Embedding-Aufruf, eine Vektor-Ähnlichkeitssuche und ein Prompt-Template und gehen davon aus, dass sich die ersten beiden Fragen von selbst erledigen. Tun sie nicht. Query-VerstĂ€ndnis und Retrieval-QualitĂ€t sind die eigentlichen schwierigen Probleme. Generierung ist der einfache Teil; ein leistungsfĂ€higes LLM kann aus fast jedem Kontext, den Sie ihm geben, eine schlĂŒssige Antwort schreiben, auch aus schlechtem Kontext. Genau das ist die Falle: schlechtes Retrieval wirft keinen Fehler, es erzeugt einfach eine selbstsichere, flĂŒssige, falsche Antwort.

Warum es ein wertvolles Problem ist, das man richtig lösen muss

Retrieval-QualitĂ€t ist kein Nice-to-have, sie ist die Obergrenze fĂŒr alles andere, was Sie darauf aufbauen:

  • Halluzinationen verstĂ€rken Vertrauensverlust. Eine falsche Antwort, die richtig klingt, ist schlimmer als gar keine Antwort, besonders bei Support- oder Wissenswerkzeugen, bei denen Menschen nach ein paar guten Erfahrungen aufhören, Dinge doppelt zu prĂŒfen.
  • Latenz hat eine harte UX-Untergrenze. Nach ungefĂ€hr zwei Sekunden gehen Nutzer davon aus, dass etwas kaputt ist, unabhĂ€ngig davon, wie gut die endgĂŒltige Antwort ist.
  • Kosten skalieren mit schlechtem Retrieval, nicht mit gutem Retrieval. Teams, die nicht prĂ€zise abrufen können, kompensieren das, indem sie mehr Chunks in das Kontextfenster stopfen, was bei jedem einzelnen Aufruf mehr Input-Tokens bedeutet.
  • Fehler sind still. FĂŒr „falschen Abschnitt abgerufen“ gibt es keinen Stack Trace. Sie erfahren es erst durch ein Support-Ticket oder einen Screenshot in Slack, was bedeutet, dass Sie Sichtbarkeit bewusst einbauen mĂŒssen — sie entsteht nicht zufĂ€llig.

Die vollstÀndige Architektur

Documents ─▶ Chunking ─▶ Embedding ─┏─▶ Vector Index
                                     └─▶ BM25 Index

User Query ─▶ Query Processing ─▶ Hybrid Retrieval ─▶ Rerank ─▶ Cache Check
                                                                     │
                                                     ┌───────────────┮───────────────┐
                                                  cache hit                     cache miss
                                                     │                                │
                                              return cached                Context Assembly
                                                answer                            │
                                                                                  ▌
                                                                              LLM Call
                                                                                  │
                                                                                  ▌
                                                                          Cache + Return

Das Leitprinzip unter all dem: Retrieval-QualitĂ€t ist eine harte Obergrenze fĂŒr GenerierungsqualitĂ€t. Kein noch so ausgefeiltes Prompt Engineering rettet eine Antwort, die auf falschem Kontext aufgebaut ist; wenn ĂŒberhaupt, macht ein besserer Prompt die falsche Antwort nur ĂŒberzeugender.

Die Kernschichten erklÀrt

1. Semantisches Chunking

Was es ist: Dokumente entlang natĂŒrlicher Bedeutungsgrenzen aufzuteilen — AbschnittsĂŒberschriften, AbsatzumbrĂŒche, Themenwechsel, die ĂŒber Satz-Ähnlichkeit erkannt werden — anstatt stumpf alle N Zeichen oder Tokens abzuschneiden, unabhĂ€ngig davon, was dort steht.

Warum es wichtig ist: Chunking mit fester GrĂ¶ĂŸe ist die mit Abstand hĂ€ufigste Ursache fĂŒr stillen QualitĂ€tsverlust in einer RAG-Pipeline. Eine Chunk-Grenze bei 500 Tokens kĂŒmmert sich nicht darum, ob sie mitten in einem Satz landet, eine nummerierte Liste von ihrer Einleitung trennt oder einen Vorbehalt von der Regel abspaltet, die er einschrĂ€nkt. Das Embedding fĂŒr diesen Chunk reprĂ€sentiert dann nur eine halbe Idee, was bedeutet, dass er entweder nicht abgerufen wird, obwohl er sollte, oder ohne den Kontext abgerufen wird, der ihn ĂŒberhaupt erst korrekt gemacht hat.

def semantic_chunks(sentences, embed_fn, threshold=0.75, max_tokens=400):
    chunks, current, current_tokens = [], [], 0
    prev_vec = None
    for sentence in sentences:
        vec = embed_fn(sentence)
        sim = cosine_similarity(prev_vec, vec) if prev_vec else 1.0
        too_big = current_tokens + count_tokens(sentence) > max_tokens
        if (sim < threshold or too_big) and current:
            chunks.append(" ".join(current))
            current, current_tokens = [], 0
        current.append(sentence)
        current_tokens += count_tokens(sentence)
        prev_vec = vec
    if current:
        chunks.append(" ".join(current))
    return chunks

Produktions-Tipp: Semantische Grenzen allein können immer noch Chunks erzeugen, die zu groß oder zu klein sind. Behalten Sie immer eine harte Token-Obergrenze als Sicherheitsnetz bei und fĂŒgen Sie einen kleinen Überlappungsbereich (10–15 %) zwischen benachbarten Chunks hinzu, damit eine Grenze, die einen abhĂ€ngigen Nebensatz trennt, auf beiden Seiten noch genug Kontext ĂŒbrig lĂ€sst.

Einen vollstĂ€ndigen Vergleich mit fixed-size, recursive und hierarchical Chunking — mit Recall- und Precision-Zahlen fĂŒr jede Strategie — finden Sie unter Chunking-Strategien fĂŒr RAG: Benchmark an echten Dokumenten.

2. Hybrid Retrieval (Vektor + BM25)

Was es ist: Zwei Retrieval-Methoden parallel auszufĂŒhren — dichte Vektor-Ähnlichkeitssuche fĂŒr semantische Bedeutung und eine sparsame Keyword-Methode wie BM25 fĂŒr exakte Term-Treffer — und anschließend die beiden Ranglisten zusammenzufĂŒhren.

Warum es wichtig ist: Embeddings sind hervorragend bei „das bedeutet etwas Ähnliches“ und stillschweigend schlecht bei „das enthĂ€lt exakt diese Zeichenfolge“. Fragen Sie einen Support-Bot nach dem Fehlercode ERR_4402 oder einem bestimmten Funktionsnamen, und eine reine Vektorsuche liefert Ihnen bereitwillig Chunks zurĂŒck, die thematisch verwandt sind, aber den wörtlichen Bezeichner nicht enthalten, weil das Embedding ihn zu einem allgemeinen Konzept geglĂ€ttet hat. BM25 fĂ€ngt genau die FĂ€lle auf, die die Vektorsuche verpasst, und umgekehrt fĂ€ngt die Vektorsuche paraphrasierte oder konzeptionelle Anfragen auf, die kein gemeinsames Vokabular mit dem Quelltext haben.

def hybrid_retrieve(query, vector_index, bm25_index, k=10, rrf_k=60):
    vec_results = vector_index.search(query, top_k=k)
    bm25_results = bm25_index.search(query, top_k=k)
    scores = {}
    for rank, doc_id in enumerate(r.id for r in vec_results):
        scores[doc_id] = scores.get(doc_id, 0) + 1 / (rrf_k + rank)
    for rank, doc_id in enumerate(r.id for r in bm25_results):
        scores[doc_id] = scores.get(doc_id, 0) + 1 / (rrf_k + rank)
    return sorted(scores.items(), key=lambda x: -x[1])[:k]

Das ist Reciprocal Rank Fusion, eine einfache und effektive Methode, zwei Rankings zusammenzufĂŒhren, ohne inkompatible Score-Skalen normalisieren zu mĂŒssen.

Produktions-Tipp: Gewichten Sie BM25 stĂ€rker, wenn die Anfrage AnfĂŒhrungsphrasen, Zahlen oder Bezeichner-Ă€hnliche Tokens enthĂ€lt (alles, was zu einem Code- oder SKU-Muster passt). Ein schneller Regex-Check vor dem Retrieval reicht aus, um die meisten dieser FĂ€lle zu erfassen.

3. Query-Caching

Was es ist: Sowohl das Embedding fĂŒr eine Anfrage als auch die endgĂŒltig generierte Antwort zu cachen, mit einem SchlĂŒssel auf Basis der Anfrage (oder einer nahezu identischen Variante davon), sodass wiederholte oder sehr Ă€hnliche Fragen die teuren Teile der Pipeline komplett ĂŒberspringen.

Warum es wichtig ist: In den meisten produktiven RAG-Systemen entfĂ€llt ein kleiner Satz von Fragen auf einen unverhĂ€ltnismĂ€ĂŸig großen Anteil des Traffics — immer dieselben paar Anfragen im Stil von „wie setze ich mein Passwort zurĂŒck“ oder „wie lautet unsere RĂŒckerstattungsrichtlinie“, nur leicht unterschiedlich von verschiedenen Nutzern formuliert. FĂŒr jede dieser Anfragen erneut zu embedden und neu zu generieren ist reine Verschwendung: Es ist dieselbe Latenz und derselbe Token-Preis fĂŒr eine Antwort, die Sie bereits erzeugt haben.

def get_cached_or_generate(query, redis_client, embed_fn, generate_fn, sim_threshold=0.95):
    query_vec = embed_fn(query)
    cache_key = f"rag:cache:{hash_vector(query_vec)}"
    cached = redis_client.get(cache_key)
    if cached and cosine_similarity(query_vec, cached["vec"]) > sim_threshold:
        return cached["answer"]
    answer = generate_fn(query)
    redis_client.setex(cache_key, 3600, {"vec": query_vec, "answer": answer})
    return answer

In einer Pipeline, an der ich gearbeitet habe, hat allein das HinzufĂŒgen dieser Schicht die durchschnittliche Query-Latenz wĂ€hrend der Spitzenzeiten von ungefĂ€hr 3,2 Sekunden auf etwa 1,1 Sekunden gesenkt — einfach deshalb, weil ein großer Anteil wiederholter Anfragen das LLM ĂŒberhaupt nicht mehr berĂŒhrte. Ihre Zahlen hĂ€ngen davon ab, wie repetitiv Ihr Anfrage-Traffic tatsĂ€chlich ist, aber das Muster gilt fast ĂŒberall.

Produktions-Tipp: Cachen Sie niemals ohne TTL und ohne einen Invalidierungspfad, der an Dokument-Updates gekoppelt ist. Ein Cache, der lÀnger lebt als das Dokument, aus dem er aufgebaut wurde, ist der Weg zu einer selbstsicher ausgelieferten Antwort, die letzten Monat korrekt war.

4. Reranking

Was es ist: Ein zweiter, teurerer Scoring-Durchlauf — meist ein Cross-Encoder-Modell — der auf die besten 20–50 Kandidaten aus dem Hybrid Retrieval angewendet wird, bevor die endgĂŒltigen Top-k in das Kontextfenster gelangen.

Warum es wichtig ist: Sowohl Vektor- als auch BM25-Suche sind schnelle NĂ€herungen. Sie sind gut darin, „wahrscheinlich relevante“ Kandidaten in eine Shortlist zu bringen, aber nicht prĂ€zise genug, um ihnen als endgĂŒltigem Ranking zu vertrauen. Ein Cross-Encoder, der sich die Anfrage und jeden Kandidaten tatsĂ€chlich gemeinsam ansieht, statt vorberechnete Vektoren zu vergleichen, ist deutlich besser darin, diese Shortlist korrekt zu ordnen — nur ist er zu teuer, um ihn ĂŒber Ihren gesamten Korpus laufen zu lassen.

Produktions-Tipp: Reranken Sie die Shortlist, niemals den vollstĂ€ndigen Korpus. Einen Cross-Encoder ĂŒber auch nur ein paar Hundert Kandidaten laufen zu lassen, fĂŒgt spĂŒrbare Latenz hinzu; ĂŒber Ihren gesamten Dokumentensatz ist es keine Option.

5. Kontextzusammenstellung & Token-Budgetierung

Was es ist: Die gerankten Chunks gezielt in Ihr Kontextfenster zu packen, ĂŒberlappende Inhalte zu deduplizieren, nach Relevanz zu sortieren und zu stoppen, sobald Sie ein Token-Budget erreichen, statt jeden abgerufenen Chunk in den Prompt zu kippen.

Warum es wichtig ist: „Mehr Kontext“ ist nicht dasselbe wie „besserer Kontext“. Ab einem bestimmten Punkt verwĂ€ssern zusĂ€tzliche Chunks das Signal, mit dem das Modell arbeiten muss, treiben Latenz und Kosten hoch und erhöhen die Wahrscheinlichkeit, dass sich das Modell an einem irrelevanten Abschnitt festbeißt. Ein hartes Token-Budget zwingt die vorgelagerten Retrieval- und Reranking-Stufen dazu, ihre Arbeit tatsĂ€chlich zu machen, statt sich auf Masse als Ausgleich zu verlassen.

End-to-End-Durchlauf

Verfolgen wir eine einzelne Anfrage durch die vollstĂ€ndige Pipeline: „Wie hoch ist das Timeout beim Retry des Payment-Webhooks?“

  1. Anfrage empfangen. Die API-Schicht nimmt den Rohstring an und normalisiert Whitespace und Groß-/Kleinschreibung.
  2. Cache-PrĂŒfung. Die Anfrage wird eingebettet und mit gecachten Query-Vektoren oberhalb des Ähnlichkeitsschwellenwerts verglichen. Bei kaltem Cache ist das ein Miss.
  3. Query-Verarbeitung. Eine leichtgewichtige PrĂŒfung markiert dies als Anfrage mit einem spezifischen technischen Begriff („webhook retry“), was die Hybrid-Gewichtung in Richtung BM25 verschiebt.
  4. Hybrid Retrieval. Vektorsuche und BM25-Suche liefern jeweils ihre besten Kandidaten zurĂŒck; Reciprocal Rank Fusion fĂŒhrt sie zu einer einzigen gerankten Shortlist zusammen.
  5. Reranking. Der Cross-Encoder bewertet die Shortlist anhand des tatsĂ€chlichen Anfrage-Texts und ordnet sie neu. Wenn das Reranking nichts ĂŒber einem minimalen Relevanz-Score zurĂŒckliefert, verzweigt die Pipeline frĂŒhzeitig zu einer Fallback-Antwort („Ich konnte dazu nichts Spezifisches finden, versuchen Sie es mit einer Umformulierung“), statt das LLM zur Generierung aus schwachem Kontext zu zwingen.
  6. Kontextzusammenstellung. Die am höchsten bewerteten Chunks werden dedupliziert, sortiert und bis zum Token-Budget in den Prompt gepackt.
  7. LLM-Aufruf. Das Modell erzeugt eine Antwort, die im zusammengestellten Kontext verankert ist, mit Anweisungen, den Quell-Chunk zu zitieren.
  8. Cache-Schreibvorgang. Das Query-Embedding und die generierte Antwort werden mit TTL und einem Versions-Tag, das an den Last-Updated-Zeitstempel des Quelldokuments gebunden ist, in den Cache geschrieben.
  9. Antwort zurĂŒckgegeben. Der Nutzer erhĂ€lt in ungefĂ€hr ein bis zwei Sekunden eine Antwort mit einer Quellenangabe zum konkreten Dokumentabschnitt.

Jeder Schritt in dieser Kette hat einen expliziten Fehlerpfad. Das ist der Unterschied zwischen einer Pipeline, die elegant degradiert, und einer, die entweder hĂ€ngen bleibt oder halluziniert, wenn weiter vorne etwas nicht das zurĂŒckliefert, was erwartet wurde.

SonderfÀlle

Tabellen und strukturierte Daten. Naives Chunking, ob semantisch oder nicht, zerreißt Tabellen oft, trennt Überschriften von Zeilen oder teilt eine Tabelle mitten in einer Zeile. Erkennen Sie tabellarische Inhalte bereits bei der Ingestion und chunkieren Sie sie als Einheit, indem Sie sie in eine Markdown- oder Key-Value-Darstellung umwandeln, die das Einbetten als Text ĂŒberlebt.

HĂ€ufig aktualisierte Dokumente. Dokumente, die sich oft Ă€ndern (Preisseiten, Richtliniendokumente, Changelogs), brauchen eine Cache-Invalidierung, die an einen Content-Hash oder eine Versionsnummer gebunden ist, nicht nur eine TTL. Ein rein zeitbasierter Cache allein liefert fĂŒr die gesamte TTL-Dauer veraltete Antworten aus, selbst wenn sich das Quelldokument fĂŒnf Minuten nach dem Schreiben des Cache-Eintrags geĂ€ndert hat.

Mehrturn-Konversationen. Eine Anschlussfrage wie „und was ist mit Staging?“ ergibt fĂŒr ein Retrieval-System ohne den Kontext des vorherigen Turns keinen Sinn. FĂŒgen Sie einen Query-Rewriting-Schritt hinzu, der den jĂŒngsten Konversationsverlauf in eine in sich geschlossene Anfrage einarbeitet, bevor sie ins Retrieval geht; andernfalls sucht Ihre Hybridsuche gegen eine halbe Frage.

Skalierung & Produktionsherausforderungen

Embedding-Generierung wird beim Ingestion-Maßstab zum Engpass. Ein paar Dokumente synchron einzubetten ist in Ordnung; Zehntausende einzubetten nicht. Verlagern Sie die Ingestion in eine asynchrone Task-Queue — Celery mit Redis als Broker ist eine naheliegende Wahl, wenn das ohnehin schon in Ihrem Stack ist — und batchen Sie Embedding-Aufrufe, statt pro Chunk eine einzelne Anfrage abzusetzen.

Die Suche im Vektorindex wird langsamer, wenn der Korpus wĂ€chst. Brute-Force-Ähnlichkeitssuche ist im kleinen Maßstab in Ordnung und bricht jenseits von ungefĂ€hr 100k Vektoren auseinander. Wechseln Sie zu einem Approximate-Nearest-Neighbor-Index (HNSW ist der ĂŒbliche Standard) und akzeptieren Sie einen kleinen, einstellbaren Genauigkeits-Trade-off fĂŒr einen großen Gewinn bei der Latenz.

Cache-Invalidierung wird im Maßstab schwieriger, nicht einfacher. Wenn mehr Dokumente sich hĂ€ufiger Ă€ndern, reicht eine einzelne globale TTL nicht mehr aus. Binden Sie Cache-Keys an einen Versions-Hash der Quelldokumente, die zu einer bestimmten Antwort beigetragen haben, sodass ein Update an einem davon natĂŒrlich jede gecachte Antwort invalidiert, die davon abhing.

Kosten schleichen sich still nach oben. Ohne Token-Tracking pro Anfrage ist das erste Anzeichen eines Kostenproblems die Monatsrechnung, nicht eine konkrete Anfrage. Loggen Sie die Anzahl der Input- und Output-Tokens pro Request und schlagen Sie bei Ausreißern Alarm; eine Anfrage, die deutlich mehr Kontext hineinzieht als ĂŒblich, ist oft ein Zeichen dafĂŒr, dass Ihr Token-Budget oder Ihr Reranking-Schwellenwert enger gesetzt werden muss.

Codebeispiele

Semantisches Chunking, Hybrid Retrieval und semantisches Caching werden oben unter den Kernschichten vollstĂ€ndig behandelt. Noch ein weiteres nĂŒtzliches StĂŒck, das man griffbereit haben sollte: ein minimaler Fallback-Guard, damit die Pipeline niemals aus leerem oder nahezu leerem Kontext generiert:

def generate_with_guard(query, context_chunks, generate_fn, min_score=0.3):
    if not context_chunks or context_chunks[0].score < min_score:
        return "I couldn't find anything specific on that in the documentation."
    context = "\n\n".join(c.text for c in context_chunks)
    return generate_fn(query=query, context=context)

Diese eine Funktion ist dafĂŒr verantwortlich, aus einer „stillen falschen Antwort“ ein „ehrliches Ich weiß es nicht“ zu machen — eine kleine Änderung mit großer Wirkung auf das Nutzervertrauen.

HĂ€ufige Fallstricke

Fehler: Vektorsuche als die gesamte Lösung behandeln. Eine Pipeline nur mit Vektorsuche wird Exact-Match-Anfragen, IDs, Codes und zitierte Begriffe systematisch verfehlen. Lösung: FĂŒhren Sie standardmĂ€ĂŸig Hybrid Retrieval aus, nicht erst als spĂ€tere Optimierung. Es ist frĂŒh gĂŒnstig hinzuzufĂŒgen und teuer nachzurĂŒsten, wenn Ihr Evaluationssatz bereits auf das Verhalten einer reinen Vektor-Pipeline zugeschnitten ist.

Fehler: Chunking nach einer festen Token-Zahl ohne RĂŒcksicht auf Inhaltsgrenzen. Das ist die hĂ€ufigste Ursache fĂŒr „die Antwort ist fast richtig, aber ein SchlĂŒsseldetail fehlt“. Lösung: Chunkieren Sie semantisch, begrenzen Sie die GrĂ¶ĂŸe als Sicherheitsnetz und fĂŒgen Sie einen kleinen Überlappungsbereich zwischen benachbarten Chunks hinzu.

Fehler: Caching ohne Invalidierungsstrategie. Ein Cache ohne RĂŒckweg zum Quelldokument liefert bereitwillig die Antwort vom letzten Monat aus, als wĂ€re sie aktuell. Lösung: Versionieren Sie Cache-Keys gegen einen Content-Hash der beitragenden Dokumente, nicht nur gegen eine zeitbasierte TTL.

Fehler: Annehmen, dass mehr abgerufene Chunks eine bessere Antwort bedeuten. Context Stuffing erhöht Kosten und Latenz und macht Antworten oft schlechter statt besser, weil das Signal verwĂ€ssert wird. Lösung: Reranken Sie aggressiv und erzwingen Sie ein hartes Token-Budget fĂŒr das, was tatsĂ€chlich den Prompt erreicht.

Fehler: Ohne Evaluationssatz ausliefern. Ohne einen festen Satz reprĂ€sentativer Anfragen und erwarteter Quellen gibt es keine Möglichkeit zu wissen, ob eine Änderung am Chunking oder Retrieval geholfen oder geschadet hat. Lösung: Erstellen Sie schon vor dem Release zumindest einen kleinen Evaluationssatz (30–50 Anfragen) und fĂŒhren Sie ihn bei jeder Änderung an der Retrieval-Schicht erneut aus.

Best Practices fĂŒr die Produktion

  • Messen Sie Retrieval-QualitĂ€t getrennt von GenerierungsqualitĂ€t. Precision@k und Recall gegen einen festen Evaluationssatz zeigen Ihnen, ob das Problem im Retrieval oder im Prompt liegt; debuggen Sie nicht den LLM-Aufruf, wenn die eigentliche Ursache weiter oben liegt.
  • Cachen Sie mit versionierten SchlĂŒsseln, nicht nur mit TTLs. Binden Sie jeden Cache-Eintrag an einen Hash der Dokumente, aus denen er aufgebaut wurde, damit Dokument-Updates automatisch die richtigen Antworten invalidieren.
  • Erzwingen Sie ein hartes Token-Budget bei der Kontextzusammenstellung. Mehr Chunks sind keine Strategie; ein enges, geranktes Kontextfenster schlĂ€gt fast immer ein großes, ungeranktes.
  • Loggen Sie jedes Retrieval, nicht nur jeden Fehler. Welche Chunks abgerufen wurden, welcher Score wo lag und was vom Token-Budget verworfen wurde — das sind die Daten, die Sie beim ersten Bericht ĂŒber eine falsche Antwort brauchen werden.
  • Bauen Sie einen Fallback-Pfad fĂŒr schwaches Retrieval. Ein ehrliches „Ich weiß es nicht“ bei niedrigem Relevanz-Score ist immer besser als eine flĂŒssige Antwort, die auf Kontext basiert, der kaum zur Frage passte.

Zum Abschluss

Nichts davon ist exotisch: semantisches Chunking, Hybrid Retrieval und eine Caching-Schicht sind alles Dinge, die die meisten Backend-Ingenieure ohnehin schon bauen können. Die LĂŒcke zwischen Demo und Produktion ist kein fehlender Durchbruch; die Demo hatte nur nie genug Dokumente oder genug Anfragevielfalt, um offenzulegen, wo Chunking mit fester GrĂ¶ĂŸe und reine Vektorsuche stillschweigend zu kurz greifen. Beheben Sie diese drei Dinge, bevor Sie den Prompt anfassen, und die meisten Tickets vom Typ „gestern hat es funktioniert, warum ist es heute falsch?“ tauchen gar nicht erst auf.

Was ist als Erstes kaputtgegangen, als Sie Ihre RAG-Pipeline aus der Demo in die Produktion gebracht haben? Ich wĂŒrde wirklich gern hören, was Sie ĂŒberrascht hat.

Faizan Nadeem
Autor
Faizan Nadeem

AI/GenAI engineer specialising in agentic RAG, LangGraph, and production LLM systems with Python and FastAPI. 2 years building AI agents, RAG pipelines, and the backends behind them.

Weitere Artikel