Production-grade multi-user RAG platform built on the spec libraries:
| Concern | Library |
|---|---|
| Document Conversion | Marker |
| Knowledge Format | Open Knowledge Format (OKF) |
| Chunking | Chonkie |
| LLM + Embeddings | LiteLLM |
| Structured Outputs | Instructor |
| Vector Store | Qdrant (ZVec optional) |
| Observability | Langfuse |
| Benchmark | FinanceBench |
Every collaborator is replaceable through the public
raghub.RAG facade.
- Quick Start
- Features
- Installation
- CLI
- Streamlit UI
- FastAPI
- Multi-User & RBAC
- Conversational RAG
- Configuration
- Development
- Project Structure
- Plugins
- Benchmarking
- Changelog
- License
from raghub import RAG
from raghub.models import UserPrincipal
rag = RAG()
alice = UserPrincipal(user_id="alice", email="alice@x", allowed_companies=["Apple"])
rag.ingest(open("report.pdf", "rb").read(), source_uri="file://report.pdf", user=alice)
response = await rag.aquery("What was the revenue?", user=alice, session_id="alice-s1")
print(response.answer)
print(response.citations)No API keys required — RAGHub falls back to deterministic in-process
providers for all spec libraries. Just pip install and go.
- Multi-tenant RBAC — query results are scoped to each user's
allowed_companies. Admins see everything; unauthorised users see nothing. - Conversational history — session-scoped turn memory enables natural follow-up questions.
- Incremental indexing — content-addressed by SHA-256 hash; unchanged files are skipped on re-ingest.
- Real streaming —
rag.astreamyields tokens as they arrive, with parallel stream-option support. - Token-usage tracking — every
generateandastreamcall records prompt/completion token counts. - Resumable ingestion — persistent SQLite job ledger survives process restarts.
- Structured output — pass a Pydantic
response_modeltorag.query()to get typed results via Instructor. - Plugin system — register custom converters, chunkers, vector stores, evaluators, and telemetry providers.
- Observability — Langfuse, OpenTelemetry, Prometheus metrics, and structlog logging out of the box.
- Evaluation — FinanceBench evaluator with Recall@K, Precision@K, MRR, Faithfulness, Context Recall, Context Precision, and Answer Correctness.
git clone https://github.com/sachn-cs/raghub.git
cd raghub
pip install -e ".[dev,api,ui,zvec]"| Extra | Includes |
|---|---|
dev |
pytest, ruff, mypy, hypothesis, types-PyYAML |
api |
FastAPI, uvicorn, python-multipart |
ui |
Streamlit |
zvec |
ZVec vector store |
All spec libraries (Marker, Chonkie, LiteLLM, Instructor, Qdrant, Langfuse, datasets) are installed by default.
For a minimal environment:
pip install -e . # core only
pip install -e ".[dev]" # core + dev tooling# Emit a starter YAML config
raghub init -o raghub.yaml
# Ingest a file or directory
raghub ingest ./documents
# Ask a question
raghub query "What was the revenue guidance?"
# Liveness probe
raghub health
# Print the version
raghub versionstreamlit run streamlit_app.pyThe UI pre-seeds five demo users with different allowed_companies:
| Companies | Admin? | |
|---|---|---|
| alice@acme.com | Apple | No |
| bob@acme.com | Microsoft | No |
| charlie@acme.com | Amazon, Tesla | No |
| diana@acme.com | No | |
| admin@acme.com | (all) | Yes |
The default password is password. Override the user directory
by setting RAGHUB_USERS to a JSON mapping.
The UI uses st.chat_message + st.chat_input for a real chat
experience with follow-up questions, conversation history, and
per-turn citation rendering.
uvicorn raghub.api.app:app --host 0.0.0.0 --port 8000The legacy DynamicRagApplication is still reachable at
/auth/login, /documents/upload, /query, etc. The new
RAG facade is the recommended path for new integrations.
Every public query method accepts a UserPrincipal. The retrieval
layer is filtered to the user's allowed_companies; admins see
everything. The LLM never receives unauthorised context.
alice = UserPrincipal(user_id="alice", email="alice@x", allowed_companies=["Apple"])
bob = UserPrincipal(user_id="bob", email="bob@x", allowed_companies=["Microsoft"])
admin = UserPrincipal(user_id="admin", email="admin@x", is_admin=True)
# Alice sees only Apple chunks; Bob only Microsoft; admin sees all.
rag.query("revenue", user=alice)
rag.query("revenue", user=bob)
rag.query("revenue", user=admin)A user with no allowed_companies and no is_admin sees no
documents (the filter resolves to {"company": []} which
matches nothing). An unauthorised user attempting to retrieve
another tenant's content receives an empty result set.
Every public query method accepts a session_id. The pipeline
loads the most recent turns from the
InMemoryConversationStore (or a
custom ConversationStore) and prepends them to the prompt so the
LLM can answer follow-up questions.
await rag.aquery("revenue", user=alice, session_id="alice-s1")
# Bob's session is isolated; Alice's session has its own history.
await rag.aquery("and growth?", user=alice, session_id="alice-s1")Configuration precedence (highest first):
- Constructor arguments to
RAG(...). - Environment variables (
RAG_*,JWT_SECRET,NVIDIA_API_KEY,OPENAI_API_KEY,ANTHROPIC_API_KEY,LANGFUSE_PUBLIC_KEY,LANGFUSE_SECRET_KEY,QDRANT_URL). - TOML config (
config/<profile>.toml). - YAML config (
config/<profile>.yaml). - Built-in defaults.
AppSettings.override(**changes) returns a new instance with the
given fields changed (the original is not mutated). This is the
runtime-override mechanism.
# Automated setup (venv + install)
./setup.sh
# Or manually:
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev,api,ui,zvec]"
# Run tests
python -m pytest tests/ -q
# Run linter
python -m ruff check raghub/
# Run type checker
python -m mypy raghub/351 tests covering:
- Ingestion pipelines (plain-text, PDF through Marker)
- Vector store operations (Qdrant, in-memory, ZVec)
- LiteLLM embedding and LLM providers (with mocked responses)
- Multi-user RBAC isolation (10 concurrent users)
- Session-scoped conversation history
- Streaming and token-usage tracking
- Security — JWT auth, unauthorised access isolation
- FinanceBench evaluation metrics
- Plugin registry and entry-point discovery
- CLI commands (health, ingest, query, init)
- Persistence (JSON document registry, SQLite stores)
raghub/
api/ RAG facade (single entry point), FastAPI, Streamlit
config/ YAML / TOML configuration
models/ Typed Pydantic domain models (Document, Chunk, Citation, ...)
interfaces/ Protocol contracts (DocumentConverter, VectorStore, ...)
converters/ Marker, plain-text, OKF normaliser
knowledge/ OKF serialisation + InMemoryKnowledgeRepository
ingestion/ IngestPipeline (convert → chunk → embed → upsert)
embeddings/ LiteLLM, SentenceTransformers, hashing
vectorstore/ Qdrant, ZVec, InMemory
llm/ LiteLLM, Heuristic
structured/ Instructor
retrieval/ Pipeline, IdentityReranker
generation/ DefaultGenerator (citations, astream, token usage)
pipelines/ IngestPipeline, QueryPipeline
observability/ NoOpTelemetry, RedactingTelemetry, StructlogTelemetryProvider
telemetry/ LangfuseTelemetryProvider, NoopSpan, LangfuseSpan
evaluation/ FinanceBenchEvaluator, retrieval metrics
plugins/ PluginRegistry, entry-point discovery
cli/ CLI commands (health, ingest, query, init, eval)
Plugins can register converters, chunkers, embedders, vector stores,
retrievers, rerankers, generators, telemetry providers, or
evaluators on a raghub.plugins.registry.PluginRegistry. They are
discovered via entry points (group="raghub.plugins") and can be
registered programmatically:
from raghub.plugins.registry import PluginRegistry
from raghub.converters.marker import MarkerConverter
registry = PluginRegistry()
registry.register_converter("marker", MarkerConverter())
rag = RAG(registry=registry)# FinanceBench evaluation
raghub-financebench --examples 25
# Performance benchmark
python -m bench.benchmark --documents 100 --queries 200 --concurrency 8The performance benchmark measures startup time, ingestion throughput,
query latency (p50/p95), queries-per-second under concurrency, and
peak RSS. The report is written to bench/report.json.
The FinanceBench evaluator reports Recall@K, Precision@K, MRR, Faithfulness, Context Recall, Context Precision, and Answer Correctness.
See CHANGELOG.md for version history.
MIT.