Chunking-Strategien im RAG-Vergleich: Alternativen, Kompromisse und Beispiele
Vergleich von Chunking-Strategien in RAG
Chunking ist der wichtigste unterschätzte Hyperparameter in Retrieval ‑ Augmented Generation (RAG): Er bestimmt still und leise, was Ihr LLM “sieht”, wie teuer die Verarbeitung wird, und wie viel vom LLM-Kontextfenster pro Antwort verbraucht wird.
Dieser Artikel behandelt Chunking als ein Ingenieur-Optimierungsproblem: Ziele definieren, Strategie wählen, messen und iterieren.
Wenn Sie neu im RAG-Modell sind, beginnen Sie mit dem Hauptartikel Retrieval-Augmented Generation (RAG) Tutorial: Architecture, Implementation, and Production Guide.

TL;DR (Executive summary)
RAG-Systeme suchen Chunks, nicht Dokumente. Chunking definiert daher die Einheit der Suche, die Einheit der Einbettungskosten und die Einheit der Beweise, die Sie zeigen oder zitieren können. In der ursprünglichen RAG-Formulierung versorgt die Suche mit Abschnitten, die Grenzen der Abschnitte sind effektiv die Grenzen der Chunks.
Eine gute Chunking-Strategie verfolgt eine Pareto-Front zwischen: Suchqualität (Erinnerung/Präzision der Beweise), Kohärenz (Chunks müssen interpretierbar sein) und Kosten (Einbettung, Speicher und Abfrageverzögerung). Es gibt keine global optimale Chunk-Größe oder Methode, und Produktions-Systeme verwenden routinemäßig mehrere Strategien (z. B. struktur-aware Chunking für PDFs + semantisch-aware Splits für Prosa + AST-Chunking für Code).
Für die meisten „Dokumentation QA“ und interne Wissensdatenbanken ist eine struktur-respektierende rekursive Aufsplittung mit moderatem Überlappung (um Randverlust zu reduzieren) ein sicherer Standard, unterstützt von einer
vektorisierten Speicherung
mit Metadaten-Filterung und optionaler Neuanordnung. LangChain’s RecursiveCharacterTextSplitter ist eine gängige Implementierung dieses hierarchischen-Trenner-Konzepts; Überlappung besteht speziell, um Informationsverlust zu reduzieren, wenn relevanter Kontext an Grenzen geschnitten wird.
Wenn Dokumente eine starke Struktur haben (PDFs mit Überschriften, Tabellen, Listen, Bildunterschriften), kann elementbasiertes / struktur-aware Chunking die Leistung von Token-Zählungssplitten übertreffen und weniger Chunks erzeugen. Eine 2024-Studie zu SEC-Berichten fand heraus, dass elementtyp-basiertes Chunking die Ergebnisse von RAG verbessert und die Anzahl der Chunks (und damit der Vektoren) um etwa die Hälfte im Vergleich zu struktur-unkritischen Methoden reduziert – was die Indizierungskosten und möglicherweise die Abfragespeed erhöht.
Wenn Sie mehr Rechenleistung aufwenden können, kann semantisches Chunking (Trennung an Themenwechseln durch Einbettungsähnlichkeit) die Retrievalgenauigkeit für narrative Texte und gemischte Themenseiten erheblich verbessern. Ältere Themensegmentierungs-Algorithmen wie TextTiling zeigen den allgemeinen Prinzip: starke Vokabular-/semantische Wechsel sind gute Grenzkanidaten.
Für sehr lange, intern vernetzte Materialien (Richtlinien, RFCs, Standards, große Handbücher), kann hierarchisches Chunking + hierarchische Suche/Verknüpfung (Eltern/Kinderknoten) größeren kontinuierlichen Kontext auf Anfrage wiederherstellen. LlamaIndex’s hierarchischer Knotenparser erzeugt grob-zu-fein Chunk-Hierarchien, und der AutoMergingRetriever kann Blattknoten in Elternknoten bei der Suche verknüpfen, wenn genügend verwandte Kinder abgerufen werden.
Chunking-Ziele und Kompromisse
Chunking ist nicht einfach „Text aufteilen, damit er in ein Einbettungsmodell passt“. Es steuert mehrere nachfolgende und operative Verhaltensweisen.
Suchgranularität vs. Suchrauschen. Kleine Chunks erhöhen die Chance, dass der genaue Satz, der eine Antwort enthält, abgerufen wird (höhere potenzielle Erinnerung bei festem top-k). Aber sie erzeugen auch mehr Vektoren, was die Indexgröße erhöht und manchmal „nahe Matches“ hervorruft, die semantisch ähnlich sind, aber nicht tatsächlich evidentiell (geringere Präzision). Dichte Retriever wie DPR wurden umgebaut, um Passage effektiv für QA abzurufen, was zeigt, dass Passage-Grenzen für die End-zu-End-QA-Leistung wichtig sind.
Kontextkohärenz vs. Grenzverlust. Kohärente Chunks helfen dem LLM, richtig zu denken und Halluzinationen zu reduzieren, indem sie vollständigen lokalen Kontext (Definitionen, Einschränkungen, Voraussetzungen) bereitstellen. Überlappung reduziert Grenzverlust, aber erzeugt duplizierten Text, was zu redundanten Suchergebnissen und vergrößerten Promptlängen führen kann, wenn nicht dedupliziert/verknüpft wird.
Einbettungs- und Indexkosten. Einbettungskosten sind typischerweise proportional zu den eingegebenen Token und die Verarbeitungszeit skaliert mit der Anzahl der Chunks (plus Vektor-Datenbank-Schreib-Überlastung). Für OpenAI-Einbettungen haben Anfragen eine pro Eingabe Maximaltokenlimit (8192 Token für alle Einbettungsmodelle) und ein Maximalgesamttokenlimit, das über alle Eingaben pro Anfrage summiert wird (300.000 Token). Für große Corpora kann die Batch-API die Kosten um ca. 50 % reduzieren mit einer asynchronen, 24-Stunden-Umstellung – nützlich für Rückverfolgungen und periodische Neuanordnungen.
Größe des Vektorindex, RAM und Latenz. Mehr Chunks bedeutet mehr Vektoren und potenziell mehr Speicher und langsammere Abfragen (je nach Indexart). FAISS stellt explizit den Indexdesign als einen Satz von Kompromissen zwischen Suchzeit, Suchqualität und Speicher pro indiziertem Vektor dar; es bietet auch GPU-Implementierungen für schnelle exakte und ungefähre Suche.
Downstream LLM Promptlänge / Kontextfensterverwendung. Die Retriever-Ausgabe wird zum Promptbudget. Eine Chunking-Strategie, die konsistent „genug“ Kontext abruft, kann die Antwortqualität verbessern und Kosten reduzieren. Umgekehrt vergrößern Überlappung und zu große Chunks die Promptlänge. In der Praxis justieren Sie oft: (Chunkgröße, Überlappung, top-k, Neuanordnung/Verknüpfung) zusammen.
Aktualisierungs-/Verarbeitungskosten und Deduplizierung. Chunking beeinflusst, wie teuer es ist, Daten zu aktualisieren. Kleine Chunks machen partielle Updates günstiger (Sie können nur den geänderten Abschnitt neu einbetten), aber sie machen Deduplizierung schwieriger, wenn sich überlappende oder nahezu identische Chunks verbreiten.
Wo Chunking im RAG-Workflow situiert ist

