Tippfehler-Cluster (02–05, 09, 12, 23, 27–28) und Terminologie (Outcomes 16↔18, Budget 16↔23, prompt_version, Coding-Agent, fester Workflow). Handoff: Git-Remote, P0/P1A/P1B erledigt, nächster Slice Faktencheck.
13 KiB
RAG: Retrieval und Generation
Der Prompt-Contract steht (Kapitel 11). Im Backlog trotzdem der Klassiker: „Wir kaufen eine Vektor-DB, dann halluziniert er nicht.“ Zwei Monate später zitiert das System die falsche Policy-Version mit der richtigen Quellenoptik — und das Team debuggt Embeddings, obwohl der Index ACL und Frische nie ernst genommen hat.
RAG (Retrieval-augmented Generation) ist kein Produktname und kein Checkbox-Feature. Es ist ein System: Wissen holen, kuratieren, dem Modell als Evidenz geben, Antwort an Evidenz koppeln — mit Ownership, Versionen und Eval.
Kern in einem Satz: RAG heißt: zur Laufzeit relevante, erlaubte Passagen holen und Generation an diese Evidenz binden (Citations / Refuse) — Qualität steckt oft im Retrieval und Korpus, nicht im nächsten Model-Tier; „Vektor-DB = fertig“ ist ein Anti-Pattern.
Einordnung: Ladder-Stufe 3 (Kapitel 08), Pattern Grounded Answer (Kapitel 07), Context-Slot Grounding (Kapitel 10). Lebende Go-Live-Liste: rag-production-ready.md.
Bridge: Klassisches SE → AI Engineering
| Klassisches SE | In RAG … |
|---|---|
| Search / Read-Model / CQRS | Retrieval als Faktenlieferung vor der „Anzeige“ (Generation) |
| Index, Schema, Reindex-Jobs | Chunking, Embeddings, Sparse-Index, index_version |
| ACL auf Dokumenten | dieselbe ACL beim Indexieren und zur Query-Zeit |
| Pagination / Projection | Top-k, Snippet-Länge, Context-Budget |
| Cache invalidation | Re-Embed, Re-Index, Cache-Keys mit Index-Version (Kapitel 10) |
| Integrationstests gegen API-Contract | Retrieval-Metriken und End-to-End Task Success |
| „Source of truth“ in der DB | Korpus-Ownership: welches Doc gilt, welche Version, wer löscht? |
Die Brücke: ihr baut eine Such- und Wissenspipeline mit probabilistischem Renderer — nicht „ChatGPT plus PDFs“.
Was RAG ist (und was nicht)
Query / Task
→ (optional) Query-Rewrite / HyDE / Filter
→ Retrieve (sparse und/oder dense)
→ (optional) Rerank
→ Filter (ACL, Score-Threshold, Dedup, Budget)
→ Context-Pack (IDs, Snippets)
→ Generate unter Evidenz-Regeln
→ Validate (Schema, Citations, Refuse)
| RAG ist | RAG ist nicht |
|---|---|
| Grounding auf eurem Korpus | Ersatz für Live-Transaktionen (→ Tools, Kapitel 13) |
| System aus Ingest + Retrieve + Generate | nur Embedding-API |
| messbar (Recall, e2e) | „wir haben Vektoren“ |
| an ACL und Retention gebunden | freies Durchreichen aller Intranet-Docs |
Nicht RAG: das Modell „kennt die Welt“ aus Pretraining. Für sich ändernde Policies und Produktfakten ist der Korpus die Wahrheit — das Modell formuliert darauf.
Korpus und Ingest
Ownership
Ohne Owner kein Production-RAG:
- Welche Quellen (Confluence, Repo, Tickets, PDFs, CMS)?
- Wer freigibt Aufnahme / Löschung?
- Welche Datenklasse und Residenz?
- Was ist die kanonische Version bei Widerspruch?
Chunking
Chunks sind eure Index-Zeilen. Schlechte Schnitte → gutes Embedding sucht Müll.
| Hebel | Praxis |
|---|---|
| Größe | an Task und Modellbudget; oft absatz-/sektionorientiert statt willkürliche Token-Säulen |
| Overlap | nur soweit nötig für Satzgrenzen — Overlap ist kein Qualitätsersatz |
| Struktur nutzen | Überschriften, Tabellen, Code-Blöcke, Ticket-Felder als Metadaten |
| Atomarität | ein Chunk ≈ eine beantwortbare Einheit; Mischmasch aus drei Themen erschwert Citations |
| Parent-Child | kleine Retrieval-Chunks, größere „Parent“-Fenster zum Generieren — wenn evaluiert |
Dokumentiert die Strategie; ändert sie nur mit Retrieval-Eval (nicht nach Bauchgefühl im Demo-Chat).
Metadaten (First-Class)
doc_id, version/updated_at, tenant/acl, source_type, locale, url/path, optional section. Ohne Metadaten kein gezieltes Filtern, keine Citations, kein Incident-Debug.
Freshness und Re-Index
| Ereignis | Pflicht |
|---|---|
| Doc geändert/gelöscht | Update oder Tombstone im Index |
| ACL geändert | Re-Index oder Query-Filter-Korrektur — sofort risikorelevant |
| Embedding-Modell gewechselt | voller Re-Embed + neue index_version |
| Chunking-Strategie geändert | Re-Ingest + Eval |
„Täglich alles neu“ ohne Event-Pipeline skaliert selten; Event-getrieben + periodischer Full-Reconcile ist der reife Default.
Retrieval: Sparse, Dense, Hybrid, Rerank
Dense (Vektor)
Semantische Ähnlichkeit. Stark bei Paraphrasen und unscharfen Fragen. Schwach bei exakten IDs, Fehlercodes, Produktnummern, seltenen Tokens — und bei schlechtem Chunking.
Sparse (BM25 / Keyword / Lexikalisch)
Stark bei exakten Strings, Codes, Eigennamen. Schwach bei rein semantischen Umschreibungen.
Hybrid (Default-Empfehlung, bis Evidenz widerspricht)
Kombiniert beide Signale (z. B. score fusion, RRF). Oft der pragmatische Start für Unternehmenskorpora. Reines Dense oder reines Sparse nur mit begründetem Eval (rag-production-ready.md).
Rerank
Zweite Stufe: Top-N (z. B. 50) → Cross-Encoder / Strong-Reranker → Top-k (z. B. 5) fürs Context-Fenster.
| Pro | Contra |
|---|---|
| bessere Precision im Fenster | Latency und Kosten |
| entlastet das Generieren | weiterer Moving Part, eigene Version |
Faustregel: erst Hybrid + gutes Chunking messen; Rerank, wenn Recall ok, aber e2e an Noise im Top-k scheitert.
Query-Pfad
- Filter vor Similarity (Tenant, ACL, Doc-Type, Zeit)
- optional Query-Rewrite nur mit Eval (Rewrite kann den Intent verbiegen)
- leere Treffer und Low-Score nicht mit „Modellwissen auffüllen“ — sondern Refuse / Nachfragen / anderes Tool
Generation: Citations und Refuse
Retrieval ohne Bindung ist teurer Context-Müll.
Evidenz-Regeln (Contract)
- Behauptungen nur mit source_id / Chunk-ID aus dem gelieferten Pack.
- Keine Evidenz oder Score unter Schwelle → Refuse oder gezielte Rückfrage — nicht raten.
- Widersprüchliche Quellen → markieren oder eskalieren, nicht still „mitteln“.
- Snippets im Context mit stabilen IDs (Kapitel 10 Evidence Pack).
Structured Output hilft: { "answer", "citations": ["doc:…#chunk:…"], "confidence_or_refuse" } — Validate im Code (Kapitel 11).
Grounding-Check (Control Flow)
Optional aber wertvoll: Antwort-Spans gegen Snippets prüfen (Overlap, NLI-ähnlich, oder strikte „nur zitierte Sätze“-Policy). Nicht perfekt — besser als reines Hoffnungsprompting.
Failure Modes (die euch treffen werden)
| Failure Mode | Symptom | Hebel |
|---|---|---|
| Miss (Recall) | richtige Doc nie im Top-k | Chunking, Hybrid, Query, Korpus-Lücken |
| Noise (Precision) | irrelevante Snippets dominieren | k senken, Rerank, Filter, Diät |
| Stale | alte Policy zitiert | Freshness, version im Citation |
| ACL-Leak | falscher Tenant sieht Doc | ACL index + query; Tests |
| Citation Theater | ID genannt, Inhalt passt nicht | Validate, Grounding-Check |
| Contradiction | zwei Quellen, eine Antwort | Policy im Contract, HITL |
| Indirect Injection | Doc enthält „ignoriere policy“ | untrusted slot, Sanitize, least privilege |
| Over-retrieve | p95 und € explodieren | Budget, Cache, async |
Eval muss Retrieval und e2e trennen: gutes Retrieve + schlechte Generation ist ein anderes Ticket als schlechtes Retrieve.
Eval (Minimum, das zählt)
| Ebene | Metriken (Beispiele) | Zweck |
|---|---|---|
| Retrieval | Recall@k, MRR, nDCG; Hit-Rate auf Gold-Docs | Index/Chunk/Query |
| Grounded e2e | Task Success, Citation-Precision, Refuse-Korrektheit | Nutzerwert |
| Ops | p95 retrieve, p95 total, €/query, empty-hit-rate | SLO (T7) |
| Safety | ACL-Proben, Injection-Docs im Suite | T8 |
Golden Set: echte Fragen + erwartete Doc-IDs (+ Idealantwort oder Claims). Online: Sample-Reviews, User-Corrections, „thumbs down“ mit Trace auf retrieval_ids. Details-Methodik: Kapitel 17; Plan: eval-plan.md.
Patterns und Trade-offs
Pattern: Hybrid first, fancy later
BM25 + Dense + einfache Fusion schlägt oft monatelanges „nur neue Embeddings“.
Trade-off: zwei Index-Pfade pflegen; dafür Robustheit auf Codes und Paraphrasen.
Pattern: Retrieve less, show IDs
Lieber 3–5 starke Snippets mit IDs als 20 halbrelevante Absätze.
Trade-off: braucht besseres Ranking; belohnt Context-Diät und Citations.
Pattern: Versioned index + pin in traces
Jeder Generate-Call loggt index_version, retrieval_ids, prompt_version, model_id.
Trade-off: Speicher; ohne das sind Incidents nicht rekonstruierbar.
Pattern: RAG für Wissen, Tools für Live
Preise, Kontostände, „Ticket #123 Status jetzt“ → Tool/API. Policies und Handbücher → RAG.
Trade-off: zwei Pfade; verhindert „gestern indexierter Preis“.
Decision Frame: Brauchen wir RAG?
| Wenn … | Dann … |
|---|---|
| Antwort muss euren Korpus widerspiegeln | RAG (Stufe 3) |
| Wissen ändert sich oft | RAG + Freshness, nicht FT als Wiki |
| Nur Labels/Format | Structured Prompt (Stufe 2), kein Index |
| Live-State / Wirkung | Tools (Stufe 4) |
| Korpus winzig und stabil im Prompt-Budget | manchmal gezielter Context ohne volles RAG-System — ehrlich benennen |
Trade-off: k und Fenster
| Größeres k / mehr Tokens | Kleineres k |
|---|---|
| höherer Recall-Chance | weniger Noise, günstiger, oft klarere Antworten |
| Lost-in-the-middle-Risiko | abhängiger von Ranking-Qualität |
Messung schlägt Default-k aus dem Tutorial.
Anti-Patterns
| Anti-Pattern | Symptom | Besser |
|---|---|---|
| Vektor-DB = fertig | Index ohne Eval/ACL/Freshness | System + Checkliste |
| Ein-Chunk-für-alles | 2k-Token-Blöcke ohne Struktur | taskgerechtes Chunking |
| Nur Dense für Ticket-IDs | exakte Keys werden verfehlt | Hybrid |
| Generate ohne Refuse | Modell füllt Lücken aus Pretraining | Evidenz-Contract |
| Citations ohne IDs | „laut Dokumentation…“ | stabile source_ids |
| Index ohne ACL | Leak bei der ersten Multi-Tenant-Query | ACL von Tag 1 |
| Re-Index nie | überzeugende Alt-Fakten | Event + Reconcile |
| Eval nur Chat-Gefühl | Demo grün, Prod rot | Recall@k + e2e |
| RAG statt Tool | „aktueller Preis aus PDF von März“ | Live-API |
| Alles embedden | Secrets und HR-Akten im Index | Datenklassen, Allowlist-Quellen |
Production Notes
Cost. Retrieve (Embed-Query, Search, Rerank) + große Contexts dominieren oft €/Task. Cache Retrieval-Ergebnisse und Embeddings mit Versions-Keys; Diät vor Tier-Upgrade (Kapitel 09, 23).
Latency. p95 = retrieve (+ rerank) + generate. Parallelisiert wo möglich; async für dicke Korpora; Rerank nur wenn der SLO es trägt.
Observability. index_version, query (redacted), filters, hit counts, top scores, retrieval_ids, empty/low-score flags, tokens grounding-slot, citation validate ok. Minimum: observability-minimum.md.
Security / Privacy. Untrusted Docs im Context = Injection-Fläche. ACL, Redaction vor Index wo nötig, keine Secrets im Korpus. Multi-Tenant-Tests sind keine Kür (Kapitel 19, 20).
Lifecycle. Embedding-Modell, Chunking und Index-Schema sind Breaking Changes für Retrieval — Canary und parallele Eval-Suite (T9). Owner für Korpus und für Retrieval-Pipeline benennen (T10).
Key Takeaways
- RAG ist ein System (Ingest, Retrieve, Rerank, Pack, Generate, Validate) — kein Vektor-DB-Kauf.
- Hybrid + Metadaten + ACL + Freshness tragen mehr als Prompt-Kosmetik.
- Citations und Refuse binden Generation an Evidenz; Struktur ≠ Wahrheit ohne Grounding-Disziplin.
- Eval trennen: Retrieval-Metriken und End-to-End Task Success.
- Live-Fakten und Wirkung bleiben Tools; stil-/format-Plateaus später ggf. FT (Kapitel 15) — Fakten nicht „fine-tunen“.
- Go-Live: rag-production-ready.md.
Praktische nächste Schritte
- Liste Korpus-Quellen, Owner, Datenklasse und „was darf nicht indexiert werden“.
- Definiere Chunking + Pflicht-Metadaten in einer halben Seite; setze
index_version. - Baue 20–50 Gold-Fragen mit erwarteten Doc-IDs; miss Recall@k bevor du am Generate-Prompt feilst.
- Erzwinge im Contract: keine Evidenz → Refuse; logge
retrieval_ids. - Geh rag-production-ready.md Punkt für Punkt durch.
- Als Nächstes Wirkung und Live-Systeme: Tools und Function Calling.