Back to Home

📥 SUJBOT2 Indexing Pipeline

Fáze 1-5: Od dokumentu k prohledávatelnému vektorovému indexu (SOTA RAG 2025)

1
Hierarchy Extraction
~30-60s
Úkol: Extrahovat hierarchickou strukturu dokumentu (kapitoly, sekce, podsekce) pomocí IBM Docling, které používá pokročilou klasifikaci podle velikosti fontu a layoutu stránky.
🛠️ Nástroj
IBM Docling (open-source)
📊 Výstup
JSON hierarchie (depth=4)
🎯 Metoda
Font-size classification + layout analysis
📄 Implementace
src/docling_extractor_v2.py
📦 Datový tok:
PDF/DOCX → Docling Parser → Hierarchie (JSON):
{
  "doc_id": "document_name",
  "sections": [
    {"id": "1", "title": "Kapitola 1", "level": 1, "content": "...", "subsections": [...]}
  ]
}
Podporuje PDF, DOCX, HTML Hloubka: 4 úrovně
2
Summary Generation
Fast: ~1-2min | Eco: ~15-30min
Úkol: Vygenerovat GENERIC shrnutí pro celý dokument a každou sekci (150 znaků).
Hierarchický proces: Nejdřív se vygenerují section summaries (150 chars každá), pak se z nich složí document summary (také 150 chars). Tyto shrnutí se pak použijí jako kontext v SAC (Phase 3).
🤖 Model (Fast)
gpt-5-nano / gpt-4o-mini
💰 Model (Eco)
OpenAI Batch API (50% levnější)
📏 Section summary
150 znaků (každá sekce)
📏 Document summary
150 znaků (ze section summaries)
🔄 Proces
Bottom-up hierarchical (sections → document)
🎨 Styl
GENERIC (NOT expert!)
📄 Implementace
src/summary_generator.py
🔬 Research-backed design (Reuter et al., 2024):
Counterintuitive finding: GENERIC summaries fungují lépe než expert summaries!
• Expert shrnutí: "Článek 12 stanovuje sankce dle nařízení 2023/1234..."
• Generic shrnutí: "Dokument popisuje pravidla a sankce..."

Proč? Generic terminologie má lepší sémantickou shodu s běžnými user dotazy, které nepoužívají právní žargon.

Hierarchická generace: Document summary se vytváří z již vygenerovaných section summaries (bottom-up přístup) → žádné truncation, pokrytí celého dokumentu bez omezení velikosti.
📦 Datový tok (hierarchický bottom-up):
KROK 1: Hierarchie + LLM → Každá sekce dostane 150-char generic summary:
{
  "section_id": "1.2",
  "content": "Tento paragraf stanovuje...",
  "summary": "Pravidla pro registraci..." (150 chars)
}

KROK 2: Section summaries → Document summary (150 chars):
Section summaries: ["Pravidla pro registraci...", "Sankce za porušení...", ...]
↓ LLM syntéza ↓
Document summary: "Dokument popisuje pravidla a sankce..." (150 chars)

Výhoda: Žádné truncation, pokrytí celého dokumentu bez ohledu na velikost!
Research-backed Generic > Expert 150 chars optimum Hierarchical bottom-up
3
Multi-Layer Chunking + Contextual Retrieval
~10-20s (chunking) + ~2-5min (context gen)
Úkol: Rozdělit dokument do 3 vrstev pomocí RCTS metody a přidat bohatý context k chunks pomocí Contextual Retrieval (Anthropic 2024), což snižuje retrieval failures o 67%.
Hybrid přístup: Kombinuje SAC koncept (document summary z Phase 2) s pokročilým LLM-generated chunk-specific contextem.
📐 Metoda
RCTS (Recursive Character Text Splitting)
📏 Chunk size
500 znaků (optimální pro právní/tech docs)
🔗 Overlap
0 (RCTS řeší přirozeně via hierarchii)
🏗️ Vrstvy
L1 (Document), L2 (Section), L3 (Chunk - PRIMARY)
✨ Contextual Retrieval benefit
-67% retrieval failures (Anthropic)
🎯 Context length
50-100 slov (LLM-generated per chunk)
📄 Implementace
src/multi_layer_chunker.py
🔬 Multi-Layer Chunking + Contextual Retrieval (Lima 2024 + Anthropic 2024 + Reuter 2024):
1. RCTS > Fixed-size chunking: RCTS respektuje sémantické hranice (věty, odstavce) místo pevných 500 znaků.

