RAG mit Ollama: Bringen Sie KI bei, Ihre Dokumente zu beantworten
Sie haben Dokumente – PDFs, Artikel, Notizen, eine Wissensdatenbank. Sie möchten Fragen stellen
und Antworten speziell zu diesen Dokumenten erhalten, nicht zu allgemeinen Kenntnissen des Modells.
Und das alles – lokal, ohne Daten in die Cloud zu senden.
Genau dafür gibt es RAG. In diesem Artikel – eine Erklärung des Konzepts,
ein visuelles Schema der Pipeline und ein Schritt-für-Schritt-Python-Beispiel, das tatsächlich funktioniert.
Und auch Muster aus der Produktion, die nicht in der Dokumentation stehen.
📚 Inhalt des Artikels
🎯 Was ist RAG – und warum ist es kein Fine-Tuning
Kurze Antwort:
RAG (Retrieval-Augmented Generation) ist eine Methode, um dem Modell Zugriff
auf Ihre Dokumente zu geben, ohne das Modell selbst zu verändern. Vor jeder Anfrage
findet das System relevante Fragmente aus Ihrer Datenbank und fügt sie
in den Kontext ein. Das Modell antwortet basierend auf diesen Fragmenten –
und nicht nur auf dem, was es während des Trainings gelernt hat.
LLMs werden auf Billionen von Tokens aus dem Internet trainiert – aber nicht auf Ihren
internen Dokumenten, nicht auf Ihrer Codebasis und nicht auf den Artikeln,
die Sie letzte Woche geschrieben haben. RAG schließt diese Lücke.
Analogie: Anwalt und Fall
Stellen Sie sich einen erfahrenen Anwalt vor. Er kennt Gesetze, Präzedenzfälle, allgemeine Praxis –
alles, was er über Jahre gelernt hat. Aber wenn ihm ein neuer Fall gegeben wird – antwortet er nicht
aus dem Gedächtnis. Er liest die Fallmaterialien, extrahiert die wichtigsten Fakten,
und erst dann formuliert er eine Position, die sich auf konkrete Dokumente stützt.
Ein LLM ohne RAG ist derselbe Anwalt, der gebeten wird zu antworten,
ohne Zugang zu den Fallmaterialien zu haben. Er wird etwas sagen, aber es wird
eine allgemeine Meinung sein, keine Antwort auf Ihren spezifischen Fall.
RAG gibt ihm diese Materialien.
Warum kein Fine-Tuning
Fine-Tuning ist das erneute Trainieren des Modells mit Ihren Daten. Klingt logisch,
ist aber in der Praxis teuer, langsam und unflexibel. Wenn sich Ihre Dokumente
ändern – müssen Sie erneut trainieren. Wenn Sie einen Fehler in den Daten gemacht haben –
hat das Modell das Falsche "gelernt".
RAG berührt das Modell überhaupt nicht. Dokumente aktualisiert – neu indiziert in Minuten.
Fehler gefunden – in der Quelle behoben. Das Modell bleibt dasselbe.
Deshalb ist RAG für die meisten Aufgaben, bei denen es darum geht, "auf Dokumenten zu antworten",
die richtige Wahl, nicht Fine-Tuning.
RAG vs. Fine-Tuning: Wann was wählen
| Kriterium |
RAG |
Fine-Tuning |
| Implementierungskomplexität |
Niedrig – wenige Tage |
Hoch – Wochen |
| Rechenressourcen |
Minimal – CPU ausreichend |
GPU erforderlich, erhebliche Kosten |
| Wissensaktualisierung |
Neuindizierung – Minuten |
Neues Training – Tage |
| Transparenz |
✔️ Sichtbar, welche Dokumente verwendet wurden |
❌ Schwer zu erklären, woher die Antwort kommt |
| Fehler in den Daten |
Quelle korrigiert – fertig |
Neues Training von Grund auf |
| Geeignet für |
Wissensdatenbank, Dokumente, FAQs, Suche |
Änderung von Stil, Ton, Antwortformaten |
| Nicht geeignet für |
Änderung des Verhaltens des Modells selbst |
Häufig aktualisierte Dokumente |
Wann RAG das Problem nicht löst
RAG ist keine Silberkugel. Es gibt mehrere Szenarien, in denen es nicht hilft:
- ⚠️ Kurze Anfragen (1-2 Wörter) – semantische Suche
bei kurzen Anfragen ist weniger präzise als Stichwortsuche.
Ein Fallback ist erforderlich.
- ⚠️ Frage geht über die Dokumente hinaus – wenn
die Antwort nicht in der Datenbank vorhanden ist, sagt das Modell entweder "Ich weiß es nicht" oder
beginnt zu halluzinieren. Der Prompt muss letzteres explizit verbieten.
- ⚠️ Stil oder Verhalten des Modells ändern –
hier hilft RAG nicht, das ist eine Aufgabe für Fine-Tuning oder
detaillierte System-Prompts.
Fazit des Abschnitts: RAG ist die richtige Wahl, wenn
es darum geht, auf spezifische Dokumente zu antworten, und diese Dokumente
sich ändern oder aktualisiert werden. Fine-Tuning ist erforderlich, wenn das
Verhalten des Modells selbst geändert werden soll, nicht um sein Wissen zu erweitern.
🎯 Wie die Pipeline funktioniert: vom Dokument zur Antwort
Kurze Antwort:
Die RAG-Pipeline ist in zwei unabhängige Phasen unterteilt. Indizierung –
wird einmal oder bei Aktualisierung von Dokumenten durchgeführt:
Dokument → Chunks → Embeddings → Vector Store.
Suche und Generierung – bei jeder Benutzeranfrage:
Frage → Embedding → Similarity Search → Prompt mit Kontext → Antwort.
Wenn man versteht, wo was passiert – wird die Fehlersuche um ein Vielfaches einfacher.
Eines der ersten Dinge, die ich in der Praxis verstanden habe: Das Modell "liest" nie
das gesamte Dokument. Es sieht nur einige
Fragmente, die das System für am relevantesten hält. Die Qualität der Antwort
hängt direkt von der Qualität dieser Auswahl ab.
Phase 1 – Indizierung
Die Indizierung erfolgt einmal – oder nach Zeitplan bei Aktualisierung des Inhalts.
Ziel: menschlichen Text in eine Form umwandeln, die der Vector Store durchsuchen kann.
Schritt 1. Dokument lesen
Eingabeformate: PDF, HTML, Markdown, Plain Text, Webseiten.
Auf diesem Schritt ist es wichtig, reinen Text ohne Markup zu erhalten.
HTML-Tags, PDF-Metadaten, Steuerzeichen – all das ist Rauschen, das die
Qualität der Embeddings verschlechtert. Jsoup für Java, BeautifulSoup für Python –
standardmäßige Bereinigungswerkzeuge.
Schritt 2. Chunking – Aufteilung in Fragmente
Das Dokument wird in kleinere Teile – Chunks – zerlegt. Warum nicht das ganze Dokument speichern?
Zwei Gründe. Erstens haben Embedding-Modelle ein Token-Limit:
nomic-embed-text – 8192 Tokens, all-minilm – 256. Ein Artikel mit 5000 Wörtern
passt einfach nicht hinein. Zweitens ist die Suche bei kleineren Fragmenten präziser:
Wenn der gesamte Artikel als ein Vektor gespeichert wird – mittelt der Vektor alle Themen des Artikels
und wird weniger spezifisch.
Standard: 512 Tokens mit einem Overlap von 50 Tokens. Overlap – ist eine absichtliche Überlappung
zwischen benachbarten Chunks, damit der Gedanke an der Grenze des Fragments nicht abbricht.
Schritt 3. Embeddings
Jeder Chunk wird in einen numerischen Vektor umgewandelt – eine Liste von 768 Zahlen
(für nomic-embed-text). Dieser Vektor kodiert die *Bedeutung* des Textes,
nicht spezifische Wörter. Deshalb werden "schlüsselfertige Webentwicklung"
und "wie man eine Website erstellt" ähnliche Vektoren haben, auch ohne gemeinsame Wörter.
Genau darin liegt der Vorteil der semantischen Suche gegenüber der LIKE-Suche.
Schritt 4. Vector Store
Vektoren und der ursprüngliche Text der Chunks werden in einer Vektordatenbank gespeichert:
pgvector (Erweiterung für PostgreSQL), Chroma, FAISS, Milvus oder eine andere.
Wenn im Projekt bereits PostgreSQL vorhanden ist – ist pgvector die natürliche Wahl:
eine Instanz der Datenbank, nichts Neues zu installieren.
Phase 2 – Suche und Generierung
Diese Phase wird bei jeder Anfrage gestartet und dauert Sekunden.
Der Benutzer gibt eine Frage ein – und nach einigen Schritten erhält er eine Antwort.
Schritt 5. Embedding der Anfrage
Die Frage des Benutzers wird ebenfalls in einen Vektor umgewandelt –
mit demselben Embedding-Modell, das bei der Indizierung verwendet wurde.
Das ist entscheidend: Wenn Sie mit nomic-embed-text indiziert haben,
muss die Anfrage ebenfalls über nomic-embed-text erfolgen.
Unterschiedliche Modelle liefern inkompatible Vektoren – und die Suche wird irrelevant sein.
Schritt 6. Similarity Search
Der Vector Store findet die N nächstgelegenen Vektoren zum Anfragevektor.
"Nächstgelegen" – ist die Kosinus-Ähnlichkeit oder das Skalarprodukt zwischen den Vektoren.
Ergebnis: die Top-5 (oder wie viele Sie angeben) relevantesten Chunks.
Ein Ähnlichkeitsschwellenwert filtert Ergebnisse unterhalb des Ähnlichkeitswerts –
normalerweise beginnt man mit 0,5 und korrigiert anhand von Logs.
Schritt 7. Prompt-Erstellung
Die gefundenen Chunks werden als Kontext in den System-Prompt eingefügt.
Die Qualität dieses Prompts beeinflusst direkt die Qualität der Antwort.
Das Minimum, das im System-Prompt enthalten sein sollte:
Antworte NUR basierend auf dem bereitgestellten Kontext.
Wenn die Antwort nicht im Kontext enthalten ist – sage es ehrlich.
Erfinde keine Informationen, die nicht in den Dokumenten vorhanden sind.
Kontext:
{gefundene Chunks}
Ohne ein explizites Verbot des Erfindens – wird das Modell halluzinieren.
Das ist kein Fehler eines bestimmten Modells, das ist das allgemeine Verhalten von LLMs.
Schritt 8. Antwortgenerierung
Das LLM (Ollama mit llama3.3, Mistral oder einem anderen Modell) generiert eine Antwort
basierend auf dem Kontext aus dem vorherigen Schritt.
Wichtiges Detail: Zeigen Sie dem Benutzer die Quellen – welche spezifischen Artikel
oder Dokumente das System verwendet hat. Das ist Transparenz und eine Möglichkeit,
zu überprüfen, woher das Modell die Informationen hat.
Fazit des Abschnitts: Zwei unabhängige Prozesse –
Indizierung und Suche+Generierung. Die meisten RAG-Probleme treten
entweder beim Chunking (falsche Größe) oder bei der
Similarity Search (falscher Schwellenwert) oder im System-Prompt
(kein Verbot von Halluzinationen) auf. Wir werden jeden im Folgenden detailliert betrachten.
🎯 Tools: LlamaIndex vs. LangChain vs. manueller Ansatz
Kurze Antwort:
Im Jahr 2026 geht die Wahl zwischen LlamaIndex und LangChain nicht um "besser",
sondern darum, was Sie bauen. LlamaIndex ist auf die Arbeit mit Dokumenten spezialisiert
und liefert bessere Suchergebnisse mit weniger Code. LangChain ist für komplexe Agentensysteme,
bei denen RAG eine von mehreren Komponenten ist. Ein manueller Ansatz über Spring AI oder
direkte REST-API – wenn Sie mit Python nicht zufrieden sind oder maximale Kontrolle
über jeden Schritt wünschen.
Eine detaillierte Analyse von 2026 stellt fest:
Der Vergleich "LangChain = Orchestrierung, LlamaIndex = Daten", der von
den meisten Artikeln wiederholt wird – ist bereits veraltet. Beide Frameworks nähern sich an
und decken ähnliche Funktionalitäten ab. Die Wahl hängt nun davon ab,
wo Sie beginnen und was die Grundlage Ihrer Anwendung ist.
LlamaIndex – wenn Dokumente und Suche im Mittelpunkt stehen
LlamaIndex wurde um die Idee aufgebaut, dass das Hauptproblem darin besteht,
LLMs zuverlässig mit Ihren Daten zu verbinden. Alles andere – Agenten, Pipelines,
Orchestrierung – baut auf diesem Fundament auf.
Unabhängige Benchmarks zeigen:
LlamaIndex ist 40% schneller als LangChain bei Document Retrieval Tasks
und hat 2025 eine Genauigkeitssteigerung der Suche um +35% erhalten.
Grund: Eingebaute Abstraktionen für Chunking, Re-Ranking und Context Assembly
sind auf Retrieval abgestimmt – nicht auf allgemeine Pipelines.
Vorteile:
- ✔️ Einfachster Start: 10 Zeilen für funktionierendes RAG
- ✔️ Integriertes Re-Ranking, Hybrid-Suche (semantisch + Stichwort)
- ✔️ Breite Liste von Datenkonnektoren über LlamaHub: PDF, HTML,
Notion, Google Docs, S3, Datenbanken
- ✔️ Flexibles Chunking: SentenceSplitter, TokenTextSplitter,
SemanticSplitter – ändern Sie es mit einer Zeile
- ✔️ Native Integration mit Ollama über separate Pakete
Nachteile:
- ⚠️ Für komplexe Agentensysteme mit vielen externen Tools –
weniger praktisch als LangChain
- ⚠️ Dokumentation weniger vollständig als bei LangChain für untypische Szenarien
Wann wählen: Sie haben Dokumente, PDFs, eine Wissensdatenbank –
Sie müssen Fragen stellen und Antworten erhalten. Blog, FAQ, interne
Dokumentation des Unternehmens, technische Referenz.
LangChain – wenn RAG Teil eines komplexeren Systems ist
LangChain wurde um die Idee aufgebaut, dass der Aufbau mit LLMs ein
Workflow-Problem ist: es gibt Eingabedaten, es gibt Ausgabedaten, dazwischen – Modelle, Tools,
Speicher und externe Quellen, die kombiniert werden müssen.
Im Jahr 2026
bedeutet dies LangGraph – ein gerichteter Graph, bei dem Knoten Funktionen sind
und Kanten Übergänge zwischen Zuständen darstellen. RAG in LangChain – ist eines der Tools
eines Agenten, nicht die zentrale Abstraktion.
Vorteile:
- ✔️ Größtes Ökosystem und Community – 220% Wachstum der GitHub-Sterne
im Jahr 2024
- ✔️ LangGraph für komplexe zustandsbehaftete Agenten mit Verzweigungen und Schleifen
- ✔️ LangSmith – Observability, Tracing, Evaluation out-of-the-box
- ✔️ Multimodale Unterstützung ist stärker als bei LlamaIndex
- ✔️ Besser für Konversationsgedächtnis bei langen Gesprächen
Nachteile:
- ⚠️ Steilere Lernkurve – mehr Konzepte für einfaches RAG
- ⚠️ Für reines Document Retrieval – mehr Code als bei LlamaIndex
- ⚠️ Häufige Breaking Changes: das ursprüngliche LangChain wurde durch LangGraph
für Produktionsszenarien ersetzt
Wann wählen: KI-Agent, der externe APIs aufruft,
Code schreibt, SQL-Abfragen ausführt – und dabei auch Dokumente durchsucht.
RAG ist hier nicht die Hauptaufgabe, sondern eines der Werkzeuge des Agenten.
Manueller Ansatz – maximale Kontrolle ohne Framework
Ollama REST API direkt + jede beliebige Vector DB + eigene Logik.
Genau dieser Ansatz liegt Spring AI für Java zugrunde, wo das Framework
fertige Abstraktionen bereitstellt, Sie aber jedes Detail der Pipeline kontrollieren.
Vorteile:
- ✔️ Volle Kontrolle über jeden Schritt – Chunking, Scoring,
Fallback-Logik
- ✔️ Keine Abhängigkeit von Python – jede Sprache über REST API
- ✔️ Keine Breaking Changes von externen Frameworks
- ✔️ Benutzerdefinierte Logik, die von Frameworks nicht unterstützt wird, kann implementiert werden
Nachteile:
- ⚠️ Mehr Code – Chunking, Batch-Indizierung, Fallback schreiben Sie selbst
- ⚠️ Kein integriertes Re-Ranking und keine Hybrid-Suche
- ⚠️ Mehr Zeit für die Implementierung als mit LlamaIndex
Wann wählen: Java / Spring Boot Projekt (Spring AI),
ungewöhnliche Anforderungen an die Pipeline oder wenn das Framework mehr
Komplexität hinzufügt als Probleme löst.
Auswahlmatrix
| Aufgabe |
Empfehlung |
| Antworten auf PDFs und Dokumenten – einfacher Start |
LlamaIndex |
| Semantische Suche in einem Blog oder einer Wissensdatenbank |
LlamaIndex |
| Interne Unternehmensdokumentation, FAQs |
LlamaIndex |
| KI-Agent, der APIs und Tools aufruft |
LangChain / LangGraph |
| Komplexer Multi-Step-Workflow mit Gedächtnis |
LangChain / LangGraph |
| Java / Spring Boot Projekt |
Spring AI (manueller Ansatz) |
| Benutzerdefinierte Fallback- und Deduplizierungslogik |
Manueller Ansatz |
| Schneller Prototyp in jeder Sprache |
Direkte Ollama REST API |
Kann man kombinieren
Ja – und das ist eine gängige Praxis in der Produktion.
Contabo beschreibt einen typischen Stack von 2026:
LlamaIndex als Knowledge Layer (Indizierung und Suche),
LangChain als Orchestration Layer (Agenten und Workflows)
und n8n oder ein eigener Service als Workflow Engine.
Aber für die meisten Projekte ist ein Framework besser als zwei –
weniger Abhängigkeiten, einfachere Wartung.
Fazit des Abschnitts: Wenn die Aufgabe lautet "auf Dokumenten antworten",
beginnen Sie mit LlamaIndex. Wenn Sie einen komplexen KI-Agenten bauen, bei dem RAG eines
der Werkzeuge ist – LangChain. Wenn Sie Java verwenden oder volle Kontrolle benötigen –
Spring AI oder direkte REST-API zu Ollama.
🎯 Auswahl des Modells für Embeddings: nomic-embed-text und Alternativen
Kurze Antwort:
nomic-embed-text ist die Standardwahl für Ollama: leicht (274 MB),
schnell, Vektor mit 768 Dimensionen. Aber es gibt eine wichtige Einschränkung: es funktioniert schlecht mit kurzen Abfragen und nicht-lateinischen Sprachen. Für ukrainischen Text
und kurze Abfragen ist ein Fallback oder ein anderes Modell erforderlich.
Ein Embedding-Modell ist das Fundament von RAG. Ein schlechtes Embedding-Modell macht
die gesamte Pipeline nutzlos, unabhängig von der Qualität des LLM.
Das habe ich nicht aus der Dokumentation gelernt – sondern als die Abfrage „LLM“
einen irrelevanten Artikel mit einem Score von 0,63 zurückgab
und der richtige Artikel nicht einmal in die Top 5 gelangte.
Was sind Embeddings – eine Analogie zur Fotografie
Stellen Sie sich vor, Sie speichern Fotos in verschiedenen Formaten.
Ein kleines Foto mit 100 × 100 Pixeln – nimmt wenig Platz ein, aber die Details sind verschwommen,
ähnliche Gesichter sind schwer zu unterscheiden. Ein Foto mit 4000 × 3000 – nimmt viel mehr Platz ein,
aber jedes Detail ist klar und einzigartig.
Bei Embeddings gilt die gleiche Logik. Ein Vektor ist ein „Foto“ von Text im numerischen Raum.
Die Vektordimension (384, 768, 1024) ist wie die Auflösung.
Ein größerer Vektor kodiert mehr Details und Nuancen der Bedeutung – und die Suche ist genauer.
Aber ein größerer Vektor nimmt mehr Platz in der Datenbank ein und wird langsamer generiert.
all-minilm mit einem 384er Vektor ist ein JPEG 100 × 100: leicht und schnell,
verliert aber Details. nomic-embed-text mit einem 768er Vektor ist ein JPEG 1920 × 1080:
ein guter Kompromiss. mxbai-embed-large mit einem 1024er Vektor ist ein RAW-Format:
maximale Detailgenauigkeit, kostet aber doppelt so viel RAM.
Und noch ein wichtiges Detail zur Foto-Analogie: Wenn Sie alle Fotos
in einem Format gespeichert haben, können Sie sie nicht mit Fotos in einem anderen Format vergleichen.
Genauso ist es mit Embeddings: Mit welchem Modell Sie indiziert haben – mit demselben
Modell müssen Sie die Abfrage einbetten.
Wenn Sie das Modell wechseln, müssen Sie die gesamte Datenbank neu indizieren.
Vergleich von Embedding-Modellen für Ollama
| Modell |
Größe |
Vektor |
Kontext |
Wann geeignet |
Befehl |
| nomic-embed-text |
274 MB |
768 |
8192 Token |
Standardwahl, lange Dokumente |
ollama pull nomic-embed-text |
| mxbai-embed-large |
669 MB |
1024 |
512 Token |
Hohe Suchgenauigkeit, kurze Chunks |
ollama pull mxbai-embed-large |
| all-minilm |
46 MB |
384 |
256 Token |
Schwache Hardware, Geschwindigkeit wichtiger als Genauigkeit |
ollama pull all-minilm |
Reale Einschränkungen von nomic-embed-text
Aus praktischer Erfahrung bei der Indizierung von über 500 Artikeln in vier Sprachen –
nomic-embed-text hat spezifische Schwächen, die in der offiziellen Dokumentation nicht aufgeführt sind:
- ⚠️ Kurze Abfragen (1-2 Wörter) – die Abfrage „LLM“ gab
einen Score von 0,63 für einen irrelevanten Artikel zurück, und der richtige Artikel kam
nicht einmal in die Top 5. Der Vektorraum des Modells kann kurze einwortige Abfragen nicht gut unterscheiden.
- ⚠️ Nicht-lateinische Sprachen – Ukrainisch und Kyrillisch im Allgemeinen
liefern eine geringere Qualität im Vergleich zu englischem Text.
Die Abfrage „LLM vs RAG in 2026“ findet das Richtige (Score 0,69),
aber eine kurze ukrainischsprachige Abfrage ist bereits ein Problem.
- ⚠️ Gemischter Inhalt – wenn Dokumente in mehreren Sprachen
gleichzeitig vorliegen, sinkt die Suchqualität: die Embeddings von englischem
und ukrainischem Text leben in verschiedenen „Zonen“ des Vektorraums.
Praktisches Fazit: Wann nomic-embed-text ausreicht
nomic-embed-text ist gut geeignet, wenn:
- ✔️ Dokumente hauptsächlich auf Englisch
- ✔️ Abfragen mit 3+ Wörtern (semantische Suche)
- ✔️ Großer Kontext benötigt wird – 8192 Token reichen für lange Artikel
Benötigt Fallback oder Ersatz, wenn:
- ⚠️ Dokumente hauptsächlich in nicht-lateinischen Sprachen
- ⚠️ Kurze Suchanfragen (1-2 Wörter) – fügen Sie Keyword-Fallback hinzu
- ⚠️ Maximale Genauigkeit erforderlich ist – erwägen Sie mxbai-embed-large
Fazit des Abschnitts: Die Wahl des Embedding-Modells ist ein Kompromiss
zwischen Genauigkeit, Größe und Geschwindigkeit – wie die Wahl des Fotoformats und der Auflösung.
nomic-embed-text ist ein guter Start. Aber kennen Sie seine Grenzen
und testen Sie immer mit echten Abfragen Ihrer Zielgruppe,
bevor Sie davon ausgehen, dass die Suche „funktioniert“.
🎯 Wichtige Entscheidungen bei der Implementierung von RAG – und was zu vermeiden ist
Kurze Antwort:
Universeller funktionierender Code für RAG existiert nicht – jedes Projekt hat seine eigene
Architektur, seine eigene Sprache, sein eigenes Speichermodell und seine eigenen Suchanforderungen.
Aber es gibt einige Entscheidungen, die in jedem RAG-Projekt getroffen werden müssen –
und typische Fallstricke bei jedem davon.
Tutorials zeigen, wie man RAG in 10 Minuten startet.
Die Produktion zeigt, dass Sie die meiste dieser Zeit damit verbringen werden,
Probleme zu lösen, die im Tutorial nicht vorhanden sind.
Entscheidung 1 – Wie Dokumente gelesen und bereinigt werden
Unabhängig von Sprache und Framework – am Eingang gibt es „rohen“ Text.
PDF enthält Kopf- und Fußzeilen, Seitenzahlen, Formatierungsartefakte.
HTML enthält Tags, Attribute, JavaScript, Werbeblöcke.
All dieser Lärm gelangt in die Embeddings und reduziert die Suchqualität.
Was im Voraus entschieden werden muss:
- ✔️ Welches Format ist das primäre und wie wird es bereinigt
- ✔️ Muss die Struktur (Überschriften, Abschnitte) beibehalten werden
oder reicht einfacher Text aus
- ✔️ Was tun mit leeren oder sehr kurzen Dokumenten
Typischer Fallstrick: Die Bereinigung am Anfang ignorieren – und Embeddings erhalten,
bei denen 30 % des Inhalts „Copyright 2024“ und „Seite 1 von 15“ sind.
Entscheidung 2 – Chunk-Größe und Aufteilungsstrategie
Es gibt keine richtige Chunk-Größe für alle Fälle.
512 Token sind Standard für Artikel. 256 für technische Dokumentation,
wo jeder Absatz unabhängig ist. 1024, wenn es wichtig ist, den Kontext
zwischen den Absätzen zu erhalten.
Was entschieden werden muss:
- ✔️ Nach Token oder nach Sätzen aufteilen – unterschiedliche Ergebnisse
an den Chunk-Grenzen
- ✔️ Welcher Überlappungsgrad benötigt wird – 0, wenn Chunks unabhängig sind,
50-100 Token, wenn Gedanken zwischen den Absätzen übergehen
- ✔️ Müssen Metadaten in jedem Chunk gespeichert werden –
Titel, URL, Kategorie, Locale – zur späteren Filterung
Typischer Fallstrick: Die Chunk-Größe einmal festlegen und nie wieder überprüfen.
Überprüfen Sie die tatsächlichen Chunks nach der Aufteilung – und Sie werden sehen, wo die Gedanken abbrechen.
Entscheidung 3 – Chunk-Identifikatoren
Es scheint eine Kleinigkeit zu sein – wird aber bei der Neuindizierung kritisch.
Wenn bei jeder Indizierung zufällige UUIDs verwendet werden –
sammelt sich die Datenbank mit Duplikaten. Nach einem Monat kann ein Dokument
durch 10 Versionen derselben Chunks repräsentiert werden.
Die richtige Entscheidung ist eine deterministische ID basierend auf der document_id und der fortlaufenden Nummer des Chunks.
Bei der Neuindizierung erhält derselbe Chunk dieselbe ID und wird überschrieben,
anstatt dupliziert zu werden. Wie das implementiert wird – in Java über
UUID.nameUUIDFromBytes(), in Python über hashlib.md5().
Die konkrete Implementierung hängt vom Stack ab – das Prinzip ist dasselbe.
Entscheidung 4 – Strategie zur Aktualisierung des Index
Wie wird bestimmt, was neu indiziert werden muss?
Zwei Ansätze:
- ✔️ Zeitstempelbasiert: Speichern Sie
indexed_at
und neu indizieren, wo updated_at > indexed_at.
Einfach und zuverlässig – aber es gibt einen Haken:
wenn @PreUpdate oder ein Trigger updated_at
bei saveAll() aktualisiert und indexed_at sofort nach dem Speichern veraltet ist. Lösung: Setzen Sie indexed_at
auf eine kurze Zukunft – now() + 10 Sekunden.
- ✔️ Hash-basiert: Speichern Sie einen Hash des Inhalts und neu indizieren
nur, wenn sich der Hash geändert hat. Genauer, aber schwieriger zu implementieren.
Entscheidung 5 – Batch-Indizierung
Der Versuch, 500 Dokumente in einer Anfrage zu indizieren, endet
entweder mit einem Timeout von Ollama oder mit einem OOM. Batch von 10-20 Dokumenten –
und bei einem Absturz machen Sie dort weiter, wo Sie aufgehört haben,
und nicht von vorne. Deshalb ist indexed_at wichtiger,
als es scheint – es ermöglicht dem Scheduler, dort anzuknüpfen, wo er abgestürzt ist.
Entscheidung 6 – LAZY-Loading und Transaktionen
Wenn Sie ein ORM (JPA, SQLAlchemy, ActiveRecord) verwenden –
seien Sie vorsichtig mit lazy-geladenen Beziehungen während der Indizierung.
Der Zugriff auf post.getTranslations() außerhalb einer Transaktion
führt zu einer LazyInitializationException in JPA oder
einem DetachedInstanceError in SQLAlchemy.
Lösung: JOIN FETCH in der Abfrage oder explizites Laden
von allem Notwendigen innerhalb der Transaktion.
Was zu vermeiden ist – kurz
- ❌ Beginnen Sie nicht mit einem „funktionierenden Beispiel aus einem Tutorial“ direkt in der Produktion –
es gibt kein Fallback, keine Batches, keine Idempotenz.
- ❌ Ignorieren Sie die Textbereinigung vor der Indizierung nicht.
- ❌ Verwenden Sie keine zufälligen UUIDs für Chunks, wenn Sie eine Neuindizierung planen.
- ❌ Legen Sie den Schwellenwert nicht für immer fest – protokollieren Sie den Score
und passen Sie ihn bei echten Abfragen an.
- ❌ Glauben Sie nicht, dass Vektorsuche Keyword-Suche vollständig ersetzen wird –
für kurze Abfragen ist ein Fallback erforderlich.
- ❌ Vergessen Sie nicht, dass die Änderung des Embedding-Modells eine vollständige Neuindizierung erfordert.
Fazit des Abschnitts: RAG ist kein „Kopieren und Ausführen“.
Es sind sechs architektonische Entscheidungen, von denen jede ihre Fallstricke hat.
Treffen Sie diese bewusst vor Beginn der Implementierung – und Sie sparen
von mehreren Stunden bis zu mehreren Tagen Debugging.
🎯 Produktionsmuster: Was in Tutorials nicht steht
Kurze Antwort:
Der Unterschied zwischen „Hello World“ RAG und Produktions-RAG sind vier Muster:
Fallback auf Keyword-Suche, idempotente Indizierung,
Deduplizierung von Ergebnissen und Batch-Verarbeitung.
Keines davon wird in grundlegenden Tutorials erwähnt.
Jedes davon entdecken Sie durch ein reales Problem.
Ich habe alle vier Muster nicht durch Dokumentation entdeckt –
sondern durch konkrete Vorfälle in der Produktion.
Fallback – als die Abfrage „Spring“ irrelevante Ergebnisse lieferte.
Idempotenz – als nach einem Monat Arbeit des Schedulers
ein Artikel 47 Mal in der Datenbank war.
Deduplizierung – als die Top-5-Ergebnisse 4 Chunks aus demselben Artikel enthielten.
Batch – als Ollama bei 500 Dokumenten hängen blieb.
Muster 1 – Fallback: Vektor → Keyword
Vektorsuche basiert auf semantischer Ähnlichkeit.
Sie findet gut „schlüsselfertige Webentwicklung“ für die Abfrage „wie man eine Website erstellt“.
Aber bei der Abfrage „Spring“ oder „RAG“ – verschwimmt die Ähnlichkeit im gesamten
Vektorraum und die Genauigkeit sinkt.
Eine Regel, die in der Praxis funktioniert: Abfragen mit 1-2 Wörtern
an die Keyword-Suche leiten, 3+ Wörter – an die Vektorsuche.
Wenn die Vektorsuche ein leeres Ergebnis liefert – Fallback auf Keyword.
Wenn die Vektorsuche mit einem Fehler abstürzt – Fallback auf Keyword.
Der Benutzer bemerkt den Unterschied nicht, erhält aber immer eine Antwort.
Die Implementierung hängt vom Stack ab – aber das Prinzip ist unveränderlich:
zwei Anbieter, eine Fassade, die entscheidet, welche verwendet werden soll,
und ein automatischer Übergang zwischen ihnen.
Muster 2 – Idempotente Indizierung
Der Scheduler startet die Indizierung jede Nacht.
Wenn bei jedem Start zufällige UUIDs für Chunks generiert werden –
nach einem Monat wird derselbe Artikel durch 30 Versionen derselben Chunks repräsentiert.
Die Suche liefert Duplikate, die Qualität sinkt, die Datenbank wächst grundlos.
Lösung: eine deterministische ID basierend auf der Dokumenten-ID
und der fortlaufenden Nummer des Chunks. Bei der Neuindizierung erhält derselbe Chunk
dieselbe ID und wird überschrieben – anstatt als neuer Eintrag hinzugefügt zu werden.
Die konkrete Implementierung hängt von der Sprache ab – in Java ist es
UUID.nameUUIDFromBytes(),
in Python – hashlib.md5() über uuid.UUID(bytes=...).
Das Prinzip ist dasselbe.
Muster 3 – Deduplizierung von Ergebnissen
Vektorsuche liefert Top-N Chunks – nicht Top-N Dokumente.
Wenn ein Artikel gut zur Abfrage passt – kann er 4 von 5 Chunks in den Top 5 liefern. Der Benutzer erhält vier Links
zur selben Seite.
Lösung: Nach Erhalt der Ergebnisse – Deduplizierung nach document_id.
Für jedes Dokument behalten Sie nur den Chunk mit dem höchsten Score.
Ergebnis: Die Top 5 enthalten immer 5 verschiedene Dokumente,
nicht 5 Fragmente desselben.
Wichtig: Die Metadaten jedes Chunks müssen die document_id enthalten –
ohne diese ist eine Deduplizierung nicht möglich. Denken Sie über die Metadatenstruktur
nach, bevor Sie mit der Indizierung beginnen.
Muster 4 – Batch-Indizierung mit Wiederherstellung
Ollama verarbeitet Embeddings sequenziell über CPU oder GPU.
Eine Anfrage für 500 Dokumente gleichzeitig – das ist entweder ein Timeout,
oder ein OOM, oder einfach ein Hängenbleiben ohne Fehler.
Lösung: Batch von 10-20 Dokumenten. Aber wichtiger ist etwas anderes –
nach jedem Batch sofort indexed_at
für die verarbeiteten Dokumente speichern. Wenn der Prozess bei Batch 7 von 50 abstürzt –
beim nächsten Start greift der Scheduler bei Batch 8 an,
und beginnt nicht von vorne. Das ist der Unterschied zwischen „gestartet und hoffen“
und zuverlässiger Indizierung.
Fazit des Abschnitts: Vier Muster – Fallback,
Idempotenz, Deduplizierung und Batch mit Wiederherstellung –
das ist der Unterschied zwischen einem Prototyp, der auf einer Demo funktioniert,
und einem System, das monatelang in der Produktion läuft.
Die Implementierung ist in jedem Stack anders – die Prinzipien sind für alle gleich.
🎯 Typische Probleme: Chunking, Threshold, Halluzinationen
Drei Klassen von Problemen in RAG – und alle drei treten nur bei echten Anfragen auf,
nicht bei synthetischen Tests. Falsches Chunking: Das Modell erhält Fragmente
ohne Kontext. Falscher Threshold: entweder zu viel Rauschen oder nichts gefunden.
Halluzinationen: Das Modell erfindet auch bei vorhandenem Kontext – aufgrund eines schwachen Prompts
oder irrelevanter Chunks, die es dennoch in die Top-Ergebnisse geschafft haben.
Das Wichtigste, was ich verstanden habe: Die meisten RAG-Probleme
sind ohne Score-Logging unsichtbar. Wenn du nicht siehst,
welchen Ähnlichkeitswert jedes Ergebnis zurückgibt –
kannst du nicht diagnostizieren, warum die Suche schlechte Antworten liefert.
Füge sofort Score-Logging hinzu – und spare Stunden beim Debugging.
Problem 1 – Chunking: Wie man erkennt, dass etwas schief läuft
Symptom: Das Modell liefert Antworten, die teilweise richtig erscheinen –
es gibt eine Verbindung zur Frage, aber die Details sind falsch oder abgeschnitten.
Ursache: Die Chunks sind an ungünstigen Stellen geteilt, und der Gedanke bricht am Rand des Fragments ab.
Diagnose: Gib nach dem Aufteilen einige echte Chunks aus und lies sie.
Wenn ein Chunk mitten im Satz beginnt oder endet – ist die Größe oder die Aufteilungsstrategie falsch.
- ✔️ Kurze Dokumente, Blogartikel – 512 Token, Overlap 50
- ✔️ Technische Dokumentation mit langen Abschnitten – 1024 Token, Overlap 100
- ✔️ Code – 256-512 Token, nach Funktionen aufteilen, nicht nach Zeilen
- ✔️ Overlap – spare nicht: 50-100 Token Überlappung garantieren,
dass der Gedanke am Chunk-Rand nicht verloren geht
Problem 2 – Ähnlichkeitsschwelle (Similarity Threshold): Wie man den richtigen Wert findet
Symptom A: Das Modell antwortet selbstbewusst, aber falsch –
der Threshold ist zu niedrig, irrelevante Chunks gelangen in den Kontext.
Symptom B: Das Modell sagt ständig „nicht gefunden“, selbst bei offensichtlichen Fragen –
der Threshold ist zu hoch, nichts besteht den Filter.
Diagnose: Logge den Score jedes Ergebnisses – und schaue dir die Verteilung an.
Wenn richtige Ergebnisse einen Score von 0,55-0,65 haben – schneidet ein Threshold von 0,7 sie alle ab.
Wenn irrelevante Ergebnisse einen Score von 0,55 haben – lässt ein Threshold von 0,5 Rauschen durch.
- ✔️ Startpunkt: 0,5 – und nach den Logs echter Anfragen anpassen
- ✔️ Kurze Anfragen (1-2 Wörter) – auf 0,4 reduzieren oder besser einen Fallback verwenden
- ✔️ Lange semantische Anfragen – 0,65-0,7 liefert ein saubereres Ergebnis
- ✔️ Wenn alle Ergebnisse unter dem Schwellenwert liegen – gib „nicht gefunden“ zurück
anstatt eines leeren Kontexts
Problem 3 – Halluzinationen auch mit Kontext
Symptom: Das Modell liefert eine selbstbewusste Antwort, die keiner
der bereitgestellten Chunks entspricht – oder kombiniert Fakten aus verschiedenen Quellen falsch.
Die Ursache liegt meist nicht im Modell – sondern im Prompt oder darin,
dass irrelevanter Kontext es dennoch in die Top-Ergebnisse geschafft hat.
Drei Schutzebenen:
- ✔️ Strenger System-Prompt – explizites Verbot des Erfindens:
„Antworte NUR auf Basis des bereitgestellten Kontexts.
Wenn keine Antwort vorhanden ist – sage es ehrlich.
Kombiniere keine Informationen aus verschiedenen Quellen, wenn sie sich widersprechen.“
- ✔️ Score-basierter Filter – wenn der maximale Score
unter den Ergebnissen unter 0,5 liegt, übergib den Kontext überhaupt nicht an die LLM.
Gib „nicht gefunden“ zurück – eine ehrliche Antwort ist besser als eine selbstbewusste Halluzination.
- ✔️ Quellen anzeigen – eine Liste von Artikeln oder Dokumenten,
aus denen die Antwort stammt. Der Benutzer kann selbst überprüfen
und melden, wenn etwas nicht stimmt.
Fazit des Abschnitts: Alle drei Probleme werden
gleich diagnostiziert – durch Score-Logging und das Lesen echter Chunks,
die in den Kontext gelangen. Füge dies vom ersten Tag an hinzu –
und die meisten Fragen „warum liefert RAG schlechte Antworten“
werden eine offensichtliche Antwort erhalten.
❓ Häufig gestellte Fragen (FAQ)
Wird eine GPU für RAG mit Ollama benötigt?
Nein. Eine GPU beschleunigt die Antwortgenerierung und Embeddings, ist aber nicht zwingend erforderlich.
Auf einer CPU werden Embeddings über nomic-embed-text langsamer generiert,
sind aber für den Produktionseinsatz mit moderater Last durchaus machbar.
Auf Apple Silicon (M1/M2/M3) – schnell, auch ohne dedizierte GPU.
Mehr Details darüber, welche Modelle auf eingeschränkter Hardware wirklich laufen –
Ollama auf 8 GB RAM: Welche Modelle funktionieren im Jahr 2026.
Wie viele Dokumente können indiziert werden?
Es gibt keine Beschränkungen – es hängt von der Größe des Vector Stores und des RAMs ab.
pgvector kommt problemlos mit Millionen von Vektoren zurecht.
In der Praxis für einen Blog mit 500 Artikeln – das sind ca. 2500 Chunks à 512 Token,
nimmt wenige MB in PostgreSQL ein. Die Generierung von Embeddings über Ollama
bei diesem Umfang dauert 15-30 Minuten auf einer CPU – akzeptabel für einen nächtlichen Scheduler.
RAG oder normale Volltextsuche?
Nicht „oder“, sondern „und“. RAG ist besser für semantische Anfragen mit 3+ Wörtern, bei denen der Inhalt wichtig ist –
„wie optimiere ich Abfragen in PostgreSQL“ findet einen Artikel über Indizes,
auch ohne exakte Wortübereinstimmung. Die Volltextsuche ist besser für kurze Anfragen
(1-2 Wörter), Namen und exakte Übereinstimmungen. Die optimale Strategie ist –
Vektorsuche mit automatischem Fallback auf FTS.
Wie aktualisiert man den Index bei Änderungen an Dokumenten?
Speichere indexed_at für jedes Dokument und starte
die Neuindizierung, wo updated_at > indexed_at.
Eine deterministische ID über einen Hash ermöglicht das Überschreiben von Chunks ohne Duplikate.
Wichtiger Hinweis: Wenn die ORM updated_at automatisch aktualisiert
bei saveAll() – setze indexed_at
auf eine kurze Zeit in der Zukunft, damit der Scheduler nicht jedes Mal alles neu indiziert.
Welches Ollama-Modell für RAG wählen?
Für Embeddings – nomic-embed-text als Standard, mxbai-embed-large
wenn höhere Genauigkeit benötigt wird. Für die Generierung von Antworten – llama3.3:8b
auf 8 GB RAM oder qwen2.5:14b, wenn 16 GB vorhanden sind.
Ein vollständiger Vergleich der Modelle mit Benchmarks und Empfehlungen für Aufgaben –
Welches Ollama-Modell wählen im Jahr 2026: Vergleich von Llama, Qwen, DeepSeek und Mistral.
Gibt es Java-Lösungen für RAG mit Ollama?
Ja – Spring AI mit nativer Unterstützung für Ollama und pgvector.
Ein reales Fallbeispiel für die Implementierung von RAG für einen Blog mit Spring AI mit spezifischen
Fehlern und Lösungen, die nicht in der Dokumentation stehen –
im Artikel Wie ich RAG für webscraft.org gebaut habe:
Spring AI + pgvector + reale Erfahrung.
Womit anfangen, wenn man noch nie mit Ollama gearbeitet hat?
Mache dich zuerst mit der Plattform selbst vertraut – was ist Ollama,
wie ist es aufgebaut und welche Aufgaben löst es.
Was ist Ollama und warum Entwickler massenhaft auf lokales KI umsteigen im Jahr 2026 –
ein Überblick ohne Fachjargon, mit dem man bequem beginnen kann.
Danach wird RAG zum logischen nächsten Schritt.
✅ Schlussfolgerungen
RAG ist eine dieser Technologien, die bis zur ersten Implementierung komplex erscheinen
und danach offensichtlich sind. Die Pipeline ist konzeptionell einfach: Dokument → Chunks →
Embeddings → Suche → Antwort. Die Komplexität beginnt in den Details –
und die meisten dieser Details findest du nicht in der Dokumentation,
sondern durch reale Vorfälle im Produktivbetrieb.
Was ich aus der Implementierung für den Blog mitgenommen habe:
- ✔️ Beginne mit nomic-embed-text – aber logge sofort den Score
bei echten Anfragen. Für nicht-lateinische Sprachen und kurze Anfragen
ist ein Fallback erforderlich – das erfährst du nicht aus der Dokumentation.
- ✔️ Determinierte UUID für Chunks – keine zufällige.
Ohne dies vervielfacht die Neuindizierung Duplikate und du verstehst nicht sofort, warum.
- ✔️ Fallback auf Keyword-Suche – Vektorsuche
ersetzt keine normale Suche, sie ergänzt sie.
- ✔️ Batch von 10-20 Dokumenten mit Speicherung von indexed_at –
damit bei einem Absturz von der Stelle fortgefahren werden kann, an der aufgehört wurde, und nicht von vorne.
- ✔️ Strenger System-Prompt – ohne explizites Verbot
des Erfindens wird das Modell halluzinieren. Das ist kein Bug eines bestimmten Modells.
Mit Ollama ist der gesamte Stack kostenlos und läuft lokal –
kein einziges Dokument geht in die Cloud. Für einen Blog, interne Dokumentation
oder eine unternehmensinterne Wissensdatenbank ist dies die richtige Architektur.
Wenn du mit Java und Spring Boot arbeitest – der nächste Artikel handelt genau davon.
Ein reales Fallbeispiel für die Implementierung von RAG für webscraft.org mit Spring AI + pgvector:
welche Fehler ich gemacht habe, welche Fallstricke ich gefunden habe und was ich anders machen würde –
Wie ich RAG für webscraft.org gebaut habe: Spring AI + pgvector + reale Erfahrung.
Wenn du noch nicht mit Ollama vertraut bist –
beginne mit dem Überblick über Ollama 2026.
📎 Quellen
- LlamaIndex: Introduction to RAG – offizielle Dokumentation
- Real Python: LlamaIndex in Python — A RAG Guide – praktisches Tutorial
- Medium: LlamaIndex for Beginners 2025 – von Null bis Produktion
- DEV Community: RAG mit LlamaIndex, ChromaDB und Ollama
- Prem AI: LangChain vs LlamaIndex 2026 — Production RAG Comparison
- Contabo: LlamaIndex vs LangChain — Which One to Choose in 2026
- Ollama: nomic-embed-text – Eigenschaften des Embedding-Modells
- Ollama: mxbai-embed-large – alternatives Embedding-Modell
Ключові слова:
RAGRetrieval-Augmented Generationкраулинг AIGoogle AI OverviewsPerplexitySEO під RAG