A production-ready Retrieval-Augmented Generation system with an agentic pipeline, multilingual support for 10+ Indian languages, and tools for searching arXiv, Semantic Scholar, OpenAlex, and the web โ alongside your own indexed document corpus.
Two pipelines ship side-by-side: Standard RAG (single-pass hybrid retrieval) and Agentic RAG (multi-tool planning with reflexion self-correction). Answers stream token-by-token over SSE, sessions survive restarts, and every retrieval knob is env-configurable. Now with multi-provider LLM support (Gemini + OpenRouter), topic watches, and literature review reports.
| Area | v2.3 | v2.4 |
|---|---|---|
| Default model | gemini-3.5-flash | gemini-3.6-flash โ latest Gemini Flash, faster and more capable |
| Multi-user support | Single-user API key | Per-user data isolation โ sessions, watches, feedback, preferences scoped to API key |
| User preferences | None | GET/PUT /prefs/{user_id} โ per-user settings with opt-in ENABLE_USER_PREFS |
| Admin API key | Falls back to API_KEYS | Dedicated ADMIN_API_KEY for destructive /purge/* operations |
| Session management | Basic eviction | Configurable โ SESSION_MAX_AGE_HOURS, CHAT_HISTORY_MAX_TURNS |
| Rate limiting | Per-IP only | Per-API-key โ each user gets their own rate-limit bucket |
| Linting | CI failures on unused imports | Clean CI โ fixed F401/E401 linting errors |
- Faithfulness verification restored โ
verify.check_claimswas passing(index, text)tuples to the NLI model instead of the chunk text, so every call raised and every answer reportedconfidence: 0.0with no evidence. - Generation restored on
gemini-3.6-flashโ models that rejectthinking_budget=0returned400 INVALID_ARGUMENT. The Gemini backend now remembers per-model rejections and retries once withoutthinking_config. - Retrieval cache actually populates โ the cacheability check ran after the collection was materialized, so nothing was ever stored. Cached entries are now copied on both read and write so callers can't mutate them.
- Tags filter returns results โ tags are stored as one comma-joined metadata string and must be filtered in Python, which needs an over-fetch (
TAGS_OVERFETCH); without it a tag query returned nothing. - Cross-vendor failover is really cross-vendor โ the OpenRouter fallback was handed a bare Gemini model name, which OpenRouter rewrites to
google/<model>, routing back to the vendor that just failed. It now picks a/-shaped slug fromLLM_SELECTABLE_MODELS. - Selected model honoured in agentic answers โ the answer generator used the configured default instead of the requested model.
- Web UI โ new Retrieval view, Library row actions (dry-run, edit metadata, delete, bulk delete), Depth + tags controls, BibTeX/Markdown evidence exports, saved reports, and an index-health diagnostics panel.
- LangGraph state machine โ query planner โ tool selector โ tool executor โ answer generator โ reflexion evaluator, with conditional loops
- 6 agent tools:
- indicrag_retrieval โ hybrid BM25 + dense search with cross-encoder reranking on your indexed corpus, with optional year-range filter
- arxiv_search โ search arXiv by topic, author, or paper ID; returns abstracts, authors, PDF links
- open_access_search โ Semantic Scholar with automatic OpenAlex fallback (free, no API key); returns citation counts and open-access PDFs
- web_search โ Tavily web search for current events and non-academic info
- calculate โ numexpr math evaluation (identifier-whitelisted)
- execute_python โ process-isolated Python with AST-based validation (import whitelist, dunder + dangerous-builtin blocking) + 10s timeout
- Reflexion loops with dual budget โ the evaluator checks faithfulness (NLI entailment, minimum across claims) and completeness (Gemini Flash). Below threshold it can regenerate, retrieve more, or reformulate โ bounded by both an iteration cap (3) and a wall-clock budget (
AGENT_REFLEXION_BUDGET_S). Stuck-loop detection auto-accepts when completeness stops improving. - Contradiction detection โ NLI-based cross-source contradiction flagging in the answer generator; surfaces both sides with citations when sources disagree
- Confidence & abstention โ finalizer surfaces a confidence score; low-confidence answers get an explicit abstention prefix with partial sourcing
- Multi-turn conversations โ session history threaded through
AgentStateso follow-ups resolve pronouns and references - Parallel tool execution โ multiple selected tools run concurrently via
ThreadPoolExecutor - Sub-query cap โ
AGENT_MAX_SUB_QUERIESlimits per-cycle retrievals to bound latency and cost - Model failover + circuit breaker โ per-(provider, model) circuit keys; one model's 429 doesn't block others. Cross-provider failover (Gemini โ OpenRouter, or reverse), with a guaranteed Gemini backstop so any selected OpenRouter model still resolves when its free-tier endpoint 429s
- Multi-provider LLM โ Gemini + OpenRouter (Claude, GPT, Llama, etc.) with user-selectable models, capability gating, and non-Gemini JSON fallback
- google-genai native function calling โ no LangChain LLM wrappers;
mode=AUTOlets the model return an empty tool list onregenerateactions
- Dense + sparse โ BGE-M3 (1024d) fused with BM25 via Reciprocal Rank Fusion (RRF)
- Two-stage reranking โ
BAAI/bge-reranker-v2-m3cross-encoder, with optional ColBERT multi-vector MaxSim rerank on the narrowed candidate set - Optional HyDE โ generate a hypothetical answer, embed it, and retrieve against it for recall on sparse queries
- Faithfulness verification โ
cross-encoder/nli-deberta-v3-basescores entailment per claim; unsupported assertions flagged, stripped, or regenerated (FAITHFULNESS_ENFORCE) - HNSW tuning knobs โ
ef_search,ef_construction,Mall env-configurable
- Section-aware chunking โ per-section chunk sizes (abstract, methods, results, โฆ) instead of uniform splits
- Multimodal figure/table indexing โ extract figure/table crops from PDFs, generate captions, and embed alongside text chunks
- Metadata enrichment โ auto-fetch authors, year, DOI from arXiv by fuzzy title match at ingest time
- Title dedup โ near-duplicate papers rejected by
SequenceMatcherratio (DEDUP_TITLE_THRESHOLD) - MD5 content dedup + parallel extraction, Indic-aware chunking
- 10+ Indian languages + English (Hindi, Tamil, Telugu, Bengali, Marathi, Gujarati, Kannada, Malayalam, Punjabi, Odia, Urdu)
- Unicode script-based language detection with Devanagari hi/mr disambiguation
- Two RAG strategies: Direct multilingual reasoning (A, recommended) or Translation-enhanced with NLLB-200 (B, sentence-batched)
- Cross-lingual semantic search via BGE-M3
- SQLite session/job persistence โ restarts don't drop in-flight state (
SESSIONS_DB_PATH) - SSE streaming โ token-by-token answers and live ingest progress
- Thread-safe model init (double-checked locking on all singletons)
- Startup warm-up via FastAPI lifespan (embeddings, vector store, reranker, BM25) โ no cold first request
- Request-ID correlation across log lines; Prometheus metrics
- API-key auth, env-driven CORS, Pydantic v2 validation, path-traversal + URL-scheme guards
- int8 quantized ONNX cross-encoders for CPU โ lower memory, faster inference
- Topic watches (
/watch/*) โ persistent monitoring with daily/weekly/monthly cadence; background digest loop fetches new papers, summarizes, and stores results - Literature review reports (
/report/*) โ async decomposition of a topic into sections, cited synthesis from the corpus, and downloadable Markdown artifact - Model selection (
GET /models) โ curated allowlist enriched with OpenRouter tool-capability metadata; UI dropdown with badges - Chat history โ endpoints + UI panels for browsing past conversations and topic watches
- LLM response cache (128 entries, 10 min TTL) โ identical prompts skip the API
- Retrieval cache (64 entries, 5 min TTL) โ auto-invalidated on ingest
- Tool result cache (64 entries, 3 min TTL) โ shared across reflexion loops
- Explicit Gemini prompt caching (opt-in) โ caches the stable system-instruction prefix per API key
- All sizes/TTLs env-configurable;
GET /cache/statsfor observability
- Python 3.11+
- Google Gemini API key (Get one here)
- 8GB+ RAM recommended
- (Optional) Tavily API key for agent web search (Get one here)
git clone https://github.com/DNSdecoded/IndicRAG.git
cd IndicRAG
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS/Linux
source .venv/bin/activate
pip install -r requirements.txtcp .env.example .envEdit .env:
# Required
LLM_API_KEY=your_gemini_api_key_here
# Optional โ enables multi-provider mode (OpenRouter)
# OPENROUTER_API_KEY=your_openrouter_key_here
# LLM_PROVIDER=gemini # gemini|openrouter
# LLM_FALLBACK_PROVIDER=openrouter
# Optional โ enables agent web search tool
TAVILY_API_KEY=your_tavily_key_here
# Optional โ higher token limit for agent answers (default 8192)
AGENT_MAX_TOKENS=8192
# Optional โ agent thinking tokens: 0=off (cheapest), -1=dynamic, N=cap (default 0)
AGENT_THINKING_BUDGET=0
# Optional โ retrieval quality boosters (off by default, cost more compute)
USE_COLBERT_RERANK=false
USE_HYDE=false
# Optional โ topic watches and literature reports (off by default)
# WATCH_ENABLE=true
# REPORT_ENABLE=true# Place PDFs in papers/ directory, then:
python ingest.py
# Or specify a directory:
python ingest.py path/to/pdfspython start_server.py
# Development mode with auto-reload
python start_server.py --devAccess at:
- Web Interface: http://localhost:8080
- API Docs: http://localhost:8080/api/docs
Open http://localhost:8080:
Ask โ pick a pipeline mode (Standard RAG or Agentic RAG), a strategy (Direct Multilingual A or English Pivot B), a model from the allowlist, and ask in English or any supported Indic language. The composer also exposes Depth (top_k = 4/8/12/16/20), a scope selector, and a tags filter. Agentic mode ignores scope, tags, and depth โ the UI says so inline.
Retrieval โ retrieval-only view over POST /search: query the corpus, the web, or both at k = 5/10/20/30 and inspect the raw passages with no LLM in the loop. Results export to BibTeX.
Library โ upload and ingest PDFs, plus per-row actions: ingest, dry-run (preview chunking/dedup before writing), edit metadata (title, authors, year, tags via PATCH /papers/{id}), and delete. Multi-select supports bulk delete.
Evidence exports โ answers export their cited sources as BibTeX or Markdown.
History โ sessions persist across restarts and can be reopened or deleted individually.
Reports โ saved literature reviews are listed and reopenable, rendered as Markdown with a download button.
Index health โ a diagnostics panel showing deep health, cache stats, index quality signals, and submitted feedback, with a one-click cache clear.
In Agentic mode the UI shows an animated progress stepper with elapsed timer, color-coded source cards (title, authors, year, citation count, PDF link), a tool-call log with latencies, and copy buttons on answers and LaTeX equations.
import requests
with requests.post('http://localhost:8080/query/stream',
json={"question": "What are the latest advances in antenna optimization using ML?"},
stream=True) as r:
for line in r.iter_lines():
if line:
print(line.decode()) # Server-Sent Eventsr = requests.post('http://localhost:8080/chat', json={
"message": "เฐฏเฐพเฐเฐเฑเฐจเฑเฐจเฐพเฐคเฑ ml เฐจเฑ เฐเฐฒเฐพ เฐ
เฐฎเฐฒเฑ เฐเฑเฐฏเฐตเฐเฑเฐเฑ?",
"strategy": "A"
})
print(r.json()['answer'])r = requests.post('http://localhost:8080/agent/query', json={
"question": "What are the latest advances in antenna optimization using ML?",
"strategy": "A"
})
data = r.json()
print(data['answer'])
print(f"Sources: {len(data['sources'])} Reflexion iterations: {data['reflexion_iterations']}")
for src in data['sources']:
print(f" [{src['section']}] {src['title']} ({src['year']}) โ {src['citations']} citations")
if src.get('pdf_url'):
print(f" PDF: {src['pdf_url']}")Agent response fields: answer, language, sources (title/authors/year/citations/pdf_url/url), tool_calls (name/args/latency_ms), reflexion_iterations (0โ3), processing_time.
| Endpoint | Method | Description |
|---|---|---|
/query |
POST | Single-turn question answering |
/query/stream |
POST | Same, streamed token-by-token (SSE) |
/chat |
POST | Multi-turn chat with persisted session history |
/chat/stream |
POST | Streamed multi-turn chat (SSE) |
/chat/{session_id} |
DELETE | Clear a chat session |
/chat |
GET | List persisted chat sessions |
/chat/{session_id} |
GET | Fetch one session's history |
/agent/query |
POST | Agentic pipeline with reflexion loops (timeout โ 504) |
/agent/stream |
POST | Agentic pipeline, streamed step-by-step (SSE) |
/compare |
POST | Kick off a multi-model answer comparison (async, returns job_id) |
/compare/status/{job_id} |
GET | Comparison job status / results |
/models |
GET | Curated model allowlist with tool-capability metadata |
/search |
POST | Retrieval-only โ corpus, web, or both (no LLM) |
/search/export |
GET | Export retrieved papers as BibTeX (format=bibtex only) |
/export/bibtex |
POST | Export an answer's cited sources as BibTeX |
/upload |
POST | Upload PDF (multipart form) |
/ingest |
POST | Ingest one PDF into the vector store |
/ingest/all |
POST | Bulk ingest all PDFs (async, returns job_id) |
/ingest/status/{job_id} |
GET | Bulk ingest job status |
/ingest/stream/{job_id} |
GET | Live ingest progress (SSE) |
/ingest/dry-run |
POST | Preview chunking/dedup without writing |
/ingest/reindex |
POST | Rebuild the index from stored papers |
/ingest/from-url |
POST | Fetch a PDF by URL and ingest it |
/ingest/health |
GET | Deep ingest-path health (store, embeddings, disk) |
/papers |
GET | List uploaded PDFs |
/papers/{paper_id} |
PATCH | Edit paper metadata (title, authors, year, tags) |
/papers/{paper_id} |
DELETE | Delete a single paper |
/watch |
GET/POST | List or create topic watches |
/watch/{id} |
GET/DELETE | Read or delete a watch |
/watch/{id}/run |
POST | Trigger a watch run immediately |
/watch/{id}/digest |
GET | Fetch persisted digest for a watch |
/report |
POST | Kick off a literature review report |
/report/status/{job_id} |
GET | Report generation status |
/report/{job_id}/download |
GET | Download completed report (Markdown) |
/reports |
GET | List saved reports |
/reports/{report_id} |
GET | Fetch one saved report |
/feedback |
POST | Submit answer feedback |
/feedback |
GET | List submitted feedback |
/feedback/stats |
GET | Aggregate feedback counts |
/prefs/{user_id} |
GET / PUT | Read / update user preferences |
/stats |
GET | Vector store statistics |
/quality |
GET | Index quality signals (chunk/metadata coverage) |
/cache/stats |
GET | Cache hit rates, sizes, TTL config |
/cache |
DELETE | Clear all caches |
/health |
GET | Health check |
/purge/papers |
DELETE | Delete all PDFs (admin key) |
/purge/database |
DELETE | Clear vector database (admin key) |
Full annotated tree: PROJECT_STRUCTURE.md
IndicRAG/
โ
โโโ ๐ Root
โ โโโ requirements.txt # dependencies
โ โโโ .env.example # LLM_API_KEY(S), TAVILY, AGENT_MAX_TOKENS, ...
โ โโโ start_server.py # Launcher with pre-flight checks
โ โโโ patterns.json # Regex patterns for PDF cleaning
โ
โโโ ๐ Core Modules
โ โโโ config.py # Configuration + env parsing (VERSION = 2.4.0-dev)
โ โโโ api_server.py # FastAPI app: lifespan warm-up + router mounting
โ โโโ deps.py # Shared deps: auth, rate limit, session/job state
โ โโโ middleware.py # Request-ID propagation
โ โโโ persistence.py # SQLite session/job/watch/report persistence
โ โโโ llm_client.py # Multi-provider dispatcher: Gemini + OpenRouter
โ โโโ gemini_cache.py # Explicit Gemini prompt caching (per client)
โ โโโ rag.py # RAG pipeline orchestration
โ โโโ sse_utils.py # Shared SSE streaming bridge
โ โโโ embeddings.py # BGE-M3 embeddings (thread-safe)
โ โโโ vector_store.py # ChromaDB wrapper (HNSW knobs)
โ โโโ bm25_search.py # BM25 + RRF fusion
โ โโโ rerank.py # Cross-encoder reranker (int8 ONNX)
โ โโโ onnx_ce.py # int8 quantized ONNX cross-encoder inference
โ โโโ colbert_rerank.py # ColBERT multi-vector MaxSim rerank (opt-in)
โ โโโ verify.py # NLI faithfulness verification
โ โโโ contradiction.py # Cross-source contradiction detection (Phase 5)
โ โโโ lang_utils.py # Unicode script + langdetect
โ โโโ pdf_utils.py # PDF extraction, Indic-aware chunking
โ โโโ figure_captioner.py # Figure/table crop extraction + captioning (Phase 3)
โ โโโ metadata_enrich.py # arXiv metadata auto-fetch at ingest
โ โโโ ingest.py # Section-aware parallel ingestion + dedup
โ โโโ translation.py # NLLB-200 sentence-batched (Strategy B)
โ โโโ cache.py # Thread-safe TTL LRU cache (LLM/retrieval/tool)
โ โโโ watch_runner.py # Background topic-watch digest loop
โ โโโ report_runner.py # Async literature-review report generation
โ โโโ purge.py # CLI cleanup (papers, db, models)
โ
โโโ ๐ providers/ # LLM provider backends
โ โโโ base.py # LLMBackend interface
โ โโโ gemini.py # GeminiBackend โ google-genai native
โ โโโ openrouter.py # OpenRouterBackend โ OpenAI-compatible API
โ
โโโ ๐ routes/ # FastAPI routers
โ โโโ query.py # /query, /query/stream, /health, /
โ โโโ chat.py # /chat, /chat/stream, /chat/{id}
โ โโโ agent.py # /agent/query
โ โโโ ingest.py # /ingest*, /upload
โ โโโ management.py # /search, /papers, /stats, /cache, /purge
โ โโโ feedback.py # /feedback, /prefs/{user_id}
โ โโโ models.py # /models โ curated model allowlist
โ โโโ watch.py # /watch โ topic monitoring CRUD + run + digest
โ โโโ report.py # /report โ literature review generation
โ
โโโ ๐ค agent/ # Agentic RAG Pipeline
โ โโโ state.py # AgentState + ReflexionFeedback schemas
โ โโโ tool_declarations.py # 6 google-genai FunctionDeclarations
โ โโโ tool_executor.py # Tool impls: corpus, arXiv, S2/OpenAlex, web, calc, sandbox
โ โโโ graph.py # LangGraph StateGraph + reflexion routing
โ โโโ json_utils.py # Robust LLM JSON parsing
โ โโโ nodes/
โ โโโ query_planner.py # Language detection + decomposition (+ HyDE)
โ โโโ tool_selector.py # Gemini function calling
โ โโโ tool_executor_node.py # Dispatch + context accumulation + audit log
โ โโโ answer_generator.py # Reuses rag context/prompt/generate + contradiction detect
โ โโโ reflexion_evaluator.py # check_claims() + Gemini completeness judge
โ โโโ finalizer.py # Terminal node โ confidence + abstention
โ
โโโ ๐ static/index.html # SPA: mode toggle, stepper, source cards, model dropdown, copy buttons
โโโ ๐ docs/ # ARCHITECTURE, DEPLOYMENT, evaluation, Eval/, ...
โโโ ๐ก examples/ # example_ingest.py, example_query.py
โโโ ๐ง deploy/ # nginx.example.conf
โ
โโโ ๐ Data (git-ignored)
โโโ papers/ # PDF documents
โโโ figures/ # Extracted figure/table crops (Phase 3)
โโโ chroma_db/ # Vector database
โโโ sessions.db # Persisted sessions/jobs/watches
โโโ models/ # Cached ML models
Key settings (all overridable via environment variables):
| Variable | Default | Description |
|---|---|---|
LLM_API_KEY |
(required) | Google Gemini API key (comma-separate for a round-robin pool) |
LLM_PROVIDER |
gemini |
Primary LLM provider: gemini or openrouter |
LLM_FALLBACK_PROVIDER |
openrouter |
Cross-provider failover when the primary is down |
OPENROUTER_API_KEY |
(none) | OpenRouter API key for multi-provider mode |
LLM_MODEL_NAME |
gemini-3.6-flash |
Gemini model for generation |
LLM_FALLBACK_MODEL |
gemma-4-26b-a4b-it |
Fallback when primary is overloaded (503/429) |
LLM_SELECTABLE_MODELS |
gemini-3.6-flash,gemini-3.5-flash,anthropic/claude-haiku,openai/gpt-5.4-nano |
Curated model dropdown (comma-separated; first entry is the default). .env.example ships a wider free-tier list. Bare name โ Gemini, / slug โ OpenRouter โ keep at least one / slug, since cross-vendor failover picks the first one here |
LLM_MAX_TOKENS |
2048 |
Max tokens for standard RAG |
AGENT_MAX_TOKENS |
8192 |
Max tokens for agentic pipeline |
AGENT_TIMEOUT |
120 |
Agent pipeline timeout (seconds) โ 504 |
AGENT_REFLEXION_BUDGET_S |
90 |
Wall-clock budget for reflexion loops |
AGENT_THINKING_BUDGET |
0 |
Agent thinking tokens: 0=off, -1=dynamic, N=cap |
AGENT_MAX_SUB_QUERIES |
3 |
Cap per-cycle retrievals to bound latency |
CONTRADICTION_DETECT_ENABLE |
false |
NLI-based cross-source contradiction flagging |
CONTRADICTION_NLI_THRESHOLD |
0.6 |
NLI score threshold for contradiction detection |
TAVILY_API_KEY |
(optional) | Enables agent web search tool |
WATCH_ENABLE |
false |
Enable topic watch endpoints (/watch/*) |
WATCH_DEFAULT_CADENCE |
weekly |
Default watch cadence: daily, weekly, or monthly |
WATCH_MAX_RESULTS |
10 |
Papers fetched per watch run |
REPORT_ENABLE |
false |
Enable literature review report endpoints (/report/*) |
REPORT_MAX_SECTIONS |
6 |
Cap report sections to bound cost/latency |
USE_HYBRID_SEARCH |
true |
BM25 + dense fusion |
USE_RERANKER |
true |
Cross-encoder reranking |
USE_COLBERT_RERANK |
false |
ColBERT multi-vector rerank layer |
COLBERT_WEIGHT |
0.5 |
Dense-vs-ColBERT fusion weight |
USE_HYDE |
false |
Hypothetical document embeddings |
EMBEDDING_MODEL_NAME |
BAAI/bge-m3 |
Sentence-transformer used for dense vectors (1024d) |
TAGS_OVERFETCH |
10 |
Multiplier applied to top_k when a tags filter is active โ tags live in one comma-joined metadata string, so filtering happens in Python after retrieval and the search must over-fetch to avoid returning nothing |
TAGS_OVERFETCH_MAX |
300 |
Hard ceiling on that widened fetch |
AGENT_MAX_CONTEXT_CHUNKS |
20 |
Chunk cap for the agentic answer prompt |
AGENT_MAX_CONTEXT_LENGTH |
80000 |
Character cap for the agentic answer prompt |
SCOPED_MAX_CHUNKS |
50 |
Chunk cap when a query is scoped to specific papers |
SCOPED_MAX_CONTEXT_LENGTH |
120000 |
Character cap for scoped queries |
ENRICH_METADATA |
true |
Auto-fetch arXiv metadata at ingest |
DEDUP_PAPERS |
true |
Reject near-duplicate titles |
DEDUP_TITLE_THRESHOLD |
0.9 |
Title similarity cutoff for dedup |
HNSW_EF_SEARCH |
100 |
ChromaDB HNSW query-time search breadth |
HNSW_EF_CONSTRUCTION |
100 |
HNSW build-time breadth (index quality vs. ingest speed) |
HNSW_M |
16 |
HNSW graph connectivity |
FAITHFULNESS_ENFORCE |
warn |
warn, strip, or regen |
FAITHFULNESS_THRESHOLD |
0.5 |
NLI support score threshold |
NLI_MODEL_NAME |
MoritzLaurer/mDeBERTa-v3-base-xnli-multilingual-nli-2mil7 |
NLI model backing faithfulness + contradiction checks |
NLI_ENTAILMENT_INDEX |
0 |
Index of the entailment label in that model's output โ change if you swap models |
GEMINI_CACHE_ENABLED |
false |
Explicit Gemini prompt caching |
GEMINI_CACHE_TTL |
3600 |
Prompt cache lifetime (seconds) |
SESSIONS_DB_PATH |
sessions.db |
SQLite path for session/job/watch persistence |
ENABLE_USER_PREFS |
false |
Enable /prefs user preferences |
SESSION_MAX_AGE_HOURS |
24 |
Max session age before eviction (hours) |
CHAT_HISTORY_MAX_TURNS |
20 |
Max conversation turns per session |
ADMIN_API_KEY |
(none) | Required for /purge/* endpoints โ fail-closed: with no value set, those routes return 403 for everyone, and an ordinary API_KEYS entry never authorizes them |
API_KEYS |
(none) | Comma-separated keys for request auth (each key = isolated user) |
CORS_ORIGINS |
localhost | Comma-separated allowed origins |
LLM_CACHE_SIZE / LLM_CACHE_TTL |
128 / 600 |
LLM response cache |
RETRIEVAL_CACHE_SIZE / RETRIEVAL_CACHE_TTL |
64 / 300 |
Retrieval cache |
TOOL_CACHE_SIZE / TOOL_CACHE_TTL |
64 / 180 |
Agent tool cache |
| Language | Code | Native Name | Language | Code | Native Name |
|---|---|---|---|---|---|
| English | en | English | Kannada | kn | เฒเฒจเณเฒจเฒก |
| Hindi | hi | เคนเคฟเคเคฆเฅ | Malayalam | ml | เดฎเดฒเดฏเดพเดณเด |
| Telugu | te | เฐคเฑเฐฒเฑเฐเฑ | Punjabi | pa | เจชเฉฐเจเจพเจฌเฉ |
| Tamil | ta | เฎคเฎฎเฎฟเฎดเฏ | Odia | or | เฌเฌกเฌผเฌฟเฌ |
| Bengali | bn | เฆฌเฆพเฆเฆฒเฆพ | Urdu | ur | ุงุฑุฏู |
| Marathi | mr | เคฎเคฐเคพเค เฅ | Gujarati | gu | เชเซเชเชฐเชพเชคเซ |
The system runs in two modes: a full Agentic RAG loop (below) and a lightweight Standard RAG fast path.
flowchart TD
Q([๐ฌ User Query]) --> P
subgraph AGENT["๐ค Agentic RAG ยท LangGraph state machine"]
direction TB
P["<b>โ Query Planner</b><br/>language detection ยท decomposition ยท HyDE <i>(optional)</i>"]
S["<b>โก Tool Selector</b><br/>Gemini function calling ยท mode = AUTO"]
E["<b>โข Tool Executor</b><br/>parallel dispatch ยท ThreadPoolExecutor"]
G["<b>โฃ Answer Generator</b><br/>format context โ build prompt โ generate"]
R{"<b>โค Reflexion Evaluator</b><br/>claim check ยท completeness judge"}
P --> S --> E --> G --> R
R -. regenerate .-> G
R -. retrieve more .-> S
R -. reformulate .-> P
end
subgraph TOOLS["๐งฐ Tool Belt"]
direction LR
T1["๐ IndicRAG Corpus<br/><i>BM25 + dense โ cross-encoder โ ColBERT (opt.)</i>"]
T2["๐ arXiv"]
T3["๐ S2 / OpenAlex"]
T4["๐ Web Search"]
T5["๐งฎ Calculator"]
T6["๐ Python Sandbox"]
end
E -.->|invokes| TOOLS
R ==>|โ
accept| F([Finalizer])
F --> A([๐ฆ Answer ยท sources ยท tool log])
classDef term fill:#bae6fd,stroke:#0284c7,stroke-width:2px,color:#082f49
classDef eval fill:#fde68a,stroke:#d97706,stroke-width:2px,color:#451a03
classDef stage fill:#e2e8f0,stroke:#64748b,color:#0f172a
classDef tool fill:#dcfce7,stroke:#16a34a,color:#052e16
class Q,A,F term
class R eval
class P,S,E,G stage
class T1,T2,T3,T4,T5,T6 tool
| Guard | Behavior |
|---|---|
| Iteration cap | Max 3 reflexion cycles |
| Wall-clock budget | AGENT_REFLEXION_BUDGET_S |
| Stuck-loop detection | Auto-accepts once completeness stops improving |
Skips the agent graph entirely โ a single pass:
Query โโโถ Hybrid retrieval (BM25 + dense โ rerank) โโโถ Generate
Typical query latency (on CPU):
| Mode | Latency | Notes |
|---|---|---|
| Standard RAG (Strategy A) | ~1โ2s | Single-pass |
| Standard RAG (Strategy B) | ~3โ6s | Includes NLLB translation |
| Agentic RAG (1 reflexion) | ~15โ30s | Multi-tool + evaluation (parallel tools) |
| Agentic RAG (max reflexions) | ~60โ90s | Bounded by timeout + reflexion budget |
Memory: base ~500MB ยท +BGE-M3 ~2.5GB ยท +reranker ~3.5GB ยท +NLLB (Strategy B) ~6GB. ColBERT rerank adds ~1GB when enabled.
| Metric | Score | Metric | Score |
|---|---|---|---|
| Retrieval Precision | 0.93 | Technical Depth | 0.88 |
| Retrieval Recall | 0.91 | Mechanistic Reasoning | 0.86 |
| Faithfulness (Grounding) | 0.98 | Cross-Document Discipline | 0.95 |
| Attribution Accuracy | 0.97 | Hallucination Rate | < 2% |
See docs/evaluation.md for methodology.
"API key not configured" โ check .env: grep LLM_API_KEY .env
"No documents indexed" โ run python ingest.py
Agent web search fails โ ensure TAVILY_API_KEY is set in .env
Agent answers truncated โ raise AGENT_MAX_TOKENS (e.g. 16384)
"Translation model gated" โ NLLB-200 needs no auth; first use downloads ~2.4GB automatically
Sessions lost on restart โ check SESSIONS_DB_PATH is writable; SQLite persistence is on by default
python purge.py --papers # Delete all PDFs
python purge.py --db # Clear vector database
python purge.py --models # Remove cached models
python purge.py --all --yes # Clear everythingContributions welcome! See CONTRIBUTING.md.
v2.4 highlights: gemini-3.6-flash default model ยท multi-user data isolation with per-API-key scoping ยท configurable session management ยท dedicated admin API key ยท clean CI linting. Full history in the git log and docs/.
Built with Google Gemini ยท LangGraph ยท Sentence Transformers (BGE-M3, reranker) ยท arXiv API ยท Semantic Scholar ยท OpenAlex ยท Tavily ยท ChromaDB ยท FastAPI.
MIT License โ see LICENSE.
- ๐ Documentation
- ๐ฌ GitHub Discussions
- ๐ Issue Tracker
Built with โค๏ธ for multilingual scientific accessibility
โญ Star this repo if you find it useful!
