Sankar045/Self-Healing-RAG
Self-healing RAG service
Implements the pipeline in your diagram:
- query classification (factual / conceptual / multi-hop)
- research-grade retrieval (optional, default on): multi-query fusion (several paraphrased searches, merge by best chunk score) + two-stage filter (top documents, then chunks)
- hybrid retrieval (dense vector + BM25) + optional re-rank
- retrieval quality check (may re-query)
- answer generation with retrieved context
- hallucination / claim check (may re-retrieve + re-generate); deep lexical scoring when
RESEARCH_VERIFY_DEEP=true - citation verification (attach source for each claim)
- returns verified answer + sources + confidence
Env: RESEARCH_RAG, RESEARCH_MAX_VARIANTS, RESEARCH_STAGE2_TOP_DOCS, RESEARCH_VERIFY_DEEP (see .env.example). POST /query includes a router.research summary when fusion ran.
Quickstart (local)
Create env file at the project root (same folder as README.md):
cp .env.example .envThe app loads `/path/to/rag/.env` automatically even if you start uvicorn from another directory. For real answers (not extractive fallback), set `OPENAI_BASE_URL`, `OPENAI_API_KEY`, and `OPENAI_MODEL` (any OpenAI-compatible provider). Check GET /health: llm_enabled should be true, and llm shows which vars are missing.
Groq (free tier): keys and models are managed in the Groq console. Use OPENAI_BASE_URL=https://api.groq.com/openai/v1, put your Groq secret in `OPENAI_API_KEY` (variable name stays OPENAI_* because the HTTP client is OpenAI-compatible), and set `OPENAI_MODEL` to a Groq model id (see .env.example).
Install dependencies:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtGenerate the sample PDF (optional) and ingest docs under data/:
python scripts/build_sample_pdf.py --out data/demo.pdf
python -m scripts.ingest --data_dir data --collection docsSupported file types include .txt, .md, and .pdf (PDF text is extracted with pypdf).
Run the API:
uvicorn app.main:app --reload --port 8000Query:
curl -s http://localhost:8000/query \
-H 'Content-Type: application/json' \
-d '{"question":"What is this system?","collection":"docs"}' | jq .Upload documents (API + demo UI)
Users can index their own files into a collection, then query that collection.
- Demo: open
http://localhost:8000/demo, pick files under Upload documents, then run a question (same Collection name). - API (multipart field name must be
files; repeat the field for multiple files):
curl -s -X POST "http://localhost:8000/collections/docs/documents" \
-H "X-API-Key: $API_KEY" \
-F "files=@./README.md" \
-F "files=@./notes.txt"Tune limits via UPLOAD_MAX_FILES, UPLOAD_MAX_BYTES_PER_FILE, UPLOAD_MAX_TOTAL_BYTES, UPLOAD_RATE_LIMIT in .env.
Quickstart (Docker)
docker compose up --buildThen query http://localhost:8000/query.
Using Qdrant (optional)
To use Qdrant as the vector database:
- Set
VECTOR_DB=qdrantin.env - Ensure Qdrant is running (the provided
docker-compose.ymlstarts it onhttp://localhost:6333)
Notes
- By default, embeddings use
sentence-transformerslocally. - Generation + verification use an OpenAI-compatible chat endpoint (OpenAI, Azure OpenAI, Ollama OpenAI-compat, etc.).
- If no LLM credentials are set, the service still retrieves and returns top sources, but the final answer will be a simple extractive fallback.
Web demo UI
Open http://localhost:8000/demo after starting the API (served from static/index.html). The page includes presenter notes (expand “How to showcase self-healing”) and a Self-healing trace panel after each query (retries, claim counts, warnings) so a live audience can see the two loops without reading raw JSON.
Live demo script (talk track)
- Clarify the “database”: the vector index (Chroma locally, or Qdrant if configured) stores chunks + embeddings for your files. It does not “heal” by itself. Self-healing is query-time behavior: optional extra retrieval and optional re-generation when quality checks fail.
- Show loop 1: run a question, point at `retries.retrieval` in the trace (or JSON). If
> 0, say: “The first search looked weak, so the pipeline widened retrieval and tried again.” - Show loop 2: point at `retries.verification` and claim chips. If verification
> 0, say: “Several sentences were not well supported by sources, so it pulled more context and asked the model again—bounded retries.” - Show grounding: expand `claims` in the JSON: each item is a sentence checked against a source chunk (or flagged). That is the “not making things up” story.
- Optional (to make retries more likely during a rehearsed demo): temporarily lower `MIN_RETRIEVAL_SCORE` in
.env(e.g.0.45) so marginal matches trigger more retrieval retries; restore afterward.
Deploy
- Docker image: the included
Dockerfilelistens on$PORT(for Render, Fly.io, Railway, etc.). - Render: connect the GitHub repo, choose “Docker”, set root
render.yamlor point the Dockerfile, then add environment variables (OPENAI_*, optionalAPI_KEY,VECTOR_DB,QDRANT_*). Default Chroma on a web dyno is ephemeral unless you attach a Render Disk and setCHROMA_DIRto the mount path—or use Qdrant Cloud (VECTOR_DB=qdrant). - Fly.io: install the Fly CLI, run
fly launchin this directory (usesfly.toml), thenfly secrets setforOPENAI_BASE_URL,OPENAI_API_KEY,OPENAI_MODEL, and optionalAPI_KEY. The samplefly.tomlusesinternal_port = 8080to match Fly’sPORT. - Secrets: never commit
.env; set LLM and DB keys only in the host’s secret store.
Debug: memory inspection
curl -s http://localhost:8000/memory/demoIf API_KEY is set in .env, pass X-API-Key: <key>.
Production-oriented features (built-in)
- Optional API key: set
API_KEYin.env; clients sendX-API-Key. - Rate limiting:
RATE_LIMIT(e.g.120/minute) via SlowAPI. - CORS:
CORS_ORIGINS(comma-separated origins, or*). - Request IDs:
X-Request-IDon responses; structured request logging. - Health:
GET /healthincludes vector store ping; setHEALTH_CHECK_LLM=trueto probe the LLM (uses quota). - Warnings:
POST /queryreturnswarningswhen the LLM is skipped or errors (extractive fallback). - Episodic memory: deduplicated “what did I ask before” answers with timestamps.
- PDF ingest: drop
.pdffiles underdata/and runscripts.ingest(usespypdf). - CI: GitHub Actions workflow runs import +
pytest.
Eval script (quick)
With the API running:
python scripts/eval_golden.py --base http://127.0.0.1:8000