Incident: RAG-Halluzinationen

Das Problem: Bei der Verarbeitung extrem komplexer Retail-Dokumente – wie 200-seitiger Quartalsberichte oder verschachtelter Produktkataloge als unstrukturierte PDFs – erzeugte unser System plötzlich bedenkliche RAG-Halluzinationen. Statt präziser Antworten wurden Fakten aus völlig unterschiedlichen Kontexten fehlerhaft, aber überzeugend klingend zusammengeführt. In einem konkreten Fall generierte das System eine Umsatzzahl, die eine Kombination aus zwei separaten Filialdaten war – keiner der Werte stimmte mit der Realität überein, und dennoch klang die Antwort syntaktisch einwandfrei.

Die Ausgangslage und das generische RAG-Prinzip

Retrieval-Augmented Generation (RAG) ist das absolute Rückgrat unserer Enterprise-Wissenssysteme. Dabei werden große Dokumente in kleine, durchsuchbare Einheiten (Chunks) unterteilt, mit einem Embedding-Modell (bei uns text-embedding-3-large von OpenAI mit 3072 Dimensionen) in hochdimensionale Vektoren umgewandelt, in einer Pinecone-Vektordatenbank gespeichert und bei Suchanfragen als präziser Kontext in den LLM-Prompt injiziert. In unserem Setup für Finanzdaten war höchste Präzision das absolute Gebot. Mit wachsender Dokumentengröße und zunehmender PDF-Komplexität (mehrspaltiges Layout, eingebettete Tabellen) stießen wir auf massive Qualitätsverluste. Die initiale Strategie bestand darin, die Chunk-Größe starr auf 300–500 Token zu begrenzen. Doch diese Taktik bekämpfte tragischerweise nur das Symptom.

Semantic Chunking Diagramm

Warum starres Token-Splitting strukturell scheitert

Ein hartes Token-Limit hat in der Realität einen katastrophalen inhaltlichen Effekt: Es reißt semantische Zusammenhänge mitten im Satz auseinander. Konkretes Beispiel aus unserem Produktivsystem: Ein Satz wie „Die EU-Sparte erzielte in Q3 eine Umsatzsteigerung von 15 %" wurde exakt an der Tokengrenze zwischen zwei Chunks geteilt. „Die EU-Sparte erzielte in Q3" landete in Chunk A, „eine Umsatzsteigerung von 15 %" in Chunk B. Bei einer Nutzeranfrage zu Q3-Umsätzen rief die Vektorsuchmaschine per Cosinus-Ähnlichkeit Chunk B ab (Similarity Score: 0.87), da „Umsatzsteigerung" semantisch sehr nah an der Query lag – ohne Chunk A, also ohne den Unternehmenskontext. Das LLM füllte die fehlende Referenz mit seinem Trainingswissen auf: Halluzination. Noch kritischer: Die Pinecone-Metadaten enthielten keinen Rückverweis auf die übergeordnete Dokumentstruktur, wodurch Seitenreferenzen vollständig verloren gingen.

Der Lösungsansatz: Dynamisches Semantic Chunking

Anstatt deterministisch an der Zeichengrenze zu schneiden, wurde in der Ingestion-Pipeline ein intelligenteres Verfahren implementiert: dynamisches, semantisches Chunking via LangChains SemanticChunker. Das Modell berechnet für jedes Satzpaar die Cosinus-Distanz im Vektorraum. Überschreitet die Distanz einen konfigurierbaren Schwellenwert – bei uns das 85. Perzentil der Distanzverteilung im gesamten Dokument – wird ein Chunk-Boundary gesetzt. Liegt die Distanz darunter, bleiben Sätze im selben Chunk, egal wie lang er wird. So entstehen Chunks, die exakt einem logischen Gedanken entsprechen, statt einer willkürlichen Zeichenanzahl. In der Praxis bedeutet das: Ein Paragraph über Q3-Finanzdaten bleibt vollständig zusammen, auch wenn er 700 Token umfasst.

Architekturwechsel: Einsatz des Parent-Document-Retrievers

Die größte architektonische Herausforderung war die Balance zwischen präziser Retrieval-Granularität und ausreichend großem LLM-Kontext. Kleine Chunks liefern höhere Retrieval-Precision, aber zu wenig Kontext für das Modell. Große Chunks bieten Kontext, senken aber die Precision durch semantisches Rauschen. Die Lösung ist der Parent-Document-Retriever: In Pinecone werden ausschließlich Embeddings für feingranulare Child-Chunks (ca. 100–150 Token) gespeichert. Jeder Child-Chunk trägt als Metadaten-Feld eine parent_id. Beim Retrieval findet Pinecone den exakten Match auf Satzebene. Sofort danach lädt das System über die parent_id den vollständigen Eltern-Chunk (600–1200 Token) aus einem Redis-basierten Docstore. Das LLM erhält also den gesamten semantischen Kontext. Die Pinecone-Anfrage kostet dabei weniger als 15 ms, der Redis-Fetch unter 2 ms.

# LangChain Semantic Chunking & Parent Retriever
from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai.embeddings import OpenAIEmbeddings
from langchain.retrievers import ParentDocumentRetriever
from langchain.storage import RedisStore
from langchain_pinecone import PineconeVectorStore

# 3072-dim embeddings for maximum vector arithmetic precision
embeddings = OpenAIEmbeddings(model='text-embedding-3-large')

# Split at 85th percentile of sentence-pair cosine distance distribution
parent_splitter = SemanticChunker(
    embeddings,
    breakpoint_threshold_type='percentile',
    breakpoint_threshold_amount=85
)

# Fine-grained child splitter for high-precision vector search
child_splitter = RecursiveCharacterTextSplitter(
    chunk_size=150,
    chunk_overlap=20,
    separators=['.', '!', '?']
)

# Redis as persistent docstore for parent chunks (24h TTL)
docstore = RedisStore(redis_url='redis://localhost:6379', ttl=86400)
vectorstore = PineconeVectorStore(index_name='finance-rag', embedding=embeddings)

retriever = ParentDocumentRetriever(
    vectorstore=vectorstore,
    docstore=docstore,
    child_splitter=child_splitter,
    parent_splitter=parent_splitter,
    search_kwargs={'k': 6}  # Top 6 child matches -> 6 parent chunks
)

# Ingest 200-page quarterly report
retriever.add_documents(docs, ids=None)

Ergebnis und Monitoring

Nach dem Rollout des neuen Retrieval-Stacks implementierten wir ein dediziertes Halluzinations-Monitoring: Für jede LLM-Antwort berechnet ein separater Validator-Agent die Grounded-Score – also den Anteil der Aussagen, der tatsächlich durch die retrieved Chunks gedeckt ist, gemessen über erneutes Embedding und Cosinus-Ähnlichkeit. Vor dem Patch lag die durchschnittliche Grounded-Score bei 0.61. Nach dem Patch bei 0.94. Die Rate an Support-Halluzinationen sank um über 80 %, der manuelle QA-Aufwand pro Woche von 12 auf unter 2 Stunden, und das Vertrauen der Fachbereiche in KI-generierte Finanzauskünfte stieg messbar an.