Chunking-Strategien und Alternativen
Unten sind die Haupt-Chunking-Familien, die Sie in modernem RAG begegnen werden. In der Praxis kombinieren Sie oft zwei: struktur-first Chunking (Respektierung von Dokumentgrenzen) plus token-budget Enforcement (sicherstellen, dass Chunks in Ihr Einbettungs- und Promptbudget passen).
Fixed-size Chunking
Was es ist. Text in gleich große Blöcke aufteilen, entweder durch Zeichen oder Token.
Warum es existiert. Es ist einfach, schnell, vorhersehbar und einfach parallelisierbar. Es ist auch die einfachste Strategie für Streaming-Verarbeitung, bei der Sie keine vollständigen Dokumentkontexte haben.
Wo es versagt. Es ignoriert Grenzen (Sätze, Abschnitte, Codeblöcke), sodass es Definitionen brechen oder „Frage/Antwort-Paare“ über Chunks teilen kann, was die Suchfehler erhöht.
Betriebsprofil. Niedrigste Verarbeitungskomplexität; vorhersehbare Chunkzahl; einfachste Caching. Aber Sie benötigen normalerweise Überlappung (siehe unten), um Grenzverlust zu vermeiden.
Überlappung Chunking
Was es ist. Jede Strategie, bei der aufeinanderfolgende Chunks eine feste Überlappungsregion teilen (z. B. 10–20 % der Chunkgröße). Überlappung ist in vielen Frameworks Standard, da sie den Informationsverlust reduziert, wenn der Kontext geteilt wird.
Warum es wichtig ist. Überlappung ist effektiv eine „weiche Grenze“ – sie ermöglicht der Suche, einen Fakt zu erfassen, der eine Grenze überschreitet.
Kosten und Fallen. Mehr Token eingebettet; mehr duplizierter Text im Index; höheres Risiko, mehrere fast identische Chunks abzurufen, es sei denn, Sie deduplizieren bei der Suche (z. B. durch Zusammenführung nach Quellverschiebungen oder MMR verwenden).
Satz- und Absatz-basiertes Chunking
Was es ist. Text an Satz- oder Absatzgrenzen aufteilen und dann Sätze/Absätze in Chunks packen, bis ein Tokenbudget erreicht wird.
Warum Ingenieure es mögen. Es verbessert die Kohärenz für natürliche Sprache und ist robust für Dokumente mit konventionellen Zeichen und Abständen.
Tooling. NLTKs sent_tokenize() verwendet standardmäßig Punkt-Satzgrenzerkennung, und spaCy bietet regelbasierte Satzgrenzerkennungstools wie Sentencizer (nützlich, wenn Sie Satzspaltung ohne vollständiges Abhängigkeitsmodell benötigen).
Fehlmodi. Nichtstandardisierte Zeichen (Protokolle, Chat-Transkripte), Tabellen, Code und Aufzählungslisten können Annahmen der Satzsegmentierung brechen.
Gleitfenster-Chunking
Was es ist. Chunks mit einer festen Fenstergröße und einem Schritt (Schrittweite) erstellen. Dies ist die „systematische Überlappung“-Version des Chunking.
Wenn es gut ist. Zeitreihentext, Transkripte, Chat-Protokolle, Meeting-Minuten – alles, bei dem relevante Fakten über lokale Nachbarschaften verteilt sein können und eine robuste Erinnerung gewünscht ist.
Wenn es schlecht ist. Es verstärkt Redundanz und kann bei Skalierung teuer sein. Es neigt auch dazu, redundante Fenster abzurufen, es sei denn, dedupliziert.
Rekursives / Trenner-Hierarchie-Chunking
Was es ist. Mit großen „natürlichen“ Trennern (z. B. \n\n für Absätze) beginnen und rekursiv in kleinere Einheiten (Sätze, Leerzeichen) aufteilen, wenn notwendig, um unter einem Budget zu bleiben. LangChain beschreibt dieses Verhalten explizit: ein rekursiver Aufsplitterer versucht, größere Einheiten intakt zu lassen und fällt erst auf kleinere Trenner zurück, wenn eine Einheit immer noch die Chunkgröße überschreitet.
Warum es ein starker Standard ist. Es respektiert die Struktur ohne komplexe Dokumentverarbeitung zu erfordern. Es ist ein praktischer Sweet Spot für Markdown, HTML-as-Text und Dokumentation.
Schlüssel-Feinabstimmung. chunk_size, chunk_overlap und die length_function (Zeichen vs. Token), plus benutzerdefinierte Trenner für mehrsprachige Codebasen.
Semantisches (einbettungsbewusstes) Chunking
Was es ist. Themenwechsel mit semantischen Darstellungen (Einbettungen) erkennen und trennen, wo Ähnlichkeit abfällt. Dies spiegelt klassische Segmentierungsideen wie TextTiling wider, die sich auf Wechseln lexikalischer Kohärenz zur Suche von Unterthemen-Grenzen konzentrieren.
Warum es die Größen-basierte Chunking übertreffen kann. Sie stoppen nicht an willkürlichen Tokenzahlen, sondern richten Chunks an Themen-Grenzen aus – oft verbessert dies die Retrievalgenauigkeit für mehrthemen Dokumente (Blogposts, Entwurf-Dokumente, Tickets, Vorfälle).
Kosten. Sie benötigen möglicherweise zusätzliche Einbettungen während des Chunking (Satz- oder Absatzniveau) vor den endgültigen Chunk-Einbettungen. Das kann die Einbettungsaufgaben verdoppeln oder verdreifachen, es sei denn, Sie wiederverwenden Zwischeneinbettungen.
Praktischer Trick. „Semantik-bewusstes Verpacken“: Berechnen Sie Einbettungen für Sätze einmal, gruppieren Sie Sätze in thematisch kohärente Segmente und erstellen Sie dann Einbettungen für jedes finale Segment.
Hierarchisches Chunking (Eltern/Kinder)
Was es ist. Erstellen Sie eine multigranular Darstellung: grobe Eltern-Chunks (z. B. Abschnittsgröße) mit feineren Kinder-Chunks (z. B. Absatzgröße). LlamaIndex’s hierarchischer Knotenparser erzeugt standardmäßig „coarse-to-fine“-Hierarchien (z. B. 2048 → 512 → 128 Token-Skalen), und der AutoMergingRetriever kann Kinderknoten in Elternknoten bei der Suche verknüpfen, wenn genügend verwandte Kinder abgerufen werden.
Warum es hilft. Es vermeidet, zwischen „kleinen Chunks für Erinnerung“ und „großen Chunks für Kohärenz“ zu wählen, indem es beide speichert und bei der Abfrage auswählt.
Kosten. Komplexere Verarbeitung und Retrieval-Logik, plus potenziell mehr Speicher (da Sie mehrere Granularitäten speichern).
Anpassung / LLM-basiertes Chunking
Was es ist. Verwenden Sie ein LLM, um Chunk-Grenzen zu entscheiden (und optional Zusammenfassungen oder kontextuelle Überschriften zu generieren). Weaviate beschreibt LLM-basiertes Chunking explizit als LLM, das semantisch kohärente Chunks erstellt, anstatt auf festen Regeln oder Einbettungsähnlichkeit zu vertrauen.
Wenn es sich lohnt. Hochwertige Corpora, bei denen Richtigkeit Kosten überwiegt (Recht, Compliance, Support-Runbooks), und bei denen Dokumente unordentlich, heterogen und schlecht segmentiert sind.
Risiken. Kosten, Latenz und Nichtdeterminismus. Sie benötigen Caching, deterministisches Decoding und Regressionstests (siehe Bewertungsabschnitt).
Struktur- und Element-basiertes Chunking (Dokumente sind nicht reiner Text)
Was es ist. Dokumente in Elemente (Titel, Absätze, Listen, Tabellen, Bildunterschriften) mit einer Dokumentverarbeitungsschicht parsen und dann mit diesen Elementen chunken. Unstructureds Chunking-Funktionen verwenden explizit Metadaten und Dokumentelemente (erzeugt durch Partitionierung), um Chunks für RAG zu erstellen. Doclings HierarchicalChunker erstellt Chunks pro erkanntem Dokumentelement und fügt strukturelle Metadaten wie Überschriften/Bildunterschriften hinzu.
Beweise aus kürzlichem Forschung. Eine 2024-Studie zu SEC-Berichten argumentiert, dass Absatz-basiertes Chunking die Dokumentstruktur ignoriert und vorschlägt, Chunking nach strukturellen Elementen zu erstellen; sie berichtet über verbesserte RAG-Ergebnisse und weniger Chunks/Vektoren als struktur-unkritische Ansätze.
Warum es für Multimodal wichtig ist. Tabellen, Abbildungen und Bildunterschriften enthalten oft die Grundwahrheit. „Flatten“ sie in reinen Text kann Signale zerstören, die Retrieval sonst nutzen würde.
Code-aware Chunking (AST/Struktur)
Was es ist. Code nach syntaktischen Einheiten (Funktionen, Klassen, Module) chunken, optional mit Dokumentationen und Kommentaren.
Warum es wichtig ist. Fixe Token-Splitts tendieren dazu, Funktionen zu halbieren und Dokumentationen von Implementierungen zu trennen – schlecht für Code-Suche und „erkläre diese Funktion“-RAG-Anwendungsfälle.
Implementierungsoptionen. Für Python ist der eingebaute ast-Modul oft ausreichend. Für mehrsprachige Repositories sind tree-sitter-basierte Chunker üblich.
Bewertungsdimensionen und wie man Chunking-Strategien vergleicht
Chunking sollte als Systemkomponente bewertet werden.
Suchqualitätsmetriken
Verwenden Sie standardisierte IR-Metriken für die Suchschicht:
- Recall@k / Precision@k: Enthält das top-k die Gold-Beweise?
- MRR / nDCG: Rangiert das Gold-Beweis hoch?
BEIR ist ein weit verbreiteter heterogener Benchmark für IR-Bewertung über Aufgaben/Domain und hebt Kompromisse zwischen sparsamen, dichten, späten Interaktionen und Neuanordnungsansätzen hervor.
Chunking beeinflusst diese Metriken, weil es definiert, was als „relevant abgerufenes Item“ zählt.
End-to-end RAG-Antwortqualitätsmetriken
Wenn Sie QA oder Assistenten erstellen, sind Retrieval-Metriken notwendig, aber nicht ausreichend. Sie benötigen auch:
- Kontext-Erinnerung / Präzision: ob abgerufene Kontexte relevante Beweise enthalten und Rauschen vermeiden.
- Glaubwürdigkeit: ob die generierte Antwort vom abgerufenen Kontext unterstützt wird.
RAGAS bietet konkrete Definitionen und Implementierungen für „Glaubwürdigkeit“ und andere RAG-orientierte Metriken.
Systemkosten und Leistungsdimensionen
Chunking verändert diese Hebel:
Latenz (p50/p95). Abfrage-Latenz erhöht sich normalerweise mit mehr Vektoren und mehr Nachverarbeitung. Ihr Vektorindex spielt auch eine Rolle: FAISS-Indextypen tauschen Suchzeit, Qualität, Speicher und Trainings/Adding-Zeit aus.[^faiss]
Einbettungskosten und Durchsatz. OpenAI-Einbettungen werden pro Token abgerechnet; die Einbettung-API hat explizite pro-Eingabe- und pro-Anfrage-Limits.[^openai_embed_create] Für Offline-Verarbeitung reduziert die Batch-API die Kosten und bietet höhere Quoten im Austausch für nicht-echte Zeitverzögerung.[^openai_batch]
Indexgröße und Speicher. Grob gesagt kostet das Speichern von N float32-Vektoren der Dimension d ~4 * N * d Bytes nur für die Rohvektoren (plus Metadaten + Index-Überlastung). Chunking beeinflusst N. Die Einbettungsdimensionalität beeinflusst d, und die OpenAI-Einbettung-API erlaubt das Steuern der Ausgabedimensionalität über den dimensions-Parameter.[^openai_embed_create]
LLM-Promptbudget. Größere Chunks und Überlappung vergrößern Prompt-Tokens. Dies kann Latenz und Kosten erhöhen und „verloren in der Mitte“-Stil-Fehlermodi erhöhen, bei denen Modelle weniger Aufmerksamkeit auf einige Kontexte zahlen. In der Praxis justieren Sie oft:
- kleine Chunks abrufen,
- zusammenführen/deduplizieren,
- optional zusammenfassen,
- senden Sie eine kompakte Beweismenge an das LLM.
Aktualisierungs-/Verarbeitungskosten. Kleinere Chunks ermöglichen teilweise Wieder-einbettung, erhöhen aber Buchhaltung. Für Streaming-Verarbeitung bevorzugen Sie deterministische, inkrementelle Chunking (fest oder gleitendes Fenster) und fügen stabile IDs hinzu (document_id, Offset-Bereiche, Hash).
Experimentelles Design: ein praktisches Benchmark-Loop
Ein reproduzierbares Chunking-Benchmark hat typischerweise:
- einen festen Corpora-Snapshot + festen Satz von Abfragen mit Gold-Beweisen (oder zumindest erwarteten Antwortbereichen).
- einen festen Einbettungsmodell und Vektorindex-Konfiguration.
- eine „nur-Retrieval“-Bewertung (Recall@k, nDCG) plus eine „RAG“-Bewertung (Glaubwürdigkeit, Antwortrelevanz).
- Kosten-Telemetrie: #Chunks, eingebettete Token, $/Monat Speicher, p95 Abfragespeed, Prompt-Tokens.
Der Unstructured SEC-Berichte-Paper ist ein gutes Beispiel, um Chunking-Strategien mit beiden Retrieval-orientierten Metriken und QA-Genauigkeitsmessungen zu bewerten.
Praktische Leitlinien, Entscheidungsmatrix und empfohlene Standards
Empfohlene Standards, die überraschend gut funktionieren
Wenn Sie eine robuste „Tag 1“-Strategie für allgemeine Dokumentation QA benötigen:
- Leicht parsen: Überschriften und grundlegende Metadaten (Quelle, Abschnittstitel, URL/Pfad, Zeitstempel) beibehalten.
- Chunken mit rekursivem Trenner-Splitter (Absatz → Satz → Wort), mit moderater Überlappung.
- Einbettung mit einem starken allgemeinen Einbettungsmodell.
- Indexieren mit Metadaten (Dokument-ID, Abschnitt, ACLs) und deduplizieren bei der Suche.
- Fügen Sie Neuanordnung oder hierarchische Zusammenführung nur hinzu, wenn Ihre Bewertung einen Mangel zeigt.
Dies entspricht dem, wie gängige RAG-Frameworks Chunk-Überlappung und struktur-respektierende Aufsplittung beschreiben.
Welche Chunking-Methode zu verwenden – Entscheidungsmatrix

| Use case | Empfohlene Chunking-Standard | Schlüsselparameter, die abgestimmt werden sollten | Typische Fehlermodus | Upgrade-Pfad |
|---|---|---|---|---|
| Kurzform QA über Dokumente (FAQs, interne Wiki) | Rekursiv/Trenner-Chunking + Überlappung | chunk_size, Überlappung, top-k |
Fehlende über-satzliche Beweise an der Grenze | Füge semantisches Chunking oder Neuanordner hinzu |
| Langform QA (Richtlinien, Standards, Handbücher) | Hierarchisches Chunking + Zusammenführung-Retriever | Eltern/Kinder-Größen, Zusammenführungsschwelle | Ruft kleine Fragmente ab; LLM hat keinen vollständigen Kontext | Auto-Zusammenführung/hierarchische Suche |
| Zusammenfassung (pro Dokument / pro Abschnitt) | Struktur-aware Chunks (Abschnitte) | Abschnittserkennung, maximale Token | Zusammenfassungen verfehlen über-Abschnitts-Links | Hierarchische Zusammenfassung + Abschnittsgraph |
| Code-Suche & „erkläre diese Funktion“ | AST/Funktionsebene-Chunking | Dokumentation/ Kommentare einbeziehen, maximale Token | Funktion geteilt; Verlust von Signatur/Verwendung | Repository-aware Hierarchie (Modul→Klasse→Funktion) |
| Multimodale PDFs (Tabellen/Abbildungen) | Element-basiertes Chunking (Titel/Tabellen/Bildunterschriften) | Tabellen-Serialisierung, Bildunterschriften-Zusammenführung | Tabelleninhalte verloren oder verfälscht | Verwende Docling/Unstructured + strukturierte Serialisierer |
| Streaming-Verarbeitung (Protokolle, Chats, Tickets) | Gleitfenster oder fixe Token-Größe | Fenster, Schrittweite, Dedup | Übermäßige Abrufung von redundanten Fenstern | Füge semantische Grenzerkennung in Batches hinzu |
Chunking – Qualitative Leistungsvergleich
Behandeln Sie dies als „erwartete Richtung der Änderung“ (validieren Sie mit Ihren eigenen Daten).
| Strategie | Retrievalgenauigkeitspotential | Kohärenz des abgerufenen Kontexts | Verarbeitungskomplexität | Vektorenrzahl / Indexgröße | Einbettungskosten | Auswirkung auf Abfragespeed | Bestens geeignet für |
|---|---|---|---|---|---|---|---|
| Fixgröße (keine Überlappung) | Mittel | Niedrig | Niedrig | Mittel | Niedrig | Mittel | schnelle Prototypen, homogener Text |
| Fixgröße + Überlappung | Mittel–Hoch | Mittel | Niedrig | Hoch | Mittel–Hoch | Mittel–Hoch | QA, bei der Grenzverlust schadet |
| Satz-/Absatz-Packing | Hoch (Prosa) | Hoch | Mittel | Mittel | Mittel | Mittel | Dokumente, Artikel, saubere Prosa |
| Gleitfenster | Hoch Erinnerung | Mittel | Mittel | Sehr hoch | Sehr hoch | Hoch | Transkripte, Protokolle, Chat |
| Rekursiv/Trenner | Hoch | Hoch | Mittel | Mittel | Mittel | Mittel | „Standard“-Dokumente RAG |
| Semantisches Chunking | Hoch–Sehr hoch | Hoch | Hoch | Mittel | Hoch | Mittel | mehrthemen Seiten, narrative Texte |
| Hierarchisch (Eltern/Kinder) | Sehr hoch | Sehr hoch | Hoch | Hoch | Hoch | Mittel | lange Handbücher / Standards |
| LLM-basiert/Anpassung | Sehr hoch | Sehr hoch | Sehr hoch | Mittel | Sehr hoch | Mittel–Hoch | hochwertige Corpora |
| Element-/Struktur-basiert | Hoch–Sehr hoch | Hoch | Hoch | Niedrig–Mittel | Mittel | Mittel | PDFs, Berichte, Tabellen, gemischte Layouts |
| Code-aware (AST) | Hoch (Code) | Hoch | Mittel | Mittel | Mittel | Mittel | Code-Suche, Repository-Assistenten |
DevOps und Hardware-Hinweise (häufig übersehen)
Chunking-Entscheidungen beeinflussen wie viel Infrastruktur Sie benötigen:
- Kleinere Chunks → mehr Vektoren → größere Indizes und mehr RAM/Disk. Für selbstgehostete FAISS kann dies Sharding oder disk-basierte Indizes erzwingen.
- Wenn Sie lokal einbetten, wird die Einbettungsdurchsatz ein GPU-Zuteilungsproblem; wenn Sie über API einbetten, wird die Tokenmenge ein FinOps-Problem (Batch-API ist Ihr Freund für Rückverfolgungen).
- Einige Engine (FAISS) bieten GPU-geschleunigte Suche; dies kann Kosten von RAM-beschränkten CPU zu GPU-Speicher und PCIe-Durchsatz verschieben.
- Struktur-aware Parsing (PDF-Layout, OCR, Tabellenextraktion) ist oft CPU-beschränkt und kann die Einbettungskosten für gescannte Dokumente dominieren; planen Sie dies separat.
Chunking – Python-Implementierungen
Alle Beispiele sind so gestaltet, dass sie lesbar und ausführbar sind. Wenn Sie einen API-Schlüssel oder eine laufende Datenbank benötigen, ist das aus dem Code klar.
Gemeinsame Hilfsmittel: Token-Zählung und stabile Chunk-IDs
from __future__ import annotations
import hashlib
from dataclasses import dataclass
from typing import Any, Iterable, Optional
from transformers import AutoTokenizer # pip install transformers
@dataclass(frozen=True)
class Chunk:
text: str
meta: dict[str, Any]
def sha1_id(*parts: str) -> str:
h = hashlib.sha1()
for p in parts:
h.update(p.encode("utf-8"))
h.update(b"\x1e")
return h.hexdigest()
# Verwenden Sie einen Tokenizer, der ungefähr mit der Tokenisierung Ihres LLM/Embedding übereinstimmt.
TOKENIZER = AutoTokenizer.from_pretrained("bert-base-uncased")
def token_len(text: str) -> int:
return len(TOKENIZER.encode(text, add_special_tokens=False))
Chunking mit fester Token-Größe
def chunk_fixed_tokens(
text: str,
*,
chunk_size: int = 512,
) -> list[Chunk]:
token_ids = TOKENIZER.encode(text, add_special_tokens=False)
out: list[Chunk] = []
for i in range(0, len(token_ids), chunk_size):
window = token_ids[i : i + chunk_size]
chunk_text = TOKENIZER.decode(window)
out.append(
Chunk(
text=chunk_text,
meta={"strategy": "fixed_tokens", "start_token": i, "end_token": i + len(window)},
)
)
return out
Chunking mit Überlappung und Schiebe-Fenster
def chunk_sliding_window(
text: str,
*,
window_tokens: int = 512,
stride_tokens: int = 384, # kleinerer Schritt = mehr Überlappung
) -> list[Chunk]:
assert 1 <= stride_tokens <= window_tokens, "Schritt muss innerhalb (0, Fenster] liegen"
token_ids = TOKENIZER.encode(text, add_special_tokens=False)
out: list[Chunk] = []
start = 0
while start < len(token_ids):
end = min(start + window_tokens, len(token_ids))
window = token_ids[start:end]
out.append(
Chunk(
text=TOKENIZER.decode(window),
meta={"strategy": "sliding_window", "start_token": start, "end_token": end},
)
)
if end == len(token_ids):
break
start += stride_tokens
return out
Satzbasiertes Chunking (NLTK) mit Token-Budget-Packung
# pip install nltk
import nltk
from nltk.tokenize import sent_tokenize
nltk.download("punkt", quiet=True)
def chunk_by_sentences_nltk(
text: str,
*,
max_tokens: int = 512,
overlap_sentences: int = 1,
) -> list[Chunk]:
sents = [s.strip() for s in sent_tokenize(text) if s.strip()]
out: list[Chunk] = []
buf: list[str] = []
buf_tokens = 0
def flush():
nonlocal buf, buf_tokens
if not buf:
return
chunk_text = " ".join(buf).strip()
out.append(
Chunk(
text=chunk_text,
meta={"strategy": "sentences_nltk", "sent_count": len(buf)},
)
)
# Überlappung durch Beibehaltung der letzten N Sätze
if overlap_sentences > 0:
buf = buf[-overlap_sentences:]
buf_tokens = token_len(" ".join(buf))
else:
buf, buf_tokens = [], 0
for s in sents:
s_tokens = token_len(s)
# Wenn ein einzelner Satz das Budget überschreitet, wechseln Sie zu fester Größen Chunking auf diesem Abschnitt
if s_tokens > max_tokens:
flush()
out.extend(chunk_fixed_tokens(s, chunk_size=max_tokens))
continue
if buf_tokens + s_tokens > max_tokens and buf:
flush()
buf.append(s)
buf_tokens += s_tokens
flush()
return out
Satzbasiertes Chunking (spaCy), wenn Sie regelbasiertes oder modellbasiertes SBD verwenden möchten
# pip install spacy
# python -m spacy download en_core_web_sm
import spacy
def chunk_by_sentences_spacy(
text: str,
*,
max_tokens: int = 512,
) -> list[Chunk]:
# Für leichte regelbasierte Aufteilungen (keine Abhängigkeitsanalyse), verwenden Sie den Sentencizer.
nlp = spacy.blank("en")
nlp.add_pipe("sentencizer") # regelbasierte Satzgrenzerkennung
doc = nlp(text)
sents = [sent.text.strip() for sent in doc.sents if sent.text.strip()]
return chunk_by_sentences_nltk(" ".join(sents), max_tokens=max_tokens, overlap_sentences=1)
Rekursives Chunking mit Trennzeichen (LangChain)
# pip install langchain-text-splitters
from langchain_text_splitters import RecursiveCharacterTextSplitter
def chunk_recursive_langchain(
text: str,
*,
chunk_size: int = 1200,
chunk_overlap: int = 150,
) -> list[Chunk]:
splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
length_function=token_len, # token-bewusste Budgetierung
separators=["\n\n", "\n", ". ", " ", ""], # anpassen Sie dies an Ihren Inhalt (z. B. Code)
)
pieces = splitter.split_text(text)
return [
Chunk(text=p, meta={"strategy": "recursive_langchain", "chunk_size": chunk_size, "overlap": chunk_overlap})
for p in pieces
]
Semantisches Chunking mit Embedding-Ähnlichkeit (OpenAI Embeddings)
Dieser Ansatz berechnet Embeddings für Kandidaten-Einheiten (Sätze/Paragraphen), und findet dann semantische „Bruchstellen“.
# pip install openai numpy
import os
import numpy as np
from openai import OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY", "YOUR_OPENAI_API_KEY"))
def embed_texts_openai(texts: list[str], *, model: str = "text-embedding-3-small") -> np.ndarray:
# HINWEIS: für große Chargen, beachten Sie die Grenzen der Anfragetoken und Chargengröße.
resp = client.embeddings.create(model=model, input=texts)
embs = np.array([d.embedding for d in resp.data], dtype=np.float32)
return embs
def cosine_sim(a: np.ndarray, b: np.ndarray) -> float:
denom = (np.linalg.norm(a) * np.linalg.norm(b)) + 1e-8
return float(np.dot(a, b) / denom)
def chunk_semantic(
text: str,
*,
max_tokens: int = 800,
breakpoint_threshold: float = 0.70,
) -> list[Chunk]:
# 1) Starten Sie mit Satz-Kandidaten
sents = [s.strip() for s in sent_tokenize(text) if s.strip()]
if len(sents) <= 1:
return [Chunk(text=text, meta={"strategy": "semantic", "note": "no_split"})]
# 2) Embedden Sie jeden Satz
embs = embed_texts_openai(sents)
# 3) Berechnen Sie Ähnlichkeitsabfälle
sims = [cosine_sim(embs[i], embs[i + 1]) for i in range(len(sents) - 1)]
# 4) Erstellen Sie Segmente an Bruchstellen
out: list[Chunk] = []
buf: list[str] = []
buf_tokens = 0
for i, s in enumerate(sents):
# Fügen Sie den Satz hinzu
s_tok = token_len(s)
if buf and buf_tokens + s_tok > max_tokens:
out.append(Chunk(text=" ".join(buf), meta={"strategy": "semantic", "reason": "max_tokens"}))
buf, buf_tokens = [], 0
buf.append(s)
buf_tokens += s_tok
# Entscheiden Sie sich für eine Bruchstelle nach Satz i (basierend auf Ähnlichkeit zum nächsten)
if i < len(sims) and sims[i] < breakpoint_threshold:
out.append(
Chunk(
text=" ".join(buf),
meta={"strategy": "semantic", "reason": "sim_drop", "sim_to_next": sims[i]},
)
)
buf, buf_tokens = [], 0
if buf:
out.append(Chunk(text=" ".join(buf), meta={"strategy": "semantic", "reason": "final"}))
return out
Hierarchisches Chunking + Retrieval-Merging (LlamaIndex)
# pip install llama-index llama-index-llms-openai
from llama_index.core import Document, StorageContext, VectorStoreIndex
from llama_index.core.node_parser import HierarchicalNodeParser, get_leaf_nodes
from llama_index.core.retrievers import AutoMergingRetriever
from llama_index.core.storage.docstore import SimpleDocumentStore
def build_hierarchical_index(text: str):
docs = [Document(text=text)]
node_parser = HierarchicalNodeParser.from_defaults() # Standards für grob-zu-fein-Größen
nodes = node_parser.get_nodes_from_documents(docs)
docstore = SimpleDocumentStore()
docstore.add_documents(nodes)
storage_context = StorageContext.from_defaults(docstore=docstore)
leaf_nodes = get_leaf_nodes(nodes)
base_index = VectorStoreIndex(leaf_nodes, storage_context=storage_context)
base_retriever = base_index.as_retriever(similarity_top_k=6)
retriever = AutoMergingRetriever(base_retriever, storage_context, verbose=True)
return retriever
Elementbasiertes Chunking für PDFs (Docling)
# pip install docling
# HINWEIS: Die Qualität der PDF-Parsing hängt von Ihrer Umgebung (Schriften, OCR usw.) ab.
from docling.document_converter import DocumentConverter
from docling.transforms.chunker.hierarchical_chunker import HierarchicalChunker
def chunk_pdf_docling(pdf_path: str) -> list[Chunk]:
converter = DocumentConverter()
doc = converter.convert(pdf_path).document # DoclingDocument
chunker = HierarchicalChunker()
doc_chunks = list(chunker.chunk(doc))
out: list[Chunk] = []
for c in doc_chunks:
# c.text enthält serialisierten Chunk-Inhalt; c.meta trägt Strukturinformationen
out.append(Chunk(text=c.text, meta={"strategy": "docling_hierarchical", **dict(c.meta)}))
return out
Codebewusstes Chunking für Python (AST)
import ast
def chunk_python_by_ast(code: str, *, filepath: str = "<memory>") -> list[Chunk]:
tree = ast.parse(code)
out: list[Chunk] = []
for node in tree.body:
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
start = getattr(node, "lineno", None)
end = getattr(node, "end_lineno", None)
if start is None or end is None:
continue
lines = code.splitlines()
snippet = "\n".join(lines[start - 1 : end])
kind = "class" if isinstance(node, ast.ClassDef) else "function"
name = getattr(node, "name", "<anon>")
out.append(
Chunk(
text=snippet,
meta={
"strategy": "python_ast",
"kind": kind,
"name": name,
"filepath": filepath,
"start_line": start,
"end_line": end,
},
)
)
return out
Beispiele für Indexierung
FAISS (lokal) – minimaler, schneller Baseline
# pip install faiss-cpu numpy
import numpy as np
import faiss
def build_faiss_index(vectors: np.ndarray) -> faiss.Index:
# Vektoren: Form (N, d), Datentyp float32
d = vectors.shape[1]
index = faiss.IndexFlatIP(d) # Skalarprodukt; Cosinusähnlichkeit, wenn Vektoren normalisiert sind
faiss.normalize_L2(vectors)
index.add(vectors)
return index
def faiss_search(index: faiss.Index, query_vec: np.ndarray, k: int = 5):
q = query_vec.astype(np.float32).reshape(1, -1)
faiss.normalize_L2(q)
scores, ids = index.search(q, k)
return ids[0].tolist(), scores[0].tolist()
Chroma (lokal) – einfache Persistenz für RAG-Prototyping
# pip install chromadb
import chromadb
def build_chroma_collection(chunks: list[Chunk], embeddings: np.ndarray, *, path: str = "./chroma_store"):
client = chromadb.PersistentClient(path=path)
col = client.get_or_create_collection(name="docs")
ids = [sha1_id(c.meta.get("strategy", "chunk"), str(i), c.text[:50]) for i, c in enumerate(chunks)]
col.upsert(
ids=ids,
documents=[c.text for c in chunks],
metadatas=[c.meta for c in chunks],
embeddings=embeddings.tolist(),
)
return col
Weaviate (selbstgehostet / Cloud) – eigene Vektoren mitbringen
# pip install weaviate-client
import weaviate
from weaviate.classes.config import Configure
def weaviate_upsert_self_provided(
chunks: list[Chunk],
embeddings: np.ndarray,
):
client = weaviate.connect_to_local() # oder connect_to_weaviate_cloud(...)
try:
collection = client.collections.create(
name="Chunk",
vector_config=Configure.Vectors.self_provided(), # Sie liefern die Vektoren
)
with collection.batch.dynamic() as batch:
for c, v in zip(chunks, embeddings):
batch.add_object(
properties={"text": c.text, **{f"m_{k}": str(vv) for k, vv in c.meta.items()}},
vector=v.tolist(),
)
# Abfragen nach Vektor
q = embeddings[0]
res = collection.query.near_vector(near_vector=q.tolist(), limit=5)
for obj in res.objects:
print(obj.properties.get("text")[:200])
finally:
client.close()
Einige Quellendokumente
- Patrick Lewis et al., “Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks”, NeurIPS 2020; arXiv:2005.11401.
- Vladimir Karpukhin et al., “Dense Passage Retrieval for Open-Domain Question Answering”, EMNLP 2020; arXiv:2004.04906.
- OpenAI API Referenz: Erstellen von Embeddings (
/v1/embeddings) – Token-Limits (8192 pro Eingabe; 300k insgesamt pro Anfrage) unddimensions-Parameter. - OpenAI Batch API Leitfaden + OpenAI API Preisseite (Batch spart ca. 50 % mit 24-Stunden-Verarbeitungszeit).
- LangChain Dokumentation:
RecursiveCharacterTextSplitterund Leitfaden zur Integration von Splitters (Chunk-Größe/Überlappung, rekursive Trennzeichenhierarchie). - LlamaIndex Dokumentation:
HierarchicalNodeParserundAutoMergingRetriever(coarse-to-fine-Knoten; Retrieval-Zeit-Merging). - Weaviate Blog: “Chunking-Strategien zur Verbesserung der Leistung von LLM RAG-Pipelines” (Beschreibung der LLM-basierten Chunking-Strategien und Kompromisse).
- Docling Dokumentation:
HierarchicalChunkererstellt Chunk aus Dokumentelementstruktur und fügt Header/Bildunterschriften-Metadaten hinzu. - Jimeno Yepes et al., “Financial Report Chunking for Effective Retrieval Augmented Generation” (arXiv:2402.05131v3, 2024).
- Marti A. Hearst, “TextTiling: Segmenting Text into Multi-Paragraph Subtopic Passages”, Computational Linguistics, 1997 (ACL Anthology: J97-1003).
- FAISS Dokumentation / GitHub-Repository: Kompromisse zwischen Suchzeit, Qualität und Speicher; optionaler GPU-Unterstützung.
- Nandan Thakur et al., “BEIR: A Heterogeneous Benchmark for Zero-shot Evaluation of Information Retrieval Models”, NeurIPS 2021; arXiv:2104.08663.
- RAGAS Dokumentation: “Faithfulness”-Metrik und verwandte RAG-Bewertungsmetriken.
- NLTK Dokumentation:
nltk.tokenize.sent_tokenize– empfohlener Satz-Tokizer basierend auf Punkt. - spaCy API-Dokumentation:
Sentencizer– regelbasierte Satzgrenzerkennung ohne Abhängigkeitsanalyse.
Andere nützliche Links
- Erweitertes RAG: LongRAG, Self-RAG und GraphRAG erklärt
- Vektor-Speicher für RAG-Vergleich
- Neuordnen mit Embedding-Modellen
- Neuordnen von Textdokumenten mit Ollama und Qwen3 Embedding-Modell – in Go
- Neuordnen von Textdokumenten mit Ollama und Qwen3 Reranker-Modell – in Go
- Selbsthosten von Cognee (LLM-Memory): LLM-Performance-Tests
- LLM-Hosting: Lokal, Selbstgehostet & Cloud-Infrastruktur verglichen
- LLM-Performance: Benchmarks, Engpässe & Optimierung
- Retrieval-Augmented Generation (RAG) Tutorial: Architektur, Implementierung und Produktionsleitfaden