About
RAGnostic is an eval harness for comparing RAG retrieval strategies over a self-fetched corpus of LLM/agent-security arXiv papers. The name's no accident, I built it to stay agnostic about which retrieval setup wins and measure that instead of guessing: dense vs. graph vs. hybrid, with and without a cross-encoder reranker, scored with RAGAS on real questions generated straight from the corpus.
How I build the corpus
The repo is split by pipeline stage, and each stage is a checkpoint, so re-running any of this is a safe, deduplicated no-op rather than starting over.
- First I fetch papers from arXiv, downloading the PDF for each one.
- Then I filter the bibliography out of each document. I embed the reference-list text and the candidate chunks with an embedding model, and drop anything whose max() cosine similarity to a citation crosses a threshold, max, not average, since a chunk only needs to closely resemble one citation to be reference-list noise.
- Then I chunk what's left using a recursive text splitter, so chunks carry overlapping context instead of getting cut off at arbitrary boundaries.
- Then I embed the chunks and push the vectors into ChromaDB.
- Then I build a knowledge graph on top: for every embedded chunk, I query Chroma for its nearest neighbors and store those as edges in Postgres. That's what lets Graph RAG expand outward from a matched chunk to its related chunks, across papers, not just within one.
How I retrieve and rerank
At query time, RAGnostic can ansIr using whichever retrieval strategy is configured:
- Dense, plain nearest-neighbor search over Chroma.
- Graph, dense search for the best match, then expand into its neighbors via the knowledge graph above.
- Hybrid, dense search plus a BM25 sparse search, merged with reciprocal rank fusion (RRF) so chunks that rank Ill in either search count for more.
On top of any of these, a cross-encoder reranker can re-score the retrieved chunks against the query directly, rather than relying on embedding similarity alone, it's slower, but it looks at the query and each chunk together instead of comparing precomputed vectors.