Files
Orchestrator/docs/chunking-plan.md
T
ankn cfaf670100 Squashed 'bahn/wissensdatenbank/' content from commit 07a8196e
git-subtree-dir: bahn/wissensdatenbank
git-subtree-split: 07a8196e5f9e55d027f90485beb95f4006387669
2026-06-30 21:19:25 +02:00

17 KiB
Raw Blame History

Plan: Heading-basiertes Chunking (umgesetzt fuer INB)

Status: umgesetzt (Phase 1). Die Entscheidungen unten sind getroffen; das Chunking ist als deterministischer, embedding-freier Schritt implementiert und fuer die INB aktiv.

Getroffene Entscheidungen (Phase 1)

  • Ablage: separater Baum output/chunks/<scope>/<domaene>/<docslug>/ (Option A). Das Voll-Dokument in output/processed/ bleibt der primaere Feed.
  • Chunks getrennt vom approved-Feed (Parent-Document-Muster ueber parent_url/parent_hash).
  • Per-Quelle aktivierbar ueber options.chunk (Default off); gemeinsame Defaults in config/chunking.yaml, pro Quelle ueberschreibbar (effective_opts).
  • Nur deterministische, embedding-freie Strategien (headings | faq | recursive).
  • Contextual Retrieval (deterministisch): Kontext-Vorspann je Chunk (> Kontext: <Dokument> > <Abschnitt>), kein LLM/Embedding.
  • Inkrementell: jeder Chunk traegt parent_hash (Inhalt) + chunk_fingerprint (wirksame Optionen/Strategie). Es wird nur neu gechunkt, wenn sich einer der beiden aendert; deaktivierte Orte/verwaiste Chunks werden entfernt. Laeuft am Ende von src.main automatisch mit.
  • Lauf: python -m src.chunk --data output (offline auf output/processed). Erste Aktivierung: INB 2026 + INB 2027 (chunk: headings).

Code: src/transformers/chunker.py (Logik), src/chunk.py (Runner), config/chunking.yaml (Defaults), src/model.py (Chunk-Felder im Frontmatter).


Plan: Heading-basiertes Chunking (urspruengliches Konzept)

Ziel & Grundidee

Grosse Dokumente (v.a. INB, Regelwerke, lange Confluence-Baeume) sind als eine Markdown-Datei fuer Retrieval/Zitate unhandlich. Idee: zusaetzlich zur Voll-Datei Chunks entlang der Ueberschriften erzeugen.

Wichtig (Vorgabe):

  • Die Voll-Datei bleibt immer erhalten (kein Informationsverlust, Single Source of Truth).
  • Chunks sind additiv und abgeleitet -> jederzeit neu erzeugbar.
  • Wir stellen die Vektor-DB NICHT. Wer anschliesst, soll die Wahl haben: Voll-Dokument einlesen oder die fertigen Chunks nutzen oder selbst chunken.

Warum an Ueberschriften?

  • Strategie-uebergreifend nutzbar: das Chunking arbeitet auf dem erzeugten Markdown, nicht auf der Quelle. Damit ist es ein Transform-Schritt nach dem Extrahieren und funktioniert (potenziell) fuer ALLE Strategien.
  • Ueberschriften sind die natuerliche, semantische Schnittkante.
  • Befund INB-Hauptdokument 2026 (Review): ~751 KB, 746 ##-Ueberschriften, davon 91 mit „Ziffer X.Y…" (z.B. 7.3.1.1.1.1 Kapazität). Ideale Schnittpunkte + praezise Zitierbarkeit.

Eignung je Strategie

