RAG (Retrieval-Augmented Generation) — The Semantic Retrieval Engine
The Semantic Retrieval Engine
Multi-format chunking, hybrid retrieval (keyword + semantic + graph), hierarchical summarization via RAPTOR, entity resolution, and background task execution.
🎯 Why This Module Exists
The RAG (Retrieval-Augmented Generation) module is the semantic retrieval engine that powers every knowledge-based operation in RAGFlow. Without this module, the system would have no way to intelligently search documents, reason about relationships, or synthesize multi-source answers. The RAG module orchestrates a sophisticated pipeline: from multi-format document chunking (14 document-type handlers), through hybrid keyword-semantic retrieval with entity graph reasoning, to hierarchical summarization via RAPTOR. It balances precision (BM25 keyword matching), recall (dense semantic embeddings), and graph-based reasoning to surface the most relevant context. This module exists separately because retrieval is a fundamentally different concern from indexing, generation, and orchestration—each with its own performance bottlenecks and optimization strategies. The entire system's quality depends on RAG relevance; a weak retrieval engine cannot be fixed by a better LLM. — Replace with 150+ words explaining what problem this module solves, why it exists as a separate module (not merged into something else), and what the system would look like without it. Use narrative voice: "Without this module, every component would need to..."
💡 Real-world analogy
Imagine a massive library where you're the retrieval specialist. You understand that books (documents) have multiple ways to be found: by title (keyword search), by theme and narrative flow (semantic search), and by how different ideas in the library relate to each other (entity graphs). When someone asks a question, you don't just hand them one book—you intelligently combine keyword lookups with semantic similarity to find the most relevant sections, then trace relationships between concepts to enrich the answer. That's what RAG does: it's the librarian that transforms vague queries into precise, contextual information. — A vivid metaphor mapping this module's core concept to everyday life. 3-5 sentences.
Trait-1 Trait-2 Trait-3
Architecture
flowchart LR
subgraph GroupA["Group A"]
A1["Component 1"] --> A2["Component 2"]
end
subgraph GroupB["Group B"]
B1["Component 3"] --> B2["Component 4"]
end
A2 --> B1
Data Flow
flowchart TD Input["Input"] --> Process["Processing"] --> Output["Output"]
🚶 Step-by-Step Narrated Walkthrough
Follow a single user query to retrieval result as it flows through the entire RAG (Retrieval-Augmented Generation) pipeline:
- Query arrives at RAG module — User query enters the pipeline. The system determines if it's a search, summarization, or chat request. Typical latency: <1ms.
- Query encoding — The query is tokenized and embedded using a dense embedding model (e.g., BGE-large). Simultaneously, keyword analysis (BM25 tokenization) prepares it for hybrid retrieval. Latency: ~50-200ms depending on model.
- BM25 keyword search — Traditional TF-IDF based search against inverted index. Fast O(log n) lookup. Returns top-k keywords matches. Latency: ~5-20ms.
- Dense semantic search — Vector similarity search against embedding indices (Elasticsearch, Infinity, ONNX). Returns semantically similar chunks even with different keywords. Latency: ~20-100ms depending on index size.
- Entity graph traversal — If entity relationships exist, traverse the knowledge graph for related concepts and entities. Adds tertiary ranking signal. Latency: ~10-50ms.
- Result fusion — Combine BM25 scores (40%) + dense scores (60%) + entity signals. Re-rank by combined score. This is where RAG's "hybrid" advantage emerges. Latency: <5ms.
- Deduplication & filtering — Remove duplicate chunks, filter by confidence threshold, apply any ACL rules. Latency: <5ms.
- Context window preparation — Truncate or expand results to fit LLM context window. Preserve order and inter-chunk relationships. Latency: <5ms.
- Optional: hierarchical summarization — If context is too large, use RAPTOR (Recursive Abstractive Summarization over Tree Structures) to compress while preserving key facts. This involves clustering chunks, LLM summarization, and building a summary tree. Latency: ~1-5 seconds (only when needed).
- Final result to LLM — The combined ranked context list is passed to the generation module. The LLM uses this context to synthesize an answer. RAG's job is complete; now generation takes over. Latency: <1ms for RAG handoff.
Key insight: RAG (Retrieval-Augmented Generation) owns X. {{SIBLING_MODULE}} owns Y. The protocol boundary handles the translation between them.-->
🏗️ Design Decisions
| Decision | Choice Made | Alternatives Considered | Why This Approach |
|---|
| Decision | Choice Made | Alternatives Considered | Why This Approach |
|---|---|---|---|
| Hybrid Retrieval | 40% BM25 + 60% dense + graph | Pure keyword, pure semantic, pure graph | Keyword catches exact matches (high precision), dense catches semantic shifts (high recall), graph adds reasoning. Weighted combination balances all three. |
| Chunking Strategy | 14 document-type handlers | Single generic chunker, no structure | Different document types (PDFs, tables, code, books, emails) have different natural breakpoints. Type-aware chunking preserves semantics and table structure. |
| RAPTOR for Summarization | Recursive clustering + LLM summarization | Simple truncation, single-level summarization | Preserves hierarchical meaning. When context is huge, RAPTOR recursively builds a summary tree, letting the LLM see both detail and overview without token explosion. |
| Entity Agent Canvas Canvas & Execution — Canvas & Execution" class="xref">Graph | Leiden community detection + LLM extraction | No entity reasoning, simple keyword co-occurrence | Leiden's stochastic optimization finds natural entity clusters without hardcoded rules. LLM extracts relationships with reasoning. Graph enables cross-document reasoning. |
| Storage Abstraction | Factory pattern with 10+ backends | Single hard-coded storage backend | Users may deploy to S3, MinIO, Azure, GCS, or on-prem OpenDAL. Abstraction prevents vendor lock-in and allows switching without code changes. |
| Background Task Execution | Redis-coordinated task queues (SVR) | Synchronous indexing, thread pool | Indexing can be slow (millions of docs). Redis coordination allows distributed workers. Async indexing doesn't block the API. |
🔬 Algorithm Spotlight
RAPTOR: Hierarchical Summarization via Clustering
The Problem: What specific problem does this algorithm solve?
The Approach: How does it work, step by step, in plain English?
Why This Algorithm: What alternatives exist and why weren't they chosen? What are the time/space complexity trade-offs?
graph TD
A[Input] --> B{Decision Point}
B -->|Case 1| C[Fast Path]
B -->|Case 2| D[Complex Path]
C --> E[Output]
D --> F[Sub-step] --> E
style C fill:#e8f5e9
style D fill:#fff3e0
Trace through an example
Given: Example input
Step 1: What happens first and why
Step 2: What happens next — note the key decision here
Result: Expected output, and what would happen if the algorithm were naive
⚠️ What Could Go Wrong
| Failure Mode | Trigger | Detection | Recovery / Mitigation |
|---|---|---|---|
| Empty result set | Query has no keyword or semantic matches in index | Fusion returns 0 results or all scores below threshold | Return empty results with explanation. Suggest clarifying query or expanding search scope. Log for analytics to find indexing gaps. |
| Embedding model unavailable | Embedding service (local ONNX, remote API) is down | HTTP 503 or connection timeout on embedding call | Fall back to keyword-only search (BM25). This degrades recall but preserves functionality. Alert ops team. |
| Entity graph corruption | Graph database inconsistency after partial update | Entity lookup returns contradictory relationships or infinite loops | Skip entity graph signal for this request. Cache hit rate drops but system doesn't crash. Trigger async graph repair job. |
| Context explosion from RAPTOR | Summarization LLM calls fail or are very slow with huge inputs | RAPTOR tree-building takes >10 seconds or hits token limit | Stop RAPTOR recursion early, return best current summary node. Degrade gracefully rather than timeout. |
| Stale index / write-read consistency | New documents indexed but not yet searchable; query issued before index propagates | User reports "I just uploaded a doc but it doesn't show up in results" | Add index refresh delay (eventual consistency model). Offer explicit "refresh index" endpoint for impatient users. |
⚡ Performance Profile
Hot Paths
- BM25 search: O(log n) inverted index lookup per query term. Typically 5–20ms for 1M-document corpus. Dominates when query is very selective (few matching docs).
- Dense embedding search: O(n) or O(log n) depending on index type (linear for brute-force, logarithmic for HNSW/IVF). 20–100ms for 1M vectors. Dominates when query has semantic shifts.
- Fusion & ranking: O(k log k) where k = number of returned candidates (typically 100–500). <5ms. Negligible compared to search.
- RAPTOR summarization (optional): O(n log n) for clustering + O(log n) LLM calls (tree depth). Only triggered for large result sets. 1–5 seconds but runs offline if possible.
Resource Usage
- Memory: Embedding indices live in-memory (e.g., HNSW graph). A 1M-document corpus with 768-dim embeddings ≈ 3GB. Chunking buffers are temporary (freed after indexing).
- I/O: BM25 index stored on disk (typically 10–20% of chunk data size). Accessed via memory-mapped files. Minimal I/O except during index rebuild (background job via SVR).
- Network: If embedding model is remote (e.g., OpenAI API), adds 500ms–2s latency per query. Consider local ONNX models for privacy and speed.
Sub-Modules
app/
Multi-format document chunking strategies.
- 14 chunker implementations
- Format-aware semantic boundaries
- Preserve table & code structure
flow/
DAG-based retrieval pipeline orchestration.
- Graph execution engine
- Pluggable chunker selection
- Parser & extractor framework
nlp/
Tokenization, query analysis, term weighting.
- DART trie tokenizer (Rust FFI)
- CJK-aware segmentation
- Query synonym expansion
llm/
Multi-provider LLM adapters and embeddings.
- Chat, embedding, reranking models
- Vision (OCR, CV) support
- Provider abstraction
graphrag/
Entity relationship extraction and reasoning.
- Microsoft GraphRAG & LightRAG
- Leiden community detection
- Entity resolution & linking
utils/
Storage abstraction and index backends.
- 10+ storage providers
- Encryption & compression
- Factory pattern for extensibility
svr/
Background task execution and coordination.
- Redis-backed task queues
- Distributed indexing
- Cache & sync services
raptor/
Hierarchical recursive summarization trees.
- UMAP + Gaussian Mixture clustering
- Multi-level LLM summarization
- Tree traversal & compression
Directory Map
Source tree for RAG (Retrieval-Augmented Generation)
rag/
├── app/ ← 14 document-type chunkers (naive, paper, book, manual, presentation, qa, table, resume, picture, audio, email, tag, one, laws)
├── flow/ ← DAG pipeline orchestration (pipeline.py, base.py, parser/, chunker/, extractor/)
├── nlp/ ← Tokenization & query analysis (rag_tokenizer.py, search.py, query.py, term_weight.py, synonym.py)
├── llm/ ← LLM adapters (chat, embedding, rerank, cv, ocr, sequence2txt, tts)
├── graphrag/ ← Entity graphs & relationship extraction (general/, light/, leiden, entity_resolution, search)
├── utils/ ← Storage backends (es/, infinity/, opensearch/, ob/, minio/, s3/, azure/, gcs/, oss/, opendal/, encrypted/)
├── svr/ ← Background services (task_executor.py, cache_file_svr.py, sync_data_source.py, discord_svr.py)
├── raptor.py ← Hierarchical summarization (UMAP, GMM clustering, tree building)
└── __init__.py