Instrumentum · open source
ResearchLens
A research assistant that reads papers and shows its working. Ask it something — or hand it your own PDF — and every claim comes back bound to the passage it came from. When nothing supports an answer it says so, which is the harder half.
101 papers · 9,540 passages — vision-language models, retrieval-augmented generation and federated learning on one side, single-cell genomics and causal discovery on the other.
Ask it something
Connecting…
Not connected
Nothing is answering. The hosted instance is not deployed yet, and browsers block a page on the public web from reaching a server on your own machine — so running it locally means opening it locally too:
git clone https://github.com/asifuddin01/researchlens
cd researchlens
docker compose upThen open localhost:8000. Your papers stay on your machine, the default model is local, and no API key is needed.
How it answers
Every part of the retrieval stack had to justify itself with a measured number before it was kept. What follows is what survived.
- 01Parseheadings by font geometry; sections and page spans, not flat text
- 02Chunkpassages that never cross a section, and can cite themselves
- 03RetrieveBM25 and dense, fused by rank rather than by score
- 04Reranka cross-encoder that sees query and passage together
- 05Reach outarXiv, PubMed and OpenAlex when the question asks what is current
- 06Answermarkers resolved against the evidence, or a refusal
- 07Addyour own PDFs, indexed for your session and nobody else’s
A PDF is not a string. Headings are found by font geometry, so a passage knows which section it came from and which page it was printed on — which is what lets a citation name a place rather than gesture at a document.
A fixed corpus cannot say what a field is doing now, and answering as though it could is the failure that looks most like success — asked for current trends in large language models, an earlier version answered from Attention Is All You Need (2017) and BERT (2018), with real citations and no sign its evidence was eight years old.
The first fix was to detect thin coverage from the retrieval scores, and it does not work. A question the corpus cannot answer at all — gaps in automated renal CT reporting — scored a cosine of 0.829, above questions it answers well; a good encoder returns high similarity for topically adjacent text whether or not the answer is present, which is the property that makes it a good retriever and a useless coverage detector. The reliable signal was the question's own wording. What is current is a question about a field, not about these papers, and is worth two seconds of live search whatever the corpus happens to hold.
arXiv is preprints, mostly machine learning and physics; PubMed is the life sciences. Between them they miss the engineering and computer-science journal literature almost entirely, so OpenAlex is searched too — which is also why there is no IEEE Xplore here. Xplore's own API needs an institutional key and so cannot be a default, but its records are in OpenAlex, and the coverage arrives without the key. What does not arrive is full text: live results are marked as abstracts, dated, and never shown with a page number, because an abstract supports what a paper claims and not what it measured.
A paper you attach goes through the same parser, chunker and encoder as the hundred and one — into an index belonging to your browser session and nothing else. It is never written to disk and never joins the shared corpus; that is a correctness requirement rather than a courtesy, because the demo is a single process serving every visitor and a global index would quote a stranger's manuscript back at someone who never uploaded it, indistinguishable from a paper that belongs there. Your passages then get guaranteed room in the evidence: someone who hands over a paper is asking about that paper, and the cross-encoder ranks a corpus passage above it more often than not.
The two retrievers fail differently. A dense encoder maps Dice 0.91 and scGPT into neighbourhoods of things that mean something similar, which for a metric value or a model name is exactly wrong. BM25 matches them literally and is helpless at paraphrase. Fusing them by rank rather than score means no normalisation has to be tuned per corpus.
What it will not do
Grounding is not a line in the prompt. A 3B model will agree to cite its sources and then not, so each of these is enforced in code, after generation, where the model has no say.
- No evidence, no call
- A model asked a question with no context answers from its training, fluently. A reader cannot tell that from a grounded answer, so the model is never invoked.
- Citations are checked, not trusted
- A marker pointing at a passage that was never retrieved is deleted after generation. An invented [7] does not reach the page.
- Unsupported becomes refusal
- An answer left with no surviving citation is replaced by a refusal. A fluent unsourced paragraph is worse than none.
- One paper cannot fill the context
- Passages per paper are capped. Otherwise a synthesis and a paraphrase of one document look identical, because both arrive with citations.
- Your papers stay yours
- A paper you add is indexed for your session alone — held in memory, never written to disk, never merged into the shared corpus. The demo is one process serving everyone, so a global index would put a stranger’s manuscript in someone else’s answers, with a citation.
- Live evidence is labelled
- An abstract fetched from arXiv, PubMed or OpenAlex supports what a paper claims, not what it measured. It is marked, dated, and never given a page number.
Found by running it
A corpus of a hundred real papers breaks a parser in ways no test anticipates. Each of these was a silent fault — nothing raised, the output merely got quietly worse.
19 → 0
papers with broken titles, twice
The first fix walked size tiers downward, because the largest glyph on page one is often a drop cap and titles extracted as “M”, “w”, “1 3”. That claim was premature: an audit later found nineteen still wrong for three other reasons. Small-caps titles lost every word’s first letter — “N MAGE IS ORTH X ORDS” — because a capital and its small caps share a baseline, not a top. arXiv’s sideways margin stamp scattered into seven titles. And Elsevier sets its own masthead half a point larger than the paper’s title.
77%
of passages changed by that fix
Grouping lines by baseline rather than by top was meant to repair titles. It repaired the body too: columns had been interleaving mid-sentence, rotated axis labels landed in paragraphs, and subscripts were flung to the end of the line. Fewer passages now — 9,870 to 9,593 — because there is less rubbish to cut up.
2×
faster embedding, from one number
Batches of 32 embed 43 passages in 6.7s; batches of 64 take 11.2s. A batch is padded to its longest member, and past about thirty the odds of catching a 512-token passage approach one, so the whole batch pays for it. The vectors agree to seven decimal places.
111s → 855ms
retrieval latency
CoreML is 2.6× faster for the bi-encoder and 24× slower for the cross-encoder, which splits into 39 partitions and thrashes. A provider is a property of the model, not the machine.
45 → 3
line-break hyphens per paper
“expres- sion” matches nothing. Whether to rejoin is decided against the document’s own vocabulary, so “single- cell” keeps its hyphen and “con- trol” does not.
13% → 70%
passages in a named section
Sections were flat, so “3.2 Training details” lost its parent. Font size already encoded the hierarchy and was being discarded.
What is measured
Sixty questions over the corpus, each hand-labelled with the passages that genuinely answer it. Written before the retrieval code, against a deliberately weak baseline, so every component added afterwards arrives with a delta rather than an intuition. If a model wrote the questions and a model judged the answers, the table would measure a model's agreement with itself.
The ablation is still being labelled. It will report Recall@5, MRR and nDCG@10 across four configurations — dense only, BM25 only, hybrid, and hybrid with reranking — emitted by the harness rather than written by hand, so the published numbers cannot drift from the code.
Reranking may turn out not to help on a corpus this size. If so, that row goes in unchanged: it is the only result here that could be surprising.
Built by Md. Asif Uddin. MIT licensed. Runs with no API key.