The Problem
Enterprises that need to expose document‑wide question‑answering across many customers run into two issues: (1) keeping each tenant’s data isolated while sharing the same retrieval infrastructure, and (2) handling the wide variety of file formats (PDF, Word, images, tables, formulas) without building a custom parser stack for every use‑case.
What This Does
rag-api delivers a multi‑tenant Retrieval‑Augmented Generation service that couples LightRAG (graph‑based retrieval) with RAG‑Anything (multimodal parsing). The code base is organized around three domains:
src/– core engine (config, multi‑tenant manager, parsers, rate‑limiter, metrics).src/multi_tenant.pycreates per‑tenant LLM and embedding functions and is the hub for tenant isolation.src/smart_parser_selector.pypicks the best parser (DeepSeek‑OCR, MinerU, Docling) using the complexity scorer insrc/document_complexity.py.src/rag.pyruns the LightRAG retrieval pipeline.
api/– FastAPI request handlers (documents.py,insert.py,query.py, etc.) that translate HTTP calls into engine actions.
scripts/– operational helpers;scripts/migrate_tenant.pyis the only CLI entry that performs tenant migration.
The top‑level main.py starts the FastAPI server, wiring the router defined in api/__init__.py to the engine modules.
How It Is Wired
- Startup –
python main.py(or the Docker entrypoint) creates the FastAPI app. - Request flow – an incoming HTTP call hits a handler in
api/. For a document upload the path is:api/insert.insert_document→src/multi_tenant.get_tenant_lightrag(called from 9 places) →src/rag.process_document_task→ parser selection (src/smart_parser_selector.select_parser) → concrete parser (src/deepseek_ocr_client,src/mineru_client, orsrc/docling_client) → vector store write (Qdrant viasrc/rate_limiter.acquireandsrc/tenant_config) → task persistence (api/task_store).
The most fan‑in functions are src/logger (22 imports) and api/insert (high instability). Changing src/logger has the widest blast radius.
- External effects – File system – parsers open PDFs/Docs (
openwithout context manager insrc/deepseek_ocr_client.pyandsrc/document_complexity.py). Network – OCR calls (requests.getindeepseek_ocr_client), MinerU remote API (src/mineru_client), and tenant config fetches. * Database – task CRUD (api/task_store) writes to Redis/DragonflyDB; tenant config reads/writes JSON files (src/tenant_config.py).
- Rate limiting – every outbound call passes through
src/rate_limiter.acquire, which is invoked from 8 locations, making it a critical throttling point.
- Metrics –
src/metrics.pyrecords response times and error rates; these are called from the monitoring endpoints inapi/monitor.py.
The internal call graph shows 290 resolved intra‑repo edges; the most reused utilities (get_tenant_config_manager, DocumentFeatures, ParseOptions) appear in 5–7 places each, indicating they are natural extension points.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/rag-api
cd rag-api
# Build the container (uses uv for dependency resolution)
docker build -f Dockerfile -t rag-api:latest .
# Run the stack (FastAPI + Qdrant vector store)
docker compose up -d # uses docker-compose.yml
# The API is now reachable at http://localhost:8000
# Swagger UI: http://localhost:8000/docs
Configuration – tenant isolation and parser keys are read from files under src/tenant_config.py and environment variables referenced there (e.g., DEEPSEEK_API_KEY). No secret files are committed; provide them at container start.
CLI migrations – to migrate an existing tenant configuration:
python scripts/migrate_tenant.py --old-id old_tenant --new-id new_tenant
The script uses src/multi_tenant to copy vector data and task records.
Real‑World Use
A SaaS provider can spin up a single rag-api service behind a tenant‑aware gateway. When a client uploads a contract PDF, the service routes the request to api/insert, the smart selector chooses DeepSeek‑OCR for complex layout, stores embeddings in Qdrant, and later answers queries via api/query using LightRAG’s hybrid graph retrieval. All tenant data remains isolated by the per‑tenant manager in src/multi_tenant.py.
Code Health & Issues
- HIGH – Pin third‑party GitHub Actions to a commit SHA (
.github/workflows/ci-basic.yml). - HIGH – No LICENSE file – redistribution rights undefined.
- MEDIUM – GITHUB_TOKEN permissions not declared (
.github/workflows/ci-basic.yml). - MEDIUM – No Dependabot/Renovate configuration.
- MEDIUM – Base Docker image not pinned by digest (
Dockerfile). - MEDIUM – No dependency‑vulnerability scan in CI.
- MEDIUM – Container runs as root; no non‑root
USERdirective. - MEDIUM – Test coverage is minimal (1 test file vs 29 source files).
- LOW – Workflow jobs lack
timeout-minutes.
Additional static findings: deep nesting (max depth 9) in src/multi_tenant.py and related modules, file handles opened without with, and broad except: clauses in request handlers. These increase maintenance risk and should be refactored.
The Bottom Line
rag-api provides a functional, container‑ready multi‑tenant RAG service with solid architecture (FastAPI + LightRAG + auto‑parser selection). It is usable out of the box but needs hardening: add a license, tighten CI security, improve test coverage, and refactor the most complex modules before extending it in production. Suitable for teams comfortable with Python, Docker, and FastAPI who can invest in the outlined cleanup.