DlightRAG
DlightRAG is a production ready multimodal RAG service built on LightRAG. It offers superior context intelligence, great accuracy with citation / highlight grounding, and unified interfaces for REST, Web, MCP, and Python SDK clients. It is designed for developers, seasoned users and teams who need a reliable RAG core service with cutting edge features integrated into their workflows and products.
Status: Python 3.14. Storage: PostgreSQL 18 ecosystem. License: Apache-2.0.
Architecture At A Glance
Clients
-> REST / Web / MCP / SDK adapters
-> RAGServiceManager
-> RAGService
-> LightRAG main
-> PostgreSQL 18 storage ecosystem
DlightRAG has one unified production RAG path: LightRAG provides fusional one-hop graph traversal and vector retrieval. DlightRAG adds product-layer metadata governance, hybrid BM25 sparse retrieval, fused visual-vector alignment, orchestration, citations, highlighting and standardized interfaces. The full runtime and code-layer view is in docs/architecture.md.
Choose Your Deployment Path
| Path | Use this when | PostgreSQL | Parser endpoint | Security | Start here |
|---|---|---|---|---|---|
| Local Docker | Developer machine, Web UI, smoke tests | Compose PG18 | Host-native MinerU (default) or optional Docling profile | auth_mode: none on loopback |
Quick Start |
| Native API | API process runs on host, PostgreSQL stays in Docker | Compose PG18 | Any reachable configured MinerU or Docling endpoint | Local or explicit auth | Native API Variant |
| Shared service | Remote users, agents, team workspace | Managed or self-hosted PG18 | Official MinerU API or independent parser service | simple or jwt |
PostgreSQL, Configuration, Security |
| Enterprise | Multi-user internal product | Managed PG18 | Independently operated parser service | jwt + JWKS, optional claim access control |
Security, PostgreSQL, Configuration |
Do not install a parser into the DlightRAG app container. Configure one
parser_sidecars.mineru or parser_sidecars.docling block; DlightRAG derives
LightRAG routing automatically. If both blocks are present, MinerU takes
priority. On macOS, keep MinerU as a native host process for MLX/MPS, or use the
optional Docling Compose profile.
Quick Start
Prerequisites. Install Docker + Compose
(runs the API and PostgreSQL), uv (builds the
isolated MinerU sidecar environment), plus git and make. DlightRAG targets
Python 3.14; uv installs it for you (uv python install 3.14), so a system
Python is not required for the Docker path.
# Install uv — macOS/Linux (see the uv docs for the Windows PowerShell command)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install make if you don't have it (git is usually already present):
# macOS xcode-select --install # or: brew install make
# Debian/Ubuntu sudo apt-get install -y make
# Fedora/RHEL sudo dnf install -y make
# Windows no POSIX make on Windows — use WSL2 (Ubuntu): install Docker
# Desktop with the WSL2 backend, then inside WSL2 follow the
# Debian/Ubuntu line above. uv, make, and Python 3.14 all live
# inside WSL2 (a Linux environment), not on Windows.
The Docker Quick Start does not require uv sync — DlightRAG itself runs
inside containers, and make mineru-install builds its own isolated
.venv-mineru. Run uv sync only for the Native API Variant
or development.
One-command setup (recommended)
From a fresh clone, an interactive wizard configures your models, selects MinerU (local/official) or Docling (bundled/external), brings up the stack, and ends with a clickable Web UI link:
git clone https://github.com/hanlianlu/dlightrag.git
cd dlightrag
uv run prerequisite_setup.py
It writes config.yaml and .env for you (with timestamped backups) and is safe
to re-run. The wizard does not preserve the checked-in model choices: the minimum
path writes only llm.default plus embedding, while the custom path replaces
role-specific LLM blocks with the roles you choose. Prefer the manual steps below
if you'd rather configure everything by hand.
Manual setup
- Clone the repo and create a secrets file:
git clone https://github.com/hanlianlu/dlightrag.git
cd dlightrag
cp .env.example .env
Fill secrets in .env:
DLIGHTRAG_LLM__DEFAULT__API_KEY=...
DLIGHTRAG_EMBEDDING__API_KEY=...
DLIGHTRAG_LLM__ROLES__EXTRACT__API_KEY=...
DLIGHTRAG_LLM__ROLES__KEYWORD__API_KEY=...
DLIGHTRAG_LLM__ROLES__QUERY__API_KEY=...
DLIGHTRAG_LLM__ROLES__VLM__API_KEY=...
DLIGHTRAG_RERANK__API_KEY=...
These match the checked-in config.yaml, which configures DeepSeek extract and
keyword roles, OpenRouter default, query, and VLM roles, plus Voyage reranking.
Role overrides are
atomic: an omitted or blank key falls back to the complete default model
configuration instead of combining its endpoint with the default key. If you
remove role-specific model blocks or switch rerank back to chat_llm_reranker,
the corresponding role/rerank keys can be omitted. Reserve api_key: null for
a genuinely unauthenticated endpoint.
Normal behavior lives in config.yaml: model names, parser sidecar settings, metadata schema, retrieval breadth, auth mode, Langfuse behavior, and deployment endpoints. Deep config reference is in docs/configuration.md.
- Choose one parser. The checked-in config uses a native MinerU sidecar:
cp .env.mineru.example .env.mineru
make mineru-install
make mineru-api
make mineru-api serves http://127.0.0.1:8210 by default and blocks in the
current terminal. Its config block uses http://host.docker.internal:8210,
which is reachable from the DlightRAG containers.
To run MinerU in the background instead (launchd on macOS, systemd --user on
Linux/WSL2), use the service targets — one command starts both the API
backend and the Gradio WebUI. The WebUI reuses that same backend automatically,
so it needs no extra setup and never loads a second copy of the models:
make mineru-service-install # install + start at login
make mineru-service-status # also: -start / -stop / -logs / -uninstall
The WebUI opens at http://127.0.0.1:7860 (unauthenticated — keep it on
loopback). Set MINERU_GRADIO_ENABLE=false in .env.mineru to manage the API
backend alone.
Alternatively, comment/remove the MinerU block in config.yaml, enable the
commented Docling block, and start the optional official CPU image:
docker compose --profile docling up -d
The image follows quay.io/docling-project/docling-serve-cpu:latest. Set a
different official image with DOCLING_SERVE_IMAGE; external Docling users set
the block's endpoint instead and do not enable the profile.
- Start DlightRAG and PostgreSQL:
docker compose up -d
docker compose ps
This starts:
| Service | Purpose | Host port |
|---|---|---|
dlightrag-api |
REST API + Web UI | 127.0.0.1:8100 |
dlightrag-mcp |
MCP streamable HTTP server | 127.0.0.1:8101 |
postgres |
PG18 ecosystem | 5432 |
The upstream LightRAG graph browser is opt-in: docker compose --profile gui up -d
serves it on 127.0.0.1:9621.
- Open the Web UI:
http://localhost:8100/web/
Upload documents or images from the Files panel, then ask a question.
Native API Variant
Use this when the API process should run on the host while PostgreSQL stays in Docker:
docker compose up -d postgres
uv sync
DLIGHTRAG_PARSER_SIDECARS__MINERU__LOCAL_ENDPOINT=http://127.0.0.1:8210 \
uv run dlightrag-api
A native run's managed input root is the host ./dlightrag_storage/inputs/<workspace>,
so files dropped there are ingested by name; paths outside it are rejected on
every surface. The checked config is Docker-first, so the
command overrides its Docker host alias with the native loopback endpoint. A
native Docling deployment likewise sets its active block endpoint to
http://127.0.0.1:5001.
Use DlightRAG
Web
The Web UI is served by the REST API at /web/. It supports workspace
selection, file/folder upload, durable principal-scoped conversations and
current-turn images, citations, source panels, and semantic highlights. The
Web-only conversation lifecycle provides New chat, select, rename, delete, and
reload persistence with 30-day inactivity retention. Search in: All authorized workspaces is the answer default; the independent Files in selector remains a
single-workspace file-management target.
REST, MCP, and Python answer/retrieve calls remain stateless. Answer calls
accept an optional caller-supplied history of prior turns for multi-turn
follow-ups, but never a Web conversation ID or server-stored history: the client
owns conversation storage and re-sends the turns it wants on each request. Web
current-image admission is configurable and defaults to three
images at 15 MiB each. Durable current-turn images always have priority over any
historical image selection; historical images that miss a transport slot
contribute their stored text descriptions rather than raw pixels.
REST
REST ingest starts durable background jobs. Poll the job endpoint for status.
curl -X POST http://localhost:8100/ingest \
-H "Content-Type: application/json" \
-d '{"source_type": "local", "path": "report.pdf"}'
curl http://localhost:8100/ingest/jobs/<job_id>
curl -X POST http://localhost:8100/answer \
-H "Content-Type: application/json" \
-d '{"query": "What are the key findings?", "stream": false}'
All SDK, REST, MCP, Web contracts and response shapes are in docs/interfaces.md.
Python SDK
uv add dlightrag
import asyncio
import os
from dlightrag import IngestSpec, RAGServiceManager
from dlightrag.config import DlightragConfig, EmbeddingConfig, LLMConfig, ModelConfig
async def main() -> None:
workspace = "research_notes"
config = DlightragConfig(
workspace=workspace,
working_dir="./dlightrag_storage/sdk_demo",
llm=LLMConfig(
default=ModelConfig(
provider="openai", # protocol family: openai | anthropic | gemini (vendor via base_url)
model="gpt-4.1-mini",
api_key=os.environ["OPENAI_API_KEY"],
temperature=0.2,
)
),
embedding=EmbeddingConfig(
provider="openai_compatible",
model="text-embedding-3-large",
api_key=os.environ["OPENAI_API_KEY"],
base_url="https://api.openai.com/v1",
dim=3072,
),
)
manager = await RAGServiceManager.acreate(config)
try:
await manager.aingest(
workspace,
IngestSpec(source_type="local", path="./docs"),
)
answer = await manager.aanswer("What are the key findings?", workspace=workspace)
print(answer.answer)
finally:
await manager.aclose()
asyncio.run(main())
config.yaml is optional for SDK users; constructor values take precedence.
MCP
Use stdio when an agent starts DlightRAG as a subprocess:
{
"mcpServers": {
"dlightrag": {
"command": "uvx",
"args": ["dlightrag-mcp", "--env-file", "/absolute/path/to/.env"]
}
}
}
Use streamable HTTP when multiple clients connect to a running service:
DLIGHTRAG_MCP_TRANSPORT=streamable-http \
DLIGHTRAG_MCP_HOST=127.0.0.1 \
dlightrag-mcp
MCP tools include retrieve, answer, ingest, get_ingest_job,
cancel_ingest_job, list_files, delete_files, list_workspaces,
create_workspace, and delete_workspace, plus get_capabilities for image
and metadata-filter capability discovery. See
docs/interfaces.md
for the authoritative tool-result contract.
Core Concepts
Workspaces. A workspace is the primitive isolation unit for indexed data, metadata, jobs, files, and queries. Query calls can target one workspace or federate across multiple workspaces.
Ingestion sources. Local files, Web uploads, S3, Azure Blob, public/signed
HTTPS URLs, and SDK AsyncDataSource connectors flow through the same ingest
contract. Web and REST uploads are staged under DlightRAG's managed
working_dir/inputs/<workspace>/ tree, then copied into the workspace input
root as retained local sources. Upload batch staging under __uploads__/ is
cleaned by the durable ingest job after the handoff.
Source downloads. Every successful ingest remains downloadable, whether or
not DlightRAG retains a local copy. source_uri is stable provenance;
download_uri is the durable S3, Azure, or queryless public HTTPS locator used
when retain_source_file is false. Signed HTTPS fetch URLs need either a
separate durable locator or retention. A non-retained custom SDK connector must
provide SourceDocument.download_uri (or download_uri_for_key). DlightRAG
rejects a document before materialization when this contract cannot be met; it
never silently changes the caller's retention choice.
Runtime storage. Docker Compose stores working_dir in the
dlightrag_data named volume mounted at /app/dlightrag_storage; the host
./dlightrag_storage directory is only used by native, non-Docker runs.
Metadata. Pass any custom fields through metadata on ingest; they are
stored as sent and are filterable without being declared first. Request-level
metadata is the batch default; manifest or SourceDocument metadata overlays it
per document.
Retrieval and answers. DlightRAG uses LightRAG mix as the base retrieval
mode, then adds metadata filtering, BM25, optional direct image retrieval, RRF
fusion, reranking, answer packing, citations, and optional semantic highlights.
The detailed mechanism is in docs/retrieval-answer.md.
Observability. Langfuse tracing is optional. Non-secret SDK behavior is set
in docs/configuration.md. To run the bundled local
Langfuse stack (make langfuse-up) and view traces, see
docs/operations.md.
Security Model
Local loopback development can use auth_mode: none. Shared or exposed
deployments should enable auth:
| Mode | Use case |
|---|---|
simple |
One shared bearer token |
jwt |
Externally issued signed tokens |
jwt + JWKS |
OIDC-style issuers with key rotation |
jwt + jwt_claims access control |
Workspace/action permissions from verified claims |
DlightRAG verifies bearer tokens and can enforce workspace/action access control. It does not issue OAuth tokens or manage users. Use an external IdP or gateway for login and token issuance. Full guidance is in docs/security.md.
Operations And Development
Use docs/operations.md for the full stop/rebuild/restart sequence and maintenance safety notes.
Development setup:
uv sync
cd frontend && npm ci && cd ..
make hooks
Verification:
make ci # the fast gate: lint, security, format, types, architecture, shell, frontend, unit tests
make ci-full # above + integration tests
make ci-e2e # above + E2E smoke
Frontend checks after editing frontend/:
cd frontend
npm run typecheck
npm run build
npm run lint:css
npm run build writes the browser bundle to src/dlightrag/web/static/generated/.
That directory is gitignored and rebuilt by make ci; the wheel picks it up
through tool.hatch.build.targets.wheel.artifacts.
Evaluation with RAGAS is documented in docs/evaluation.md.
Documentation Map
- docs/architecture.md - runtime ownership, storage topology, and code layering.
- docs/interfaces.md - SDK, REST, MCP, and Web contracts.
- docs/security.md - auth, JWT/JWKS, IdP boundaries, and access control.
- docs/configuration.md - configuration precedence, fields, and defaults.
- docs/retrieval-answer.md - retrieval, filters, BM25, fusion, rerank, answers, citations, and highlights.
- docs/postgresql.md - PostgreSQL requirements and tuning.
- docs/operations.md - maintenance commands and recovery workflows.
- docs/evaluation.md - RAGAS evaluation workflow.
- docs/web-theme-design.md - current Web appearance state, tokens, interaction, and accessibility design.
- LightRAG API Server docs - upstream parser routing and external parser contracts.
- MinerU Docker deployment docs - Linux/WSL2 Docker support and macOS warning.
- Docling Serve - official Docling HTTP service and container images.
License
Apache License 2.0. See LICENSE.
Built by HanlianLyu. Contributions welcome.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dlightrag-1.8.8.tar.gz.
File metadata
- Download URL: dlightrag-1.8.8.tar.gz
- Upload date:
- Size: 5.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fd5bdc77be7b752809aea7d8834319c79db5cc40233886c83940d46cbac8efc0
|
|
| MD5 |
43552c788ac5c7499136abd1dad6a416
|
|
| BLAKE2b-256 |
74e20bffe5adadf68b6d59b033ab165c69718e523693338e832e8b987697e5fb
|
Provenance
The following attestation bundles were made for dlightrag-1.8.8.tar.gz:
Publisher:
publish.yml on hanlianlu/DlightRAG
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dlightrag-1.8.8.tar.gz -
Subject digest:
fd5bdc77be7b752809aea7d8834319c79db5cc40233886c83940d46cbac8efc0 - Sigstore transparency entry: 2376275112
- Sigstore integration time:
-
Permalink:
hanlianlu/DlightRAG@0a88bba706871c4992897cad176ec873669df9d0 -
Branch / Tag:
refs/tags/v1.8.8 - Owner: https://github.com/hanlianlu
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0a88bba706871c4992897cad176ec873669df9d0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dlightrag-1.8.8-py3-none-any.whl.
File metadata
- Download URL: dlightrag-1.8.8-py3-none-any.whl
- Upload date:
- Size: 4.8 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3fabbcdc4187c4a35d1932b9af60d70a24a99e7788c758c886987cd1527c0ea2
|
|
| MD5 |
59c9e205ceafc8f308ba998df280110b
|
|
| BLAKE2b-256 |
1f22df169d71473a43b3b5c91c35052820a1672a807d7e152f894eaf5a0bb1c3
|
Provenance
The following attestation bundles were made for dlightrag-1.8.8-py3-none-any.whl:
Publisher:
publish.yml on hanlianlu/DlightRAG
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dlightrag-1.8.8-py3-none-any.whl -
Subject digest:
3fabbcdc4187c4a35d1932b9af60d70a24a99e7788c758c886987cd1527c0ea2 - Sigstore transparency entry: 2376275151
- Sigstore integration time:
-
Permalink:
hanlianlu/DlightRAG@0a88bba706871c4992897cad176ec873669df9d0 -
Branch / Tag:
refs/tags/v1.8.8 - Owner: https://github.com/hanlianlu
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0a88bba706871c4992897cad176ec873669df9d0 -
Trigger Event:
push
-
Statement type: