Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

179 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐ŸŒ IndicRAG โ€” Multilingual Agentic Scientific RAG

Ask DeepWiki Code Wiki License: MIT Python 3.11+ FastAPI Google Gemini LangGraph Version

INDICRAG.png

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.


What's New in v2.4

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

v2.4 patch โ€” correctness fixes

  • Faithfulness verification restored โ€” verify.check_claims was passing (index, text) tuples to the NLI model instead of the chunk text, so every call raised and every answer reported confidence: 0.0 with no evidence.
  • Generation restored on gemini-3.6-flash โ€” models that reject thinking_budget=0 returned 400 INVALID_ARGUMENT. The Gemini backend now remembers per-model rejections and retries once without thinking_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 from LLM_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.

โœจ Key Features

๐Ÿค– Agentic RAG Pipeline

  • 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 AgentState so follow-ups resolve pronouns and references
  • Parallel tool execution โ€” multiple selected tools run concurrently via ThreadPoolExecutor
  • Sub-query cap โ€” AGENT_MAX_SUB_QUERIES limits 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=AUTO lets the model return an empty tool list on regenerate actions

๐Ÿ” Hybrid Retrieval Pipeline

  • Dense + sparse โ€” BGE-M3 (1024d) fused with BM25 via Reciprocal Rank Fusion (RRF)
  • Two-stage reranking โ€” BAAI/bge-reranker-v2-m3 cross-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-base scores entailment per claim; unsupported assertions flagged, stripped, or regenerated (FAITHFULNESS_ENFORCE)
  • HNSW tuning knobs โ€” ef_search, ef_construction, M all env-configurable

๐Ÿ“ฅ Smart Ingestion

  • 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 SequenceMatcher ratio (DEDUP_TITLE_THRESHOLD)
  • MD5 content dedup + parallel extraction, Indic-aware chunking

๐ŸŒ True Multilingual Support

  • 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

๐Ÿ›ก๏ธ Production-Ready Infrastructure

  • 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 & Literature Reports

  • 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

๐Ÿ—„๏ธ Three-Layer Caching + Gemini Prompt Cache

  • 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/stats for observability

๐Ÿš€ Quick Start

Prerequisites

  • Python 3.11+
  • Google Gemini API key (Get one here)
  • 8GB+ RAM recommended
  • (Optional) Tavily API key for agent web search (Get one here)

Installation

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.txt

Configuration

cp .env.example .env

Edit .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

Ingest Documents

# Place PDFs in papers/ directory, then:
python ingest.py

# Or specify a directory:
python ingest.py path/to/pdfs

Start Server

python start_server.py

# Development mode with auto-reload
python start_server.py --dev

Access at:


๐Ÿ“– Usage

๐Ÿ–ฅ๏ธ Web UI

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.

๐Ÿ”Œ REST API

Streaming Query โ€” POST /query/stream

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 Events

Standard Chat โ€” POST /chat

r = requests.post('http://localhost:8080/chat', json={
    "message": "เฐฏเฐพเฐ‚เฐŸเฑ†เฐจเฑเฐจเฐพเฐคเฑ‹ ml เฐจเฑ เฐŽเฐฒเฐพ เฐ…เฐฎเฐฒเฑ เฐšเฑ‡เฐฏเฐตเฐšเฑเฐšเฑ?",
    "strategy": "A"
})
print(r.json()['answer'])

Agentic Query โ€” POST /agent/query

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.


๐Ÿ”ง API Reference

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)

๐Ÿ“ Project Structure

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

โš™๏ธ Configuration

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

๐ŸŽฏ Supported Languages

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 เช—เซเชœเชฐเชพเชคเซ€

๐Ÿ—๏ธ Architecture

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
Loading

๐Ÿ”’ Loop guardrails

Guard Behavior
Iteration cap Max 3 reflexion cycles
Wall-clock budget AGENT_REFLEXION_BUDGET_S
Stuck-loop detection Auto-accepts once completeness stops improving

โšก Standard RAG mode

Skips the agent graph entirely โ€” a single pass:

Query โ”€โ”€โ–ถ Hybrid retrieval (BM25 + dense โ†’ rerank) โ”€โ”€โ–ถ Generate

๐Ÿ“Š Performance

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.


๐Ÿ“ˆ KPI Metrics

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.


๐Ÿ› Troubleshooting

"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


๐Ÿงน Maintenance

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 everything

๐Ÿค Contributing

Contributions 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/.


๐Ÿ™ Acknowledgments

Built with Google Gemini ยท LangGraph ยท Sentence Transformers (BGE-M3, reranker) ยท arXiv API ยท Semantic Scholar ยท OpenAlex ยท Tavily ยท ChromaDB ยท FastAPI.


๐Ÿ“„ License

MIT License โ€” see LICENSE.


๐Ÿ†˜ Support


Built with โค๏ธ for multilingual scientific accessibility

โญ Star this repo if you find it useful!

Report Bug ยท Request Feature ยท Documentation

About

Production-grade multilingual RAG for scientific research across 12 languages (English + 11 Indic). Uses BGE-M3, ChromaDB, hybrid BM25+dense retrieval, cross-encoder reranking, and Gemini 3.6 Flash. Includes fast RAG, LangGraph agents, 6 research tools, NLI verification, multimodal indexing, and grounded citations (<2% hallucinations).

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages