Case Study:
Papierkram-Orakel

Lokales RAG-System für den privaten Papierkram

Bedienungsanleitungen, Verträge, Garantien, Rezepte: der Ordner, den niemand liest — verwandelt in eine Wissensbasis, die Fragen in Alltagssprache beantwortet und jede Aussage mit Datei und Seite belegt.

PythonRAGHybrid SearchSQLiteSentence-TransformersTesseract OCR

100 %

Suche & Ranking lokal

20/20

Eval-Fragen korrekt

7

Dateiformate inkl. Scans & Fotos

1

Cloud-Schritt — austauschbar

Motivation

Warum dieses Projekt?

Jeder Haushalt besitzt einen Ordner (oder zwanzig), dessen Inhalt praktisch nie gelesen wird — bis die Waschmaschine blinkt oder eine Kündigungsfrist droht. Klassische Volltextsuche scheitert, weil man die Wortwahl des Dokuments nicht kennt; ein LLM einfach fragen scheitert, weil es den Mietvertrag nicht kennt und im Zweifel halluziniert. RAG (Retrieval Augmented Generation) löst genau dieses Problem: Erst finden, dann formulieren. Bewusst lokal gebaut — private Verträge und Belege gehören nicht als Suchindex in eine Cloud, und eine SQLite-Datei pro Wissensgebiet bedeutet: kein Vendor-Lock-in, jederzeit exportierbar, löschbar, versionierbar.

Wofür es im Alltag taugt

Gerätehandbücher & FehlercodesVerträge & KündigungsfristenGarantien & KaufbelegeSteuerunterlagenHausbau-DokumenteFamilienrezepte

Architektur

Die Architektur

Zwei Phasen: Bei der Indexierung werden Dokumente geparst (inkl. OCR für Scans und Handyfotos), absatzweise in ~700-Zeichen-Chunks geschnitten, lokal embedded und in einer SQLite-Datei mit Vektor- und Volltextindex abgelegt. Bei jeder Frage laufen Vektor-Suche und BM25 parallel, werden per Reciprocal Rank Fusion verschmolzen, ein Cross-Encoder sortiert die Kandidaten fein — und erst dann formuliert ein LLM die Antwort, strikt begrenzt auf die gefundenen Textstellen.

Workflow-Diagramm: Indexierung und Abfrage der lokalen RAG-Pipeline
Ein einziger Cloud-Schritt: Suche, Ranking und OCR laufen komplett lokal auf CPU — nur die finale Antwortformulierung nutzt ein LLM.
Hybrid statt nur semantisch: BM25 rettet exakte Treffer wie Artikelnummern, bei denen reine Vektor-Suche das »bedeutungsähnlichste«, aber falsche Teil wählen würde.
Domain-Architektur: Jedes Wissensgebiet ist ein Ordner mit YAML-Konfiguration (Persona, Chunking, Retrieval-Parameter) — neue Gebiete ohne eine Zeile Kern-Code.

Deep Dives

Deep Dives & Herausforderungen

1. Hybrid Search mit Reciprocal Rank Fusion

Semantische Suche findet »Feinwäsche-Programm«, wenn man nach »Wolle waschen« fragt — aber sie verwechselt Ersatzteil 4055-C mit 4055-D, weil beide fast identisch klingen. Deshalb laufen Vektor-KNN (sqlite-vec) und BM25-Volltextsuche (FTS5) parallel; die Fusion arbeitet rein rangbasiert (Score = Σ 1/(60+Rang)), wodurch Cosine-Distanz und BM25-Score vergleichbar werden, ohne Normalisierungs-Tricks. Ein Chunk, der in beiden Listen vorn liegt, gewinnt.

2. Ehrlichkeit durch Architektur, nicht durch Hoffnung

Das LLM bekommt ausschließlich die gefundenen Textstellen plus die Anweisung, jede Aussage mit [Quelle: Datei | Ort] zu belegen und Nichtwissen zuzugeben. Im Praxistest mit echten Bauprojekt-Dokumenten antwortete das System auf eine Frage nach Kosten, die nirgends dokumentiert waren: »Das steht nicht in den Unterlagen« — statt plausibel klingende Zahlen zu erfinden. Genau dieses Verhalten ist das Qualitätsmerkmal eines RAG-Systems.

3. OCR-Fallback für die analoge Realität

Der Papierkram-Ordner enthält nicht nur digitale PDFs, sondern gescannte Kaufbelege und Handyfotos von Quittungen. Die Parser-Registry erkennt Seiten ohne Textebene und schickt sie automatisch durch Tesseract-OCR — im Praxistest wurde ein gescannter Behörden-Schriftwechsel korrekt indexiert und zitierfähig, inklusive Kennzeichnung »(OCR)« in der Quellenangabe.

4. Reranking mit Kandidaten-Pool

Der Cross-Encoder liest Frage und Chunk gemeinsam und bewertet die Relevanz deutlich genauer als der Vergleich zweier vorab berechneter Vektoren. Damit er etwas zu entscheiden hat, holt die Hybrid-Suche bewusst einen vergrößerten Kandidaten-Pool (Vektor-Top-8 + BM25-Top-8), aus dem nach dem Reranking die besten vier ans LLM gehen.

5. Qualität messbar machen statt durchklicken

Ein Eval-Testset mit 20 handgeschriebenen Fragen prüft Retrieval-Trefferquote und Antwort-Korrektheit gegen erwartete Quellen und Stichworte — inklusive bewusst harter Fälle wie fast identischer Artikelnummern und einem synthetisch gescannten PDF ohne Textebene. Aktueller Stand: 20/20 Retrieval-Treffer, 20/20 korrekte Antworten.

Austauschbares LLM-Backend

Das LLM ist der kleinste Baustein — und in Minuten ersetzt

Die gesamte Intelligenz der Suche — Embeddings, Hybrid-Retrieval, Reranking — läuft lokal und modellunabhängig. Das Sprachmodell kommt erst im allerletzten Schritt ins Spiel und ist hinter einer einzigen Funktion gekapselt: generate_answer(domain, frage, fundstellen). Wer volle Offline-Fähigkeit will, tauscht diese eine Funktion gegen einen Ollama-Call — der Rest des Systems merkt davon nichts.

Claude CLI (aktuell)

Headless über die bestehende Subscription, Modell pro Wissensgebiet wählbar (haiku/sonnet/opus).

Ollama — komplett lokal

Ein HTTP-Call an localhost statt Subprocess: qwen2.5 oder llama3.1 machen das System nach dem Erstsetup vollständig offline-fähig.

Beliebige API

Anthropic-, OpenAI- oder ein anderer API-Call — Prompt-Aufbau und Zitatpflicht bleiben identisch.

Suche und Ranking bleiben in jedem Fall lokal — getauscht wird nur, wer den letzten Satz formuliert.

Unter der Haube

Engineering Details

Eine SQLite-Datei pro Wissensgebiet

Drei Tabellen mit geteilter Row-ID: Klartext + Metadaten, FTS5-Volltextindex, sqlite-vec-Vektorindex (384 Dim.). Export, Backup oder Löschen = eine Datei kopieren oder entfernen.

Absatzbewusstes Chunking

~700 Zeichen mit 10 % Overlap, geschnitten an Absatzgrenzen statt mitten im Satz; überlange Absätze fallen auf ein Sliding Window zurück. Jeder Chunk behält Datei und Fundstelle für das spätere Zitat.

Lokale Modelle, lazy geladen

Multilingualer MiniLM-Bi-Encoder für Embeddings, mmarco-Cross-Encoder fürs Reranking — beide CPU-tauglich und erst beim ersten Zugriff geladen, damit die CLI ohne Modell-Load startet.

Parser-Registry

Dateiendung → Parser-Funktion: PDF (digital + Scan), DOCX inkl. Tabellen, Markdown, TXT, JPG/PNG/HEIC. Neue Formate sind eine Funktion im Dict, kein Umbau.

Abgesicherter LLM-Aufruf

Headless-Call mit deaktivierten Tools, ohne Session-Persistenz, mit Timeout; leere Trefferliste erzeugt eine statische Antwort ganz ohne LLM-Call.

Web-UI für Nicht-Techniker

FastAPI + Chat-Oberfläche: neues Wissensgebiet anlegen, Dateien per Drag & Drop hochladen, indexieren, fragen — der komplette Workflow ohne Terminal.

Ergebnis

Ergebnis

Das System beantwortet im Eval 20 von 20 Testfragen korrekt und mit richtiger Quelle — darunter die klassische RAG-Falle fast identischer Artikelnummern und ein nur per OCR lesbares Scan-PDF. Im Praxistest mit echten Hausbau-Dokumenten lieferte es seitengenaue Antworten aus einer 20-seitigen Baubeschreibung, kombinierte Behördenschreiben und Leitfaden zu einer sauber zitierten Antwort — und gab bei einer nicht dokumentierten Kostenfrage ehrlich zu, die Antwort nicht zu kennen.

Tech Stack

PythonSQLite + sqlite-vecFTS5 / BM25Sentence-TransformersCross-Encoder RerankingTesseract OCRPyMuPDFFastAPIClaude CLI