2. Multi-layer indexing: 3 separátní indexy přinášejí 2.3x více relevantních chunků:
• L1 (Document level): Pro high-level dotazy ("Co říká zákon X?")
• L2 (Section level): Pro střední granularitu ("Pravidla pro registraci?")
• L3 (Chunk level): Pro detailní dotazy ("Specifická sankce za X?")

3. Contextual Retrieval (Anthropic 2024): LLM generuje chunk-specific context (50-100 slov) pro každý chunk:

📥 Vstupy pro context generaci (per chunk):
  • Document summary (150 chars z Phase 2) → globální kontext
  • Section hierarchy (např. "1.2.3 Sankce za porušení") → pozice v dokumentu
  • Preceding chunk (předchozí 500 chars) → kontext "co bylo před"
  • Following chunk (následující 500 chars) → kontext "co bude po"
  • Raw chunk (500 chars) → samotný obsah

🤖 LLM prompt:
"Give a short succinct context (50-100 words) to situate this chunk within the overall document for improving search retrieval."

📤 Výstup:
  • Generated context (50-100 slov) - vysvětluje, CO chunk diskutuje v rámci celého dokumentu

💾 Embedding & Storage:
  • Embedding: generated_context + "\n\n" + raw_chunk
  • Storage: pouze raw_chunk (context se stripne při retrievalu)

✨ Výsledek: Chunk "ví", o čem je celý dokument + kde v něm se nachází + co je okolo → -67% retrieval failures (Anthropic research)
📦 Datový tok (Contextual Retrieval):
1. RCTS Chunking:
Sekce "1.2.3 Sankce za porušení" → RCTS (500 chars) → raw chunks

2. Context Generation (per chunk):
Inputs → LLM:
  • Doc summary: "Dokument popisuje pravidla a sankce GDPR..."
  • Section: "1.2.3 Sankce za porušení"
  • Preceding: "[předchozí 500 chars]"
  • Current: "Článek 83 stanovuje sankce..."
  • Following: "[následující 500 chars]"

LLM → Generated context (50-100 slov):
"This section details the specific financial penalties and sanctions imposed under GDPR Article 83 for violations of data protection regulations, including both administrative fines and serious breaches."

3. Embedding & Storage:
FOR EMBEDDING:
augmented = "[Generated context]\n\nČlánek 83 stanovuje sankce..."

FOR STORAGE:
stored = "Článek 83 stanovuje sankce..." (bez context)

Výhoda: Každý chunk má bohatý kontext (doc summary + hierarchy + surrounding) → -67% retrieval failures!
RCTS optimum -67% retrieval failures 3 layers 500 chars/chunk LLM context (50-100 words) Anthropic 2024
4
Embedding + FAISS Indexing
Fast: ~2-3min | Eco: ~20-40min
Úkol: Vytvořit embeddingy pro všechny 3 vrstvy chunků a uložit je do 3 separátních FAISS indexů. Embeddingy obsahují context + raw_content, ale ukládá se pouze raw_content.
🤖 Model (cloud)
text-embedding-3-large (3072D)
💻 Model (lokální)
bge-m3 (1024D, free, GPU)
🗄️ Index typ
FAISS IndexFlatIP (cosine similarity)
📊 Počet indexů
3 separátní (L1, L2, L3)
💾 Batch size
100 (cloud) / 32 (local)
📄 Implementace
src/embedding_generator.py
src/faiss_vector_store.py
🔬 Context-aware embeddings (Anthropic 2024):
Key insight: Embedduj context + raw_content, ale ukládej pouze raw_content!