Strategie Ueberschriften vorhanden? Chunking sinnvoll?
pdf (pymupdf, INB/Regelwerk) ja (##), teils „Ziffer" sehr (grosse Dokumente)
confluence_tree/page ja (Hn aus storage->md) ja bei langen Seiten
confluence_faq je Frage ### ja (1 Chunk je Frage/Antwort)
sitemap/crawler (Web) meist (html2text #) mittel (Seiten oft kurz)
file/gitlab_md ja (Markdown) ja bei langen Dateien

-> Generischer Helfer chunk_by_headings(markdown, level, min_chars) + Opt-in pro Quelle.

Chunk-Format (Vorschlag)

Jeder Chunk = eigene Markdown-Datei mit Frontmatter, das die Herkunft referenziert:

---
kind: "chunk"                 # Voll-Dokument: kind: "document" (Default)
parent_url: "<url der Voll-Quelle>"
parent_hash: "<content_hash der Voll-Datei>"
section: "7.3.1.1.1.1 Kapazität"
ziffer: "7.3.1.1.1.1"         # nur wenn erkannt
chunk_index: 12
domain/tool/scope/tags/owners/contact/source: geerbt
content_hash: "<hash des Chunk-Texts>"
---
## 7.3.1.1.1.1 Kapazität
... Abschnittstext ...
  • Heading bleibt im Chunk-Text (Chunk ist selbst-erklaerend).
  • Stabiler Slug aus ziffer/Heading; Kollision -> Index anhaengen.

Ablage (Entscheidung offen, s.u.)

  • Option A: separater Baum output/chunks/<scope>/<domaene>/<docslug>/NNN-...md. Vorteil: output/processed/ bleibt „eine Datei pro Quelle/Seite", Chunks klar opt-in.
  • Option B: Unterordner neben der Voll-Datei: output/processed/.../<docslug>.chunks/. Vorteil: Chunks liegen direkt beim Dokument.

Empfehlung: Option A (sauberer Feed; processed/ = Dokumente, chunks/ = abgeleitet).

Konfiguration (pro Quelle, additiv, Default AUS)

options:
  chunk: headings        # off (Default) | headings
  chunk_level: 2         # welche Heading-Ebene schneidet (Default: kleinste vorhandene)
  chunk_min_chars: 200   # kleinere Chunks mit Vorgaenger zusammenfassen

INB-Quellen bekaemen chunk: headings. Alles andere bleibt zunaechst aus.

Umsetzungs-Skizze (spaeter)

  1. src/transformers/chunker.py: chunk_by_headings(md, level, min_chars) -> [(section, ziffer, text)]
    • make_chunks(doc) -> list[Document] (erbt Metadaten, setzt kind/parent/section/ziffer).
  2. src/model.py: Document um kind, parent_url, parent_hash, section, ziffer, chunk_index erweitern (Frontmatter).
  3. src/main.py: nach Filter/Freigabe, wenn source.options.chunk == "headings" und Doc approved -> Chunks erzeugen und ueber das Gate schreiben (nach output/chunks/).
  4. src/store.py + src/site.py: kind lesen; auf der Uebersicht Chunks standardmaessig ausblenden (Toggle „Chunks anzeigen"), damit die Bestandszahlen (Dokumente) sauber bleiben; eigener Zaehler fuer Chunks.
  5. Robustheit: Mini-Chunks zusammenfassen, sehr grosse optional spaeter weiter teilen (Absatz/Token-Budget, evtl. Overlap).
  6. Tests: Splitten je Level, Mini-Merge, Ziffer-Extraktion, Parent-Verknuepfung, content_hash stabil.

Phasen

  • Phase 1: generischer Chunker + nur fuer INB aktiv; zweites Artefakt; UI-Toggle.
  • Phase 2: weitere grosse Dokumente (Regelwerk, lange Confluence-Baeume).
  • Phase 3 (optional): token-bewusstes Sub-Splitting + Overlap.

Offene Entscheidungen

  1. Ablage: output/chunks/ (Option A, empfohlen) vs. Unterordner beim Dokument (Option B).
  2. Chunks in den „approved Feed" (output/processed/) aufnehmen oder bewusst getrennt halten (Empfehlung: getrennt, damit Voll-Dokument der primaere Feed bleibt).
  3. Heading-Ebene: automatisch kleinste vorhandene vs. pro Quelle konfiguriert.
  4. Mini-/Max-Groessen (chunk_min_chars, spaeter Token-Budget).
  5. Reihenfolge: zuerst INB (Phase 1) ja/nein.

Recherche (Stand 2025/2026) & begruendete Empfehlungen

Quellen (Inhalte fuer Compliance umformuliert, keine Originalzitate): Weaviate-/Firecrawl-Ueberblick, Digital Applied Retrieval Playbook 2026, CustomGPT Chunking Strategies, Langcopilot Practical Guide, Airbyte Chunking Strategies, Anthropic Contextual Retrieval.

Was die Forschung sagt (verdichtet)

  • Chunking entscheidet stark ueber die Qualitaet mehr als die Modellwahl. Ein Weaviate-Benchmark (Sept 2025) misst bis zu ~9 % Unterschied bei Recall zwischen bester und schlechtester Methode (gleicher Korpus/Retriever).
  • Recursive Splitting (erst an Ueberschriften, dann Absaetze, Saetze, Woerter) gilt breit als bester Allrounder/Default (gute Balance Qualitaet/Kosten).
  • Struktur-/Heading-basiertes Splitting ist ideal fuer technische Dokumente mit klarer Gliederung genau unser INB/Regelwerk-Fall.
  • Semantic Chunking bringt nochmal Genauigkeit, ist aber deutlich teurer (mehrfache Rechenkosten, teils ~14x langsamer) eher spaeter/optional.
  • Overlap bringt laut neueren Analysen (Jan 2026) kaum messbaren Nutzen -> als Default 0, nur optional aktivierbar.
  • Chunk-Groesse: verbreiteter Richtwert ~400800 Tokens; sehr grosse Chunks (Richtung ~2,5k Tokens „context cliff") verschlechtern Treffer.
  • Contextual Retrieval (Anthropic): jedem Chunk einen kurzen Kontext voranstellen (Dokumenttitel + Abschnittspfad) reduziert Retrieval-Fehler erheblich. Deterministisch (ohne LLM) machbar, indem wir die Heading-Breadcrumb in jeden Chunk schreiben.
  • Parent-Document-Retrieval: kleine Chunks zum Finden, grosses Dokument zum Antworten. Das ist genau das gewuenschte Muster „ein Dokument + zugehoerige Chunks".

Empfehlungen zu den offenen Entscheidungen

1) Ablage: separater Baum output/chunks/ (EMPFOHLEN)

  • Pro: output/processed/ bleibt „eine Datei pro Quelle/Seite" = stabiler, einfacher Feed; Chunks sind klar als abgeleitet/optional erkennbar; getrennt loeschbar/regenerierbar; Bestandszahlen auf den Pages bleiben sauber.
  • Contra: zwei Wurzelverzeichnisse; Konsument muss wissen, dass es beides gibt (loesen wir per Frontmatter parent_* + Doku auf der Chatbot-Seite).
  • Alternative B (Unterordner beim Dokument) vermischt Voll-Doc und Chunks im selben Baum -> Feed wird unuebersichtlich. Daher A.

2) Chunks NICHT in den primaeren output/processed-Feed (EMPFOHLEN)

  • Voll-Dokument bleibt der primaere, eindeutige Feed (1 Seite = 1 Datei). Chunks liegen in output/chunks/ mit parent_url/parent_hash -> klassisches Parent-Document-Muster.
  • Konsument hat die Wahl: nur processed/ (grob), nur chunks/ (fein) oder beides (Parent-Document-Retrieval). Wir geben die Vektor-DB nicht vor -> maximale Flexibilitaet.

3) Heading-Ebene: automatisch kleinste sinnvolle, pro Quelle ueberschreibbar

  • Default: feinste durchgaengig vorhandene Ebene erkennen (INB: ##).
  • chunk_level: N erlaubt manuelles Setzen, falls die Auto-Erkennung schlecht trifft.

4) Groessen/Overlap (Defaults, grounded)

  • chunk_min_chars: 200 (Mini-Abschnitte mit Vorgaenger zusammenfassen).
  • chunk_max_chars optional (z.B. ~46k Zeichen ≈ ~11.5k Tokens); zu grosse Abschnitte fallen per Recursive-Sub-Split kleiner.
  • chunk_overlap: 0 als Default (Overlap nur optional).
  • Breadcrumb-Prefix je Chunk (Dokumenttitel + Abschnittspfad) standardmaessig AN (billiger Contextual-Retrieval-Effekt).

5) Reihenfolge: zuerst INB (Phase 1) JA.

Chunk-Strategien als Menue (was die Tool-Eintragenden waehlen koennen)

Pro Quelle ueber options.chunk waehlbar (Default off):

chunk: Wert Was passiert Wofuer geeignet
off (Default) kein Chunking, nur Voll-Datei kurze Seiten, Kundeninfos
headings Split an Markdown-Ueberschriften (chunk_level) INB, Regelwerk, lange Confluence-Baeume
recursive Ueberschriften -> Absaetze -> Saetze, Zielgroesse chunk_size Doks ohne saubere Gliederung (manche PDFs/Webseiten)
faq je Frage/Antwort ein Chunk (Spezialfall headings auf ###) confluence_faq
pages ein Chunk je PDF-Seite PDFs mit unbrauchbaren Ueberschriften

Zusatz-Optionen (alle optional): chunk_level, chunk_size, chunk_min_chars, chunk_max_chars, chunk_overlap, chunk_breadcrumb: true|false.

Nicht im ersten Wurf (spaeter): semantic (Embedding-basiert, teuer) und contextual (LLM-generierter Kontext je Chunk) beide hohe Kosten, erst wenn Bedarf.

Empfohlener Startpunkt

  • Generischen headings- + recursive-Splitter bauen, Breadcrumb-Prefix an, Overlap 0, Ablage output/chunks/, Chunks getrennt vom Feed, parent_* im Frontmatter.
  • Phase 1 nur fuer INB aktiv (chunk: headings), dann Treffer evaluieren, dann ausweiten.

Recherche (Stand 2026) & fundierte Empfehlungen

Quellen (Auswahl, paraphrasiert; Inhalte zur Lizenzkonformitaet umformuliert):

Was die Recherche zeigt (Kernbefunde)

  • Die Chunk-Strategie beeinflusst die Retrieval-Qualitaet oft staerker als das Modell. Ein Weaviate-Benchmark (Sept 2025) nennt bis zu ~9 % Unterschied in der Trefferquote zwischen bester und schlechtester Methode auf demselben Korpus.
  • Struktur-/dokumentbewusstes Chunking (Ueberschriften, Tabellen, Codebloecke erhalten) gilt als entscheidend fuer strukturierte Inhalte; customgpt.ai berichtet hier deutliche Genauigkeitsgewinne. Genau das sind die INB/Regelwerke.
  • Recursive Splitting (~400-800 Token, 10-20 % Overlap) ist der gaengige Allzweck-Default.
  • Semantisches Chunking kann die Trefferquote spuerbar heben, ist aber teuer (jeder Satz wird eingebettet, teils ~14x langsamer) -> braucht ein Embedding-Modell.
  • Overlap-Mythos: eine Analyse (Jan 2026) findet kaum messbaren Nutzen von Overlap; bei semantischen Schnittkanten (Ueberschriften) ist Overlap ohnehin weniger noetig.
  • „Context Cliff" ~2.5k Token: sehr grosse Chunks „verwaessern" das Embedding -> Obergrenze sinnvoll.
  • Contextual Retrieval (Anthropic): ein kurzer Kontext-Vorspann pro Chunk (z.B. Dokumenttitel + Abschnittspfad) reduziert Retrieval-Fehler stark -> billig & deterministisch machbar.

Was das fuer UNS bedeutet (wichtige Einordnung)

Wir stellen die Vektor-DB nicht und wollen deterministische, reproduzierbare Artefakte in Git. Daraus folgt eine klare Linie:

  • Wir liefern, was man ohne Embedding-Modell sauber erzeugen kann: strukturerhaltende, ueberschriften-basierte Chunks + saubere Voll-MD. Das ist laut Recherche der mit Abstand wichtigste Hebel („clean, document-aware input").
  • Semantisches / late / contextual-embedding-Chunking gehoert zum Anschliesser (er hat Embedding-Modell + Vektor-DB). Wir wuerden es NICHT fest verdrahten wir liefern die ideale Vorlage dafuer.
  • Deshalb ist „ein Voll-Dokument + zugehoerige Chunks" genau richtig: maximale Wahl, kein Lock-in.

Empfehlung je offener Entscheidung

Entscheidung Optionen Empfehlung Begruendung
Ablage (A) separater Baum output/chunks/<scope>/... · (B) Unterordner beim Dok · (C) in output/processed/ A Voll-Dok bleibt der primaere, eindeutige Feed; Chunks klar opt-in/abgeleitet; Konsument waehlt „processed ODER chunks" ohne Doppel-Embedding.
Chunks in approved-Feed? rein / getrennt getrennt Verhindert, dass derselbe Inhalt doppelt im Index landet; output/processed bleibt „eine Datei pro Quelle".
Heading-Ebene fix / auto / konfigurierbar konfigurierbar mit smartem Default (kleinste sinnvolle Ebene; klein -> mergen, gross -> bis Zielband teilen) Recursive-Prinzip: Struktur respektieren, aber Zielgroesse halten (gegen Mini-Fragmente & Context Cliff).
Zielgroesse ~300-1200 Token Band, hartes Max < ~2000 Token gaengiger Default-Korridor; unter Context Cliff.
Overlap 0 / 10-20 % Default 0 (optional aktivierbar) „Overlap-Mythos"; Ueberschriften sind semantische Grenzen.
Kontext-Vorspann aus / an an (empfohlen): 1 Zeile „aus > " je Chunk Contextual-Retrieval-Effekt, deterministisch, billig.

Chunk-Strategien als Menue fuer Tool-Eintragende

Pro Quelle waehlbar ueber options.chunk (Default off). Bewusst nur deterministische, embedding-freie Verfahren Semantik-Chunking bleibt dem Anschliesser:

chunk: Was es tut Wann nutzen
off (Default) nur Voll-Dokument kurze Seiten, Standard
headings schneidet an Markdown-Ueberschriften; klein -> mergen, gross -> bis Zielband; ziffer/Abschnitt als Metadatum strukturierte, lange Dokumente (INB, Regelwerk, lange Confluence-Baeume)
faq ein Chunk je Frage/Antwort confluence_faq-Quellen
recursive groessenbasiert: Absatz -> Satz bis Zielband (ohne Embeddings) lange Dokumente ohne brauchbare Ueberschriften
pages (spaeter) ein Chunk je PDF-Seite paginierte PDFs (gewann NVIDIA-2024-Benchmark fuer paginierte Docs)

Gemeinsame Optionen: chunk_target_tokens (Default ~500), chunk_max_tokens (~1800), chunk_min_chars (~200), chunk_overlap (Default 0), chunk_context_header (Default an).

Bewusst NICHT angeboten (Begruendung dokumentieren): semantic/late/contextual-embedding -> brauchen ein Embedding-Modell und gehoeren in die Vektor-DB des Anschliessers. Wir liefern dafuer die saubere, strukturierte Vorlage.

Empfohlener Startpunkt (Phase 1)

INB-Quellen: chunk: headings, chunk_level: auto, chunk_target_tokens: 500, chunk_max_tokens: 1800, chunk_overlap: 0, chunk_context_header: on. Ablage unter output/chunks/allgemein/regulierung/inb-2026/<ziffer-oder-slug>.md. Voll-MD bleibt unveraendert in output/processed/.