RAGFlow

Open-source RAG engine with deep document understanding

RAGFlow ingests heterogeneous documents — PDFs with scanned tables, slides, code books, audio, e-mails — and turns them into citable, searchable knowledge that LLMs can reason over. It ships its own deep-learning OCR/layout pipeline, a Agent Canvas Canvas & Execution — Canvas & Execution" class="xref">Graph-RAG construction stack, an editable agent-canvas DSL, and a polished web UI; not just a thin wrapper around an embedding model.

Python · TypeScript · Go · C++ DeepDoc OCR + Layout GraphRAG · RAPTOR · Agent Canvas Apache 2.0

12
Top-level modules
~700
Python files
1100
TS/TSX files (web)
218
Go files (internal)
115
C/C++ files (tokenizer)
14
Document types parsed
20+
Agent component types
10+
LLM provider adapters

🎯 Project Philosophy

When you first look at this codebase, the most striking thing is how much RAGFlow refuses to outsource. Most "RAG products" are 800 lines of Python that calls an embedding API and a chat API. RAGFlow ships its own Chinese-aware tokenizer (in C++ with a DART double-array trie), its own layout-detection and table-structure neural networks (PaddlePaddle/ONNX, in deepdoc/vision/), its own Graph-RAG construction stack with Leiden community detection, and its own agent-canvas DSL with iteration, loops, switches, and a code sandbox. Reading the source feels less like reading a "wrapper" and more like reading a small operating system for retrieval.

Several design principles emerge from the code patterns:

The implicit value system you can read in commits and naming: correctness of retrieval > raw latency, deployment optionality > opinionated stack, end-to-end ownership > vendor dependency. The team has clearly chosen to take on more code in exchange for fewer integration risks at runtime.

🏗️ Design Decisions

DecisionChoice MadeAlternativesWhy This Approach
Doc parsing strategyShip in-house OCR + layout NN (deepdoc/vision/)Outsource to Azure Form Recognizer, AWS Textract, Unstructured.ioLayout-aware chunking is the moat; vendor APIs lag on Chinese docs and don't expose bbox confidence; on-prem deploy must run airgapped
Backend frameworkFlask + Peewee ORM + worker queueFastAPI + SQLAlchemy + Celery; Django + DRFFlask blueprints map cleanly to the per-domain API surface (kb_app, dialog_app, document_app); Peewee is lighter than SQLAlchemy and the schema is simple enough; Redis queue avoids Celery's broker complexity
Heavy work isolationOut-of-process worker (rag/svr/task_executor.py) over RedisThreadpool inside Flask; gevent; CeleryParsing is CPU-/GPU-bound and unpredictable; pushing it out of the API process keeps request latency stable and lets ingest scale horizontally without touching the API tier
Workflow DSLJSON DAG canvas (agent.canvas.Graph) reused for ingest pipelinesPython-only flows (LangChain), YAML pipelines (Haystack)Visual graph editing in web/; one execution engine for both agent runs and parse pipelines (Pipeline(Graph)); JSON survives DB round-trip and version migration
Vector / doc storePluggable backends via rag/utils/storage_factory.pyTie hard to a single store (e.g. only ES, only Pinecone)Different enterprises already run ES, Infinity, OpenSearch, or OceanBase; lock-in to one would be a deal-breaker; the abstraction cost is one interface per store
TokenizerCustom DART-trie tokenizer in C++ (internal/cpp/) with cgo+ctypes bindingsjieba (Python pure), HanLP, OpenSearch built-inThe DART double-array trie is O(1) per char with cache-friendly memory layout; needed for Chinese segmentation at indexing throughput; cgo overhead is amortised over batches
Knowledge graphBoth Microsoft GraphRAG and LightRAG ports (rag/graphrag/general/ + light/)Pick one; build a custom graph extractorThe two represent different cost/quality points — General is heavyweight (community reports), Light is faster; users pick per-KB rather than the team picking for them
Frontend stackReact + Vite + Tailwind + shadcn/ui + ZustandNext.js full-stack; UmiJS (was used previously); Vue/SvelteThe agent-canvas page needs heavy client-side interaction (drag-drop graph, real-time SSE, complex state); Vite gives fast HMR; shadcn/ui provides accessible primitives without a runtime cost
Parallel Go serviceMirror DAO/handler/service layers in internal/Python-only; rewrite to Go entirely; gRPC sidecarGo gives ~10x throughput for thin HTTP paths and cleaner cgo into the C++ tokenizer; full rewrite would lose ML ecosystem; sharing MySQL keeps both stacks honest

System Architecture

How the modules compose. Edges are labelled with the contract at each boundary — what flows between modules and why the dependency exists.

flowchart TD
  subgraph Frontend["Frontend Tier"]
    WEB["web/ React SPA"]
  end
  subgraph API_Tier["Python API Tier"]
    API["api/ Flask blueprints"]
    APIDB["api/db Peewee models + services"]
    AGENT["agent/ canvas + components"]
  end
  subgraph Workers["Worker Tier"]
    EXEC["rag/svr/task_executor.py"]
    PIPE["rag/flow/Pipeline DAG"]
  end
  subgraph Core["Core RAG Engine"]
    APP["rag/app per ParserType chunkers"]
    DEEP["deepdoc parsers + vision"]
    NLP["rag/nlp tokenizer + search"]
    LLM["rag/llm provider adapters"]
    GRAPH["rag/graphrag GraphRAG + Light"]
    RAPTOR["rag/raptor recursive index"]
  end
  subgraph Stores["Storage Backends"]
    DOCSTORE["ES / Infinity / OpenSearch / OB"]
    OBJSTORE["MinIO / S3 / Azure / GCS / OSS"]
    REDIS["Redis queue + locks + progress"]
    MYSQL["MySQL Tenant / KB / Doc / Task"]
  end
  subgraph GoTier["Parallel Go Tier"]
    GOSVR["internal/ Gin server"]
    CPP["internal/cpp tokenizer"]
  end
  subgraph Interop["Interop"]
    SDK["sdk/ Python wrapper"]
    MCP["mcp/ MCP server"]
    COMMON["common/ shared utils"]
    MEMORY["memory/ chat memory"]
  end

  WEB -->|REST + SSE| API
  WEB -->|REST| GOSVR
  API --> APIDB
  API --> AGENT
  APIDB -->|ORM| MYSQL
  API -->|enqueue| REDIS
  REDIS -->|consume| EXEC
  EXEC --> APP
  EXEC --> PIPE
  EXEC --> RAPTOR
  EXEC --> GRAPH
  PIPE -->|extends Graph| AGENT
  APP --> DEEP
  APP --> NLP
  APP --> LLM
  GRAPH --> LLM
  GRAPH --> NLP
  EXEC -->|index chunks| DOCSTORE
  EXEC -->|store files| OBJSTORE
  AGENT -->|retrieval| NLP
  AGENT -->|chat/embed| LLM
  API -->|search| NLP
  NLP -->|query| DOCSTORE
  GOSVR --> MYSQL
  GOSVR --> CPP
  GOSVR -->|same schema| DOCSTORE
  SDK -->|HTTP| API
  MCP -->|via SDK| SDK
  MEMORY -->|persists in| DOCSTORE
  COMMON -.->|imported by| API
  COMMON -.->|imported by| EXEC

Modules

Core Engine

rag/

The heart of the engine — chunkers, retrieval, GraphRAG, RAPTOR, NLP, LLM

Per-document-type chunkers (rag/app/), the new DAG ingest pipeline (rag/flow/), Chinese-aware tokenizer (rag/nlp/), provider-agnostic LLM adapters (rag/llm/), Graph-RAG construction (rag/graphrag/), and pluggable storage connectors (rag/utils/).

111 .py filesRAPTOR + GraphRAG14 ParserTypes

deepdoc/

Layout-aware document parsing + neural OCR / table-structure recognition

Per-format extractors (PDF, DOCX, XLSX, PPT, HTML, EPUB, JSON, MD), alternative engines (mineru, docling, paddleocr, tcadp), plus PaddlePaddle/ONNX models for layout detection and table structure recognition.

37 .py files14 parsers5 vision recognizers

Orchestration & API

api/

Flask REST API — blueprints, Peewee ORM, layered services

Entry point ragflow_server.py; per-domain blueprints under api/apps/; database models in api/db/db_models.py; service layer in api/db/services/ handles document, dialog, KB, task, canvas, LLM operations.

98 .py filesFlask15+ services

agent/

Editable agent canvas DSL — DAG of LLM/retrieval/iteration components

The Graph execution engine (canvas.py) plus 20+ component types: LLM, agent-with-tools, categorize, switch, iteration, loop, message, invoke, data-operations. Tools include web search, code sandbox, SQL, retrieval invocation.

87 .py files20+ componentsJSON DSL

internal/

Parallel Go service — Gin handlers, GORM DAOs, cgo to C++ tokenizer

Mirrors the Python API for high-throughput deployments. Layered handler → service → dao → entity. Includes internal/cpp/ with the C++ rag-analyzer (DART trie + PCRE2 + opencc + re2) bound via a C-API and cgo.

218 .go files115 cpp/hGin + GORM

Frontend

web/

React + Vite + Tailwind + shadcn/ui SPA

Knowledge-base manager, chat with streaming + citations, agent canvas editor, document viewer, file manager, settings. State via Zustand; data via React Query; routing via React Router.

1100 .ts/tsxReact 18shadcn/ui

Shared / Interop

common/

Cross-cutting Python utilities — settings, constants, parsers, security

Shared settings.py, constants.py (LLMType, ParserType, TaskType enums), crypto/token/string utilities, SSRF guard, MCP tool-call connector, doc-store / data-source interfaces.

91 .py filesFlat module

memory/

Long-term chat memory subsystem

Per-tenant persistent memory layer for multi-session chats; vector + summary storage.

12 .py filesFlat module

mcp/

Model Context Protocol server — exposes RAGFlow as MCP tools

Lets external LLM clients (Claude Desktop, etc.) invoke RAGFlow KB-search and chat through the standard MCP interface.

3 .py filesMCP server + client

sdk/

Python SDK wrapping the REST API

Programmatic client used by the MCP server, examples, and external integrations. Modules cover chat, KB, document, agent.

19 .py filesHTTP wrapper

tools/

DevOps and data-loading utility scripts

Misc CLI utilities for migration, data import, model conversion.

24 .py filesCLI

admin/

Server administration tooling

Tenant management, system maintenance, user administration helpers.

14 .py filesAdmin CLI
LevelWhat You'll FindWhen to Use
0 — Project Hub (this page)Project philosophy, design decisions, module map, end-to-end data flowsGetting started, choosing where to dive in
1 — Module Overview (e.g., rag_doc/index.html)Module purpose, sub-module cards, narrated walkthrough, algorithm spotlight, failure analysisUnderstanding a module's role and design choices before reading code
2 — Sub-Module Deep Dive (e.g., rag_doc/graphrag/index.html)Annotated code walkthroughs, design rationale, edge cases, configuration knobs, real code examplesImplementing a feature, debugging, or extending a sub-module
Focus Pages (e.g., rag_doc/graphrag/leiden-community-detection/)Algorithm trace, alternatives comparison, complexity analysis, failure recoveryDeeply understanding a specific mechanism (why Leiden vs Louvain, how DART trie works, etc.)

🔗 Key Data Flows

Three flows you should understand before reading individual modules. Note the annotations explaining why each hand-off occurs and where latency lives.

Flow A — Ingest a PDF into a knowledge base

