2. ChunkingFortgeschritten

Strategien für Chunking RAG 2025: Optimale Größen & Techniken

25. Januar 2025
15 Min. Lesezeit
Équipe de Recherche Ailog

Beherrschen Sie Chunking für RAG: optimale Größen (512–1024 tokens), Überlappungsstrategien, semantische vs. feste Segmentierung. +25% Retrieval-Genauigkeit.

Auf einen Blick

  • Die Chunk-Größe zählt: 500-1000 Tokens balancieren Kontext und Genauigkeit
  • Semantisches Chunking (Aufteilung nach Bedeutung) übertrifft feste Größenaufteilung in der Qualität (+15-30% Retrieval-Genauigkeit)
  • Überlappung (10-20%) verhindert Kontextverlust an den Grenzen
  • Beste Wahl für die meisten Fälle: Recursive text splitter mit 512 Tokens, 50 Tokens Überlappung
  • Jetzt ausprobieren: Testen Sie verschiedene Strategien auf der Ailog-Plattform

Das Chunking-Problem

Die meisten Dokumente sind zu lang, um:

  • Als einzelner Vektor eingebettet zu werden (Kontextfenster-Grenzen)
  • Vollständig als LLM-Kontext verwendet zu werden (Token-Grenzen)
  • Präzise abgerufen zu werden (zu viele irrelevante Informationen)

Chunking teilt Dokumente in kleinere, handhabbare Stücke auf und bewahrt dabei die semantische Bedeutung.

Warum Chunking wichtig ist

Schlechtes Chunking führt zu:

  • Fragmentiertem Kontext: Wichtige Informationen auf mehrere Chunks verteilt
  • Irrelevantem Retrieval: Chunks enthalten eine Mischung aus relevanten und irrelevanten Inhalten
  • Kontextverlust: Chunk-Grenzen schneiden kritische Informationen ab
  • Schlechte Generierung: Dem LLM fehlt der vollständige Kontext für eine präzise Antwort

Gutes Chunking ermöglicht:

  • Präzises Retrieval: Genau die relevanten Informationen finden
  • Vollständiger Kontext: Chunks enthalten vollständige Gedanken oder Konzepte
  • Effiziente Token-Nutzung: Kein Kontextverschwendung für irrelevanten Text
  • Bessere Antworten: Das LLM hat genau das, was es braucht, nicht mehr

Chunking mit fester Größe

Zeichenbasiert

Den Text alle N Zeichen aufteilen.

DEVELOPERpython
def chunk_by_chars(text, chunk_size=1000, overlap=200): chunks = [] start = 0 while start < len(text): end = start + chunk_size chunks.append(text[start:end]) start += chunk_size - overlap return chunks

Vorteile:

  • Einfache Implementierung
  • Vorhersehbare Chunk-Größen
  • Schnelle Verarbeitung

Nachteile:

  • Schneidet mitten in Wörtern oder Sätzen
  • Ignoriert semantische Grenzen
  • Zerstört Code, Tabellen, Listen

Verwenden, wenn:

  • Ein schneller Prototyp benötigt wird
  • Die Textstruktur homogen ist
  • Präzision nicht kritisch ist

Tokenbasiert

Nach Anzahl der Tokens aufteilen (entspricht der Tokenisierung des Modells).

DEVELOPERpython
import tiktoken def chunk_by_tokens(text, chunk_size=512, overlap=50): encoding = tiktoken.get_encoding("cl100k_base") tokens = encoding.encode(text) chunks = [] start = 0 while start < len(tokens): end = start + chunk_size chunk_tokens = tokens[start:end] chunks.append(encoding.decode(chunk_tokens)) start += chunk_size - overlap return chunks

Vorteile:

  • Respektiert Token-Grenzen präzise
  • Funktioniert mit jedem Embedding-Modell
  • Vorhersehbare Embedding-Kosten

Nachteile:

  • Ignoriert weiterhin semantische Grenzen
  • Tokenisierungs-Overhead
  • Kann einen wichtigen Kontext zerschneiden

