HELLO! I AM A RETRIEVER THAT READS ACROSS SCRIPTS AND KNOWS WHEN TO SAY NO.

Evidence-grounded question answering for Hindi, English and Hinglish, over Indian government scheme documents.

English ← drag the tear → हिन्दी (scroll)
HinglishScholarship ke liye minimum eligibility kya hai? Hindiछात्रवृत्ति के लिए न्यूनतम पात्रता क्या है? EnglishWhat is the minimum eligibility for a scholarship?
About

A citizen asks in Hindi, in English, or — most often — in Romanized Hindi–English. The answer sits in a document written in the other language, in the other script. IndicRAG-QA finds it, cites it, or says it does not know.

40government schemes, each with an English and a Hindi article
694passages, every Hindi document through five Devanagari integrity checks
393verified questions across six query × evidence language cells
4kinds of unanswerable question, from out-of-scope to near-miss
How it works

One path,
three scripts.

01

Read the script

Devanagari, Latin, or both — and for Latin, whether Hindi function words like kya and ke liye make it Hinglish.

English · Indic · Code-Mixed
02

Retrieve twice

BM25 matches surface words; a multilingual encoder (e5-base) matches meaning across languages. 50 candidates each.

694 passages
03

Fuse by eligibility

A passage in the other script is scored on the retriever that could see it — not docked for a vote BM25 could never cast.

script-aware RRF
04

Answer from evidence

The generator answers only from the retrieved passages and names the one it used.

cited passage id
05

Or refuse

Below the BM25 floor, or when the generator finds no answer in the passages: "Insufficient information available in the provided documents."

4 answerability signals
Architecture

Built once,
asked often.

Offlineonce per corpus · about 40 min on a CPU
Per query~0.25 s extracted · ~1 min generated

Retrieve reads both offline indices; fusion reads each passage's script.

Evaluationevery committed number, one command
Storage & caching
data/
├── corpus_manifest.jsonl   sha256 + licence per source
├── text/<doc_id>.txt       extracted, before normalization
├── passages.jsonl          694 passages, frozen at v1
├── lex/lexical.pkl         TF-IDF + BM25
├── emb/<model>.npy         float32, L2-normalized
├── emb/<model>.meta.json   passage fingerprint
└── gen/<model>.jsonl       generations, keyed by prompt hash

Nothing expensive is computed twice, and every cache carries the hash of its input: an index built from different passages refuses to load.

The project, measured
0GPUs — every figure reproduces on a 4-core laptop
393tests (pytest), plus a ruff-clean tree
25CLI commands, audited against the docs
22reports, each regenerated and diffed by regenerate-reports.py --check
Findings

Fusion was
the problem.

0.274→0.685

Cross-lingual Recall@5 on the sealed test split. Standard Reciprocal Rank Fusion docks a Devanagari passage for the lexical retriever's blindness to its script, and scores below the dense retriever it contains. Script-aware fusion counts only the retrievers that could have returned a passage — +0.411, p = 0.0001, no monolingual cost. Over dense retrieval alone it gains little: +0.030, significant only on code-mixed queries.

system
monolingual
cross-lingual
code-mixed

Retrieval makes answers groundable.

0.18 → 0.87

Share of answers the cited passage supports, closed-book against dense RAG, on 72 test questions (+0.684, p = 0.0001).

Which retriever does not reach the answer.

−0.027

Token-F1, script-aware against dense RAG (p = 0.55). The generator still loses more than retrieval: 0.359 against 0.223.

Only a reader sees a missing fact.

22 / 23

Near-miss questions caught by the generator's own abstention. A BM25 score threshold catches about half; the fused score, almost none.

How fusion breaks — one real test question

Watch the
gold sink.

BM25

matches words — can only reach passages in the query's script

    Dense (e5-base)

    matches meaning — ranks the Hindi gold passage first

      Fused

        Plain RRF scores each passage Σ 1/(60 + rank) over the retrievers that returned it. Script-aware RRF multiplies by 2 / |eligible|, where BM25 is ineligible for a passage in a script other than the query's. Both are recomputed here in your browser from the real candidate lists (50 per retriever) for ; the rankings match index/hybrid.py.

        Four ways to be unanswerable

        Knowing
        when not to.

        Questions are real items from the gold set. Recall is the share of each class correctly refused: the BM25 floor on the 273-item test split (report-answerability-bm25.txt); the generator's own abstention on 85 held-out items of an enriched sample (report-answerability-signals.txt). Each class rests on 7–23 items.

        Playground

        Ask it
        something.

        checking for a live server…
        detected as EnglishIndicCode-Mixed
        retriever
        Results

        Every system,
        one test split.

        Recall@5allmonolingualcross-lingualcode-mixed

        216 answerable test questions, scored once after tuning on the dev split; 95% bootstrap intervals and paired tests in evals/report-retrieval-test.txt. The gold set was verified in two language-model passes, with the test split then reviewed by the author; the blind second pass was a separate model instance.