sequenceDiagram
    participant U as User (web/)
    participant API as api/apps/document_app
    participant DB as MySQL (Document, Task)
    participant OBJ as MinIO/S3
    participant Q as Redis Queue
    participant W as rag/svr/task_executor
    participant DD as deepdoc parsers + vision
    participant CHK as rag/app chunker
    participant LLM as rag/llm/embedding
    participant DS as ES / Infinity
    U->>API: POST /v1/document/upload (multipart)
    API->>OBJ: write raw file
    Note over API,OBJ: Heavy bytes never touch the API process beyond a stream
    API->>DB: insert Document + Task rows
    API->>Q: LPUSH task_id
    API-->>U: 200 with task_id (returns fast)
    Note over U,API: API stays unblocked; ingest is async
    Q-->>W: BRPOP task_id
    W->>OBJ: read file
    W->>DD: parse layout + OCR if scanned
    Note over W,DD: deepdoc gives bbox-aware text + tables
    W->>CHK: chunk per ParserType (naive/paper/manual/...)
    CHK->>LLM: embed each chunk
    LLM-->>CHK: vectors
    CHK->>DS: bulk index chunks + vectors
    W->>DB: update Task progress (also pushes Redis log)
    Note over W,DB: progress visible to web/ via SSE polling

Flow B — Chat query with retrieval-augmented generation

sequenceDiagram
    participant U as User (web/ chat)
    participant API as api/apps/restful_apis
    participant DLG as DialogService
    participant SRC as rag/nlp/search
    participant DS as ES / Infinity
    participant RR as rag/llm/rerank_model
    participant CHT as rag/llm/chat_model
    U->>API: POST /v1/conversation/completion (SSE)
    API->>DLG: build LLMBundle + retrieve
    DLG->>SRC: hybrid query (BM25 + dense)
    SRC->>DS: search content_ltks + vector
    DS-->>SRC: top-K candidates
    SRC->>RR: rerank top-K
    RR-->>SRC: scored top-N
    SRC-->>DLG: chunks + citations
    Note over DLG: Compose prompt with citations
    DLG->>CHT: stream completion
    CHT-->>DLG: token stream
    DLG-->>API: SSE token frames
    API-->>U: text/event-stream
    Note over API,U: Citations link back to original chunks for trust

Flow C — Run an agent canvas (or ingest pipeline)

sequenceDiagram
    participant U as User (web/ canvas)
    participant API as api/apps canvas
    participant G as agent.canvas.Graph
    participant N1 as Node Begin
    participant N2 as Node LLM or AgentWithTools
    participant N3 as Node Iteration or Switch
    participant T as agent/tools or rag/llm
    U->>API: run canvas (DSL JSON)
    API->>G: instantiate Graph(dsl)
    G->>N1: execute begin
    N1-->>G: initial variables
    G->>N2: schedule next ready node
    N2->>T: invoke LLM / tool / retrieval
    T-->>N2: result
    N2-->>G: write outputs to var scope
    Note over G,N2: scheduler picks edges by topological order + branch conditions
    G->>N3: evaluate switch/iteration
    N3-->>G: select next path or sub-graph
    Note over N3: iteration runs sub-graph per item with isolated scope
    G-->>API: SSE per-component progress
    API-->>U: live trace

How the Python and Go Tiers Connect

RAGFlow keeps a parallel Go service. Reading the directory layout, both stacks share the same MySQL schema and the same doc-store; neither is canonical. The Go side handles high-throughput HTTP paths and binds the C++ tokenizer through cgo for performance.

sequenceDiagram
    participant Web as web/ SPA
    participant Py as Python api/ (Flask)
    participant Go as Go internal/ (Gin)
    participant DB as MySQL (shared)
    participant CPP as C++ rag_analyzer
    participant DS as Doc-store (shared)
    Web->>Py: heavy ops (upload, agent run, chat, GraphRAG build)
    Web->>Go: thin reads (search, list, fetch)
    Py->>DB: write tasks, docs, chats
    Go->>DB: read same schema
    Go->>CPP: cgo tokenize_query
    CPP-->>Go: terms + weights
    Go->>DS: search hybrid
    Py->>DS: index + search
    Note over Py,Go: They never call each other directly — coupling is via DB + doc-store
Key insight: The Python tier owns state-changing work (ingest, agent runs, chat sessions). The Go tier specialises in read-heavy paths (search, list). The boundary is shared MySQL + doc-store, not RPC. This means schema migrations must be coordinated, but neither tier becomes a bottleneck for the other.

Directory Map

Project source tree
ragflow/
├── api/                       ← Flask REST API server (entry: api/ragflow_server.py)
│   ├── apps/                    ← Blueprints: document, llm, restful_apis, sdk, services, auth
│   ├── db/                      ← Peewee models + services + joint_services
│   └── common/, utils/, validation.py
├── rag/                       ← Core RAG engine
│   ├── app/                     ← Per-ParserType chunkers (naive, paper, manual, qa, table, ...)
│   ├── flow/                    ← New DAG ingest pipeline (Pipeline extends agent.canvas.Graph)
│   ├── nlp/                     ← rag_tokenizer + search/query rewriting + term-weight
│   ├── llm/                     ← Provider adapters (chat / embedding / rerank / cv / ocr / tts)
│   ├── graphrag/                ← Microsoft GraphRAG-General + LightRAG variants + Leiden
│   ├── utils/                   ← Pluggable doc-store + object-store backends + Redis
│   ├── svr/                     ← task_executor.py, cache_file_svr, sync_data_source
│   ├── prompts/                 ← System prompt templates
│   ├── res/                     ← Resource files (dictionaries, etc.)
│   └── raptor.py                ← RAPTOR recursive abstraction index
├── deepdoc/                   ← Deep document parsing
│   ├── parser/                  ← pdf, docx, xlsx, ppt, html, md, json, epub, figure, resume, ...
│   └── vision/                  ← OCR + layout + table-structure recognizers (PaddlePaddle/ONNX)
├── agent/                     ← Agent canvas DSL
│   ├── canvas.py                ← Graph execution engine
│   ├── component/               ← 20+ node types
│   ├── tools/                   ← External integrations (web search, code, SQL, retrieval)
│   ├── sandbox/                 ← Code-exec sandbox
│   ├── templates/               ← Pre-built canvas DSL JSONs
│   └── plugin/                  ← Third-party plugin loader
├── internal/                  ← Parallel Go service
│   ├── server/, router/, handler/, service/, dao/, entity/
│   ├── engine/, storage/, cache/, tokenizer/, common/, utility/
│   └── cpp/                     ← C++ rag_analyzer (DART trie + opencc + pcre2 + re2)
├── web/                       ← React SPA
│   └── src/{pages, components, services, hooks, layouts, locales, theme, routes, utils, lib}
├── common/                    ← Cross-cutting Python utilities
├── memory/                    ← Long-term chat memory subsystem
├── mcp/                       ← Model Context Protocol server
├── sdk/                       ← Python SDK wrapping REST
├── tools/                     ← DevOps / data-loading scripts
├── admin/                     ← Admin tooling
├── docker/                    ← Compose files + dockerfiles
├── conf/                      ← Runtime config + model lists
├── helm/                      ← Kubernetes Helm chart
├── docs/                      ← User-facing markdown documentation
├── test/                      ← Tests (pytest + playwright)
├── pyproject.toml             ← uv-managed Python deps
├── Dockerfile                 ← Production image
└── README.md

Build & Tech Stack

Languages

Python 3.10+ (backend), TypeScript/React (web), Go 1.22+ (internal), C++17 (tokenizer)

Backend Framework

Flask + Peewee ORM + Gunicorn workers; Quart support for async paths

Frontend Stack

React 18 + Vite + Tailwind + shadcn/ui + Zustand + React Query + React Router

Storage

MySQL (state); ES / Infinity / OpenSearch / OceanBase (chunks + vectors); MinIO / S3 / Azure / GCS / OSS / OpenDAL (objects); Redis (queue + locks + progress)

ML / Inference

PaddlePaddle + ONNX runtime (layout, OCR, TSR); embedding/rerank/chat via vendor adapters (OpenAI, Bedrock, Tongyi, Ollama, Xinference, ...)

Build & Dev

uv sync --python 3.12 --all-extras; Docker Compose; pre-commit; ruff; pytest; npm + Vite