Verwenden, wenn:

  • Ein striktes Token-Budget besteht
  • Die Token-Anzahl kritisch ist (API-Kosten)
  • Das Embedding-Modell strikte Token-Grenzen hat

Empfohlene feste Größen

AnwendungsfallChunk-GrößeÜberlappungBegründung
Kurze FAQs128-256 Tokens0-20Minimaler Kontext erforderlich
Allgemeine Dokumentation512-1024 Tokens50-100Balance zwischen Präzision und Kontext
Technische Dokumentation1024-2048 Tokens100-200Mehr Kontext für komplexe Themen
Code256-512 Tokens50-100Funktions-/Klassenkontext erhalten

Semantisches Chunking

An natürlichen semantischen Grenzen aufteilen.

Satzbasiert

An Satzgrenzen aufteilen.

DEVELOPERpython
import nltk nltk.download('punkt') def chunk_by_sentences(text, sentences_per_chunk=5): sentences = nltk.sent_tokenize(text) chunks = [] for i in range(0, len(sentences), sentences_per_chunk): chunk = ' '.join(sentences[i:i + sentences_per_chunk]) chunks.append(chunk) return chunks

Vorteile:

  • Respektiert Satzgrenzen
  • Besser lesbare Chunks
  • Bewahrt vollständige Gedanken

Nachteile:

  • Variable Chunk-Größen
  • Satzerkennung kann fehlschlagen
  • Gruppiert möglicherweise keine zusammengehörigen Sätze

Verwenden, wenn:

  • Lesbarkeit wichtig ist
  • Sätze eigenständig sind
  • Es sich um allgemeinen narrativen Text handelt

Absatzbasiert

An Absatzumbrüchen aufteilen.

DEVELOPERpython
def chunk_by_paragraphs(text, paragraphs_per_chunk=2): paragraphs = text.split('\n\n') chunks = [] for i in range(0, len(paragraphs), paragraphs_per_chunk): chunk = '\n\n'.join(paragraphs[i:i + paragraphs_per_chunk]) chunks.append(chunk) return chunks

Vorteile:

  • Respektiert die Dokumentstruktur
  • Hält zusammengehörige Inhalte beisammen
  • Natürliche Leseeinheiten

Nachteile:

  • Sehr variable Größen
  • Abhängig von der Formatierung
  • Lange Absätze bleiben problematisch

Verwenden, wenn:

  • Dokumente gut formatiert sind
  • Absätze vollständige Ideen darstellen
  • Blogbeiträge, Artikel

Recursive Character Splitting

LangChain-Ansatz: Aufteilungen in Präferenzreihenfolge ausprobieren.

DEVELOPERpython
from langchain_text_splitters import RecursiveCharacterTextSplitter splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=200, separators=["\n\n", "\n", ". ", " ", ""] ) chunks = splitter.split_text(text)

Trennhierarchie:

  1. Doppelter Zeilenumbruch (Absätze)
  2. Einfacher Zeilenumbruch (Zeilen)
  3. Punkt + Leerzeichen (Sätze)
  4. Leerzeichen (Wörter)
  5. Zeichen

Vorteile:

  • Respektiert die Dokumentstruktur, wo möglich
  • Elegante Rückfalllösung
  • Balance zwischen Semantik und Größe

Nachteile:

  • Bleibt etwas willkürlich
  • Erfasst möglicherweise nicht die wahren semantischen Einheiten
  • Konfiguration erforderlich

Verwenden, wenn:

  • Allgemeines Chunking benötigt wird
  • Gemischte Dokumenttypen vorliegen
  • Eine gute Standardwahl gesucht wird

Metadaten-bewusstes Chunking

Die Dokumentstruktur für das Chunking nutzen.

Markdown-Chunking

Nach Überschriften aufteilen und die Hierarchie beibehalten.

DEVELOPERpython
def chunk_markdown(text): chunks = [] current_h1 = "" current_h2 = "" current_chunk = [] for line in text.split('\n'): if line.startswith('# '): if current_chunk: chunks.append({ 'content': '\n'.join(current_chunk), 'h1': current_h1, 'h2': current_h2 }) current_chunk = [] current_h1 = line[2:] elif line.startswith('## '): if current_chunk: chunks.append({ 'content': '\n'.join(current_chunk), 'h1': current_h1, 'h2': current_h2 }) current_chunk = [] current_h2 = line[3:] current_chunk.append(line) if current_chunk: chunks.append({ 'content': '\n'.join(current_chunk), 'h1': current_h1, 'h2': current_h2 }) return chunks

Vorteile der Metadaten:

  • Überschriften liefern Kontext für die Suche
  • Filterung nach Abschnitt möglich
  • Besseres Relevanz-Scoring

HTML/XML-Chunking

Nach semantischen HTML-Tags aufteilen.

DEVELOPERpython
from bs4 import BeautifulSoup def chunk_html(html): soup = BeautifulSoup(html, 'html.parser') chunks = [] # Nach Abschnitten aufteilen for section in soup.find_all(['section', 'article', 'div']): if section.get('class') in ['content', 'main']: chunks.append({ 'content': section.get_text(), 'tag': section.name, 'class': section.get('class') }) return chunks

Code-Chunking

Nach Funktions-/Klassengrenzen aufteilen.

DEVELOPERpython
import ast def chunk_python_code(code): tree = ast.parse(code) chunks = [] for node in ast.walk(tree): if isinstance(node, (ast.FunctionDef, ast.ClassDef)): chunk_lines = code.split('\n')[node.lineno-1:node.end_lineno] chunks.append({ 'content': '\n'.join(chunk_lines), 'type': type(node).__name__, 'name': node.name }) return chunks

Vorteile:

  • Bewahrt logische Einheiten (Funktionen, Klassen)
  • Metadaten erleichtern das Auffinden
  • Natürliche Code-Grenzen

Nachteile:

  • Sprachspezifische Analyse
  • Komplexe Implementierung
  • Kontext zwischen Funktionen kann verloren gehen

Fortgeschrittene Chunking-Techniken

Basierend auf semantischer Ähnlichkeit

Sätze nach semantischer Ähnlichkeit gruppieren.

DEVELOPERpython
from sentence_transformers import SentenceTransformer from sklearn.cluster import AgglomerativeClustering def semantic_chunking(text, model, max_chunk_size=512): sentences = nltk.sent_tokenize(text) embeddings = model.encode(sentences) # Ähnliche Sätze gruppieren clustering = AgglomerativeClustering( n_clusters=None, distance_threshold=0.5 ) labels = clustering.fit_predict(embeddings) # Sätze nach Cluster gruppieren chunks = {} for sent, label in zip(sentences, labels): chunks.setdefault(label, []).append(sent) return [' '.join(sents) for sents in chunks.values()]

Vorteile:

  • Echte semantische Gruppierung
  • Bewältigt Themenwechsel
  • Optimale Informationsdichte

Nachteile:

  • Rechenintensiv
  • Erfordert ein Embedding-Modell
  • Komplex zu justieren

Gleitendes Fenster mit kontextuellem Überlappung

Jedem Chunk umgebenden Kontext hinzufügen.

DEVELOPERpython
def sliding_window_chunk(text, window_size=512, context_size=128): tokens = tokenize(text) chunks = [] for i in range(0, len(tokens), window_size): # Hauptfenster start = max(0, i - context_size) end = min(len(tokens), i + window_size + context_size) chunk = { 'content': detokenize(tokens[i:i+window_size]), 'context': detokenize(tokens[start:end]), 'position': i } chunks.append(chunk) return chunks

Vorteile:

  • Jeder Chunk hat umgebenden Kontext
  • Reduziert Informationsverlust
  • Besser für Anfragen an Grenzen

Nachteile:

  • Höherer Speicherbedarf
  • Mehr Embeddings erforderlich
  • Mögliche Redundanz

Hybrides hierarchisches Chunking

Auf mehreren Granularitätsebenen aufteilen.

DEVELOPERpython
def hierarchical_chunk(document): # Ebene 1: Dokument doc_embedding = embed(document['content']) # Ebene 2: Abschnitte sections = split_by_headers(document['content']) section_embeddings = [embed(s) for s in sections] # Ebene 3: Absätze paragraph_chunks = [] for section in sections: paragraphs = section.split('\n\n') paragraph_chunks.extend([ {'content': p, 'section': section} for p in paragraphs ]) para_embeddings = [embed(p['content']) for p in paragraph_chunks] return { 'document': {'embedding': doc_embedding, 'content': document}, 'sections': [{'embedding': e, 'content': s} for e, s in zip(section_embeddings, sections)], 'paragraphs': [{'embedding': e, **p} for e, p in zip(para_embeddings, paragraph_chunks)] }

Retrieval-Strategie:

  1. Auf Dokumentebene suchen
  2. Bei Übereinstimmung in den Abschnitten suchen
  3. Schließlich die spezifischen Absätze abrufen

Vorteile:

  • Mehrere Granularitätsebenen
  • Retrieval vom Allgemeinen zum Spezifischen
  • Bessere Kontexterhaltung

Nachteile:

  • Komplexe Implementierung
  • Mehr Speicher erforderlich
  • Langsamere Indexierung

Chunk-Überlappung

Warum Überlappung?

Ohne Überlappung:

Chunk 1: "...das Datenbankschema umfasst Benutzertabellen"
Chunk 2: "mit Spalten für E-Mail und Passwort..."

Anfrage: "Benutzerdatenbank E-Mail" könnte beide Chunks verpassen

Mit Überlappung:

Chunk 1: "...das Datenbankschema umfasst Benutzertabellen mit Spalten für..."
Chunk 2: "...Benutzertabellen mit Spalten für E-Mail und Passwort..."

Jetzt erscheint "Benutzertabellen mit Spalten" in beiden Chunks, was den Recall verbessert.

Optimale Überlappung

Chunk-GrößeEmpfohlene ÜberlappungVerhältnis
128 Tokens10-20 Tokens8-15%
512 Tokens50-100 Tokens10-20%
1024 Tokens100-200 Tokens10-20%
2048 Tokens200-400 Tokens10-20%

Kompromisse:

  • Mehr Überlappung: Besserer Recall, mehr Speicherbedarf, langsamere Suche
  • Weniger Überlappung: Weniger Speicherbedarf, schnellere Suche, kann Kontext verpassen

Chunking für verschiedene Inhaltstypen

Technische Dokumentation

DEVELOPERpython
# Empfohlen: Markdown-bewusst, Code-Blöcke erhalten chunk_size = 1024 # Chunk-Größe overlap = 150 # Überlappung preserve_code_blocks = True # Code-Blöcke erhalten preserve_tables = True # Tabellen erhalten

Kundenservice-Tickets

DEVELOPERpython
# Empfohlen: Feste Größe mit moderatem Überlappung chunk_size = 512 overlap = 100 split_by_turns = True # Jede Frage-/Antwort-Runde

Forschungsartikel

DEVELOPERpython
# Empfohlen: Auf Abschnitte basierend, Zitate bewahren split_by_sections = True preserve_citations = True chunk_size = 1024

Code-Repositories

DEVELOPERpython
# Empfohlen: Syntaxbewusste Aufteilung split_by_functions = True include_docstrings = True chunk_size = 512

Chat-Protokolle

DEVELOPERpython
# Empfohlen: Nach Nachrichten aufteilen chunk_by_messages = True messages_per_chunk = 10 preserve_threading = True

Chunking-Strategien evaluieren

Retrieval-Metriken

Mit einer Reihe von Anfragen testen:

DEVELOPERpython
def evaluate_chunking(queries, ground_truth, chunking_fn): chunks = chunking_fn(documents) embeddings = embed(chunks) precision_scores = [] recall_scores = [] for query, expected_docs in zip(queries, ground_truth): retrieved = search(embed(query), embeddings, k=5) precision = len(set(retrieved) & set(expected_docs)) / len(retrieved) recall = len(set(retrieved) & set(expected_docs)) / len(expected_docs) precision_scores.append(precision) recall_scores.append(recall) return { 'precision': np.mean(precision_scores), 'recall': np.mean(recall_scores) }

End-to-End-Metriken

Die vollständige RAG-Pipeline testen:

  • Antwortgenauigkeit
  • Kontextnutzung (wie viel des abgerufenen Kontexts genutzt wird)
  • Antwortverankerung (Treue zu den Chunks)

Praktische Empfehlungen

Entscheidungsrahmen

  1. Einfach beginnen: Feste Größe mit Überlappung (512 Tokens, 100 Überlappung)
  2. Leistung messen: Evaluierungsmetriken verwenden
  3. Fehler identifizieren: Wo scheitert das Retrieval?
  4. Iterieren: Semantisches oder metadaten-bewusstes Chunking ausprobieren
  5. A/B-Tests: Strategien mit echten Anfragen vergleichen

Häufige Muster

90% der Anwendungsfälle:

  • Recursive Character Splitting
  • Chunks von 512-1024 Tokens
  • Überlappung von 10-20%

Strukturierte Dokumente:

  • Markdown-/HTML-bewusstes Chunking
  • Metadaten erhalten (Überschriften, Abschnitte)
  • Variable Größen akzeptabel

Code:

  • Syntaxbewusste Aufteilung
  • Docstrings zusammen mit Funktionen einbeziehen
  • Kleinere Chunks (256-512)

Hybride Suche:

  • Mehrere Chunk-Größen
  • Hierarchisches Retrieval
  • Der Komplexitätsaufwand lohnt sich für hochwertige Anwendungen

Häufige Fallstricke

  1. Zu kleine Chunks: Kontextverlust, fragmentiertes Retrieval
  2. Zu große Chunks: Irrelevante Informationen, Token-Verschwendung
  3. Keine Überlappung: Verpasst Anfragen an Grenzen
  4. Struktur ignorieren: Willkürliche Aufteilungen in Tabellen, Code, Listen
  5. Einheitsgröße: Verschiedene Inhalte erfordern verschiedene Strategien
  6. Keine Evaluierung: Raten statt messen

Ailog-Expertentipp: In Produktivumgebungen mit mehr als 10 Mio. Dokumenten haben wir festgestellt, dass der Start mit Chunks von 512 Tokens und 10% Überlappung in 80% der Fälle funktioniert. Optimieren Sie erst weiter, wenn Sie in Ihren Evaluierungsmetriken Retrieval-Fehler feststellen. Der größte Fehler besteht darin, das Chunking zu über-ingenieren, bevor die tatsächliche Leistung gemessen wurde. Einfach beginnen, messen, iterieren.

Chunking-Strategien auf Ailog testen

Möchten Sie verschiedene Chunking-Ansätze ohne Programmierung testen?

Die Ailog-Plattform ermöglicht Ihnen:

  • Dokumente hochladen und Chunking-Strategien nebeneinander vergleichen
  • Semantisches Chunking vs. feste Größe sofort testen
  • Chunk-Grenzen und Überlappungen visualisieren
  • Retrieval-Qualität mit echten Anfragen evaluieren
  • Die beste Strategie mit einem Klick in Produktion deployen

Kostenlos ausprobieren → Keine Kreditkarte erforderlich.

Nächste Schritte

Mit korrekt aufgeteilten Dokumenten ist der nächste Schritt die Auswahl und Konfiguration einer Vektordatenbank, um Embeddings effizient zu speichern und zu durchsuchen. Dies wird im folgenden Leitfaden über Vektordatenbanken behandelt.

Tags

découpagedocument processingrécupérationoptimizationchunking sémantiquelangchain

Verwandte Artikel

Ailog Assistant

Ici pour vous aider

Salut ! Pose-moi des questions sur Ailog et comment intégrer votre RAG dans vos projets !