Proč?
• Embedding fáze: Context pomáhá modelu pochopit sémantiku chunku (SAC summary)
• Retrieval fáze: LLM dostane pouze raw_content (bez redundantního kontextu)
• Výsledek: Lepší embeddingy, čistší LLM kontext, žádná duplicita

3 separátní indexy: Místo 1 merge index používáme 3 specializované indexy → hierarchical search dokáže vybrat správnou vrstvu podle typu dotazu.
📦 Datový tok (embedding):
SAC chunks → Embedding Generator → 3 FAISS indexes:

FOR KAŽDÝ chunk (L1/L2/L3):
  embedding_input = doc_summary + "\n\n" + chunk_content
  vector = embed_model(embedding_input) # 3072D nebo 1024D
  
  faiss_index[layer].add(vector)
  metadata_store[chunk_id] = {
    "raw_content": chunk_content, # ← BEZ summary!
    "doc_id": "...",
    "section_id": "..."
  }
3072D embeddings 3 FAISS indexes Context-aware Batch processing
5
Advanced Retrieval Setup
~5-15s (setup only)
Úkol: Připravit 3 pokročilé retrieval komponenty, které se použijí při search (Phase 7). Tato fáze pouze inicializuje struktury - skutečné vyhledávání probíhá až při user query.
5A: Knowledge Graph Construction
Úkol: Extrahovat entity (osoby, organizace, místa, data, částky...) a vztahy (18 typů) z dokumentů a vytvořit graf.

Metoda: LLM-based entity extraction (GPT-5-nano nebo Claude Haiku) + NetworkX/Neo4j storage
Entity types: PERSON, ORG, LOCATION, DATE, MONEY, LAW, REGULATION, ...
Relationship types: REFERS_TO, AMENDS, SUPERSEDES, REQUIRES, ...
Využití: Multi-hop queries, entity-based filtering, relationship traversal

Implementace: src/graph/, src/graph_retrieval.py
Konfigurace: ENABLE_KNOWLEDGE_GRAPH=true
5B: Hybrid Search Initialization (BM25 + Dense + RRF)
Úkol: Připravit BM25 index pro lexikální vyhledávání a RRF fusion mechanismus.

Komponenty:
BM25 (lexical): Keyword-based search (exact matches, acronyms) - index se vytvoří z chunk textů
Dense (semantic): FAISS embedding search (sémantické podobnosti) - už máme z Phase 4
RRF (Reciprocal Rank Fusion): Kombinuje BM25 + Dense score lists → hybrid ranking

Výhoda: BM25 najde "GDPR", Dense najde "ochrana osobních údajů" → RRF spojí oba výsledky → +23% precision
Parametry: RRF k=60 (research-optimal)

Implementace: src/hybrid_search.py
5C: Reranker Loading (Cross-encoder)
Úkol: Načíst cross-encoder reranker model pro 2-stage retrieval.

2-stage retrieval:
1. Stage 1 (fast): Hybrid search vrátí top-100 candidates (~200ms)
2. Stage 2 (quality): Cross-encoder přehodnotí všechny páry (query, chunk) a vybere top-k (~300ms)

Modely: ms-marco-MiniLM, bge-reranker-large
Výhoda: +25% accuracy oproti pure hybrid search
DŮLEŽITÉ: ❌ NEPOUŽÍVAT Cohere reranker! (horší výsledky na právních dokumentech podle LegalBench-RAG)

Implementace: src/reranker.py
📦 Výstup Phase 5:
✅ Knowledge Graph: NetworkX/Neo4j instance s entitami a vztahy
✅ BM25 Index: Rank-BM25 index pro lexikální search
✅ Reranker Model: Cross-encoder (ms-marco nebo bge-reranker)
✅ HybridVectorStore: Wrapper spojující FAISS + BM25 + Reranker

→ Připraveno pro user queries v Phase 7!
+23% precision (hybrid) +25% accuracy (reranker) Knowledge graph 2-stage retrieval
5
Fází indexingu
3
FAISS indexy
500
Znaků/chunk (RCTS)
-58%
DRM redukce (SAC)
+23%
Precision (Hybrid)
+25%
Accuracy (Reranker)
2-3min
Indexing (Fast mode)