ragbench is a lightweight RAG benchmark and RAG evaluation framework.
Benchmark any retrieval-augmented generation (RAG) pipeline with synthetic datasets and deterministic metrics β no LLM API required for the core. Plug in your retriever and generator (LangChain, LlamaIndex, Haystack, or hand-rolled), run over a built-in dataset, and get a reproducible scorecard of retrieval and generation quality.
Built incrementally as a medium-complexity project. Retrieval + generation metrics and synthetic datasets ship first; an optional LLM-as-judge backend is planned.
- No API costs for core evals β deterministic metrics (Precision@K, Recall@K, MRR, NDCG, AnswerOverlap) run entirely locally. Only pay for LLM calls when you opt into the judge backend.
- Framework-agnostic β your pipeline is just
(retriever, generator)callables. Works with LangChain, LlamaIndex, Haystack, or hand-rolled code. - Reproducible by design β versioned synthetic datasets, no network calls in the core path. Same dataset, same scorecard, every time.
- Run-diffing built in β A/B compare two pipelines or configs head-to-head with
diff_runs.
- π§ͺ Synthetic datasets β a 10-query factual set + multi-hop set, with ground-truth relevance, so you can benchmark without a private corpus
- π Deterministic metrics β Precision@K, Recall@K, MRR, NDCG@K (retrieval) + AnswerOverlap, Faithfulness-lite, CitationCoverage (generation)
- π Framework-agnostic β your pipeline is just
(retriever, generator)callables - π Scorecards β per-metric means Β± stdev, overall weighted score, pass-rate
- π Reproducible β versioned datasets, no network calls in the core
- π« Zero hard dependencies β pure stdlib; optional
openaifor the planned judge backend
pip install ragbenchfrom ragbench import run_benchmark, scorecard
from ragbench.datasets import factual
from ragbench.report import render_scorecard
from ragbench.types import RetrievedDoc, Answer
syn = factual() # dataset + companion corpus
docs = syn.as_retrieved_docs()
def retriever(query: str) -> list[RetrievedDoc]:
... # your retrieval logic, returns RetrievedDoc lists
def generator(query: str, docs: list[RetrievedDoc]) -> Answer:
... # your LLM call, returns an Answer
run = run_benchmark(syn.dataset, retriever, generator)
print(render_scorecard(scorecard(run)))Example output:
ragbench β factual (10 queries, 0.01s)
overall: 0.940 pass-rate: 100.0%
metrics:
answer_overlap 1.000 Β±0.000 ββββββββββββββββββββ
citation_coverage 1.000 Β±0.000 ββββββββββββββββββββ
faithfulness_lite 0.980 Β±0.040 βββββββββββββββββββ
mrr 1.000 Β±0.000 ββββββββββββββββββββ
ndcg@k 1.000 Β±0.000 ββββββββββββββββββββ
precision@k 0.200 Β±0.000 ββββ
recall@k 1.000 Β±0.000 ββββββββββββββββββββ
| Dataset | Queries | Notes |
|---|---|---|
factual() |
10 | single-doc factual Q&A across 5 categories |
multi_hop(n) |
n | two-doc evidence, tests full-evidence recall |
Retrieval (need relevant_doc_ids ground truth): Precision@K, Recall@K, MRR, NDCG@K.
Generation (no LLM judge): AnswerOverlap (token Jaccard vs expected), Faithfulness-lite (fraction of answer tokens supported by context β a hallucination proxy), CitationCoverage (cited docs that were actually retrieved).
LLM-as-judge (optional): FaithfulnessJudge + AnswerRelevanceJudge β a pluggable JudgeBackend scores answers. Ships with a deterministic MockJudge (no network, real heuristics) and an LLMJudge (optional openai dep). Swap the backend, keep the metric.
ragbench datasets # list datasets
ragbench metrics --judge mock # list the metric suite
ragbench run --dataset factual # run reference pipeline, print scorecard
ragbench run --dataset adversarial # hard-negative distractors (precision stress)
ragbench run --dataset long-tail # head + tail queries (recall on rare queries)
ragbench run --pipeline mypipe.py # benchmark YOUR retriever+generator
ragbench run --judge mock --json # add judge metrics, JSON output
ragbench run --judge llm --model gpt-4o-mini # real LLM judge (needs OPENAI_API_KEY)
ragbench compare --dataset factual # A/B diff: good vs weak retrieverWrite a mypipe.py exposing retriever and generator, then:
ragbench run --pipeline mypipe.py --dataset factual --json# mypipe.py
from ragbench.types import RetrievedDoc, Answer
def retriever(query: str) -> list[RetrievedDoc]:
... # your retrieval logic
def generator(query: str, docs: list[RetrievedDoc]) -> Answer:
... # your LLM callCompare two pipelines or configs head-to-head:
from ragbench import run_benchmark, diff_runs, render_diff
run_a = run_benchmark(dataset, retriever_a, generator)
run_b = run_benchmark(dataset, retriever_b, generator)
print(render_diff(diff_runs(run_a, run_b, "pipe-a", "pipe-b")))- LLM-as-judge backend (faithfulness, answer-relevance) β optional
openaidep - CLI:
ragbench run --dataset factual - Run diffing: compare two pipelines head-to-head
- More synthetic datasets (adversarial, long-tail)
- Pluggable user pipelines (
--pipeline mypipe.py)
git clone https://github.com/alvabillwu/ragbench.git
cd ragbench
pip install -e ".[dev]"
pytest -v
python examples/benchmark.py
ragbench run --judge mockAn honest comparison with related RAG evaluation frameworks:
| Tool | Core metrics need an LLM? | Dependencies | Best for |
|---|---|---|---|
| ragbench | No β deterministic core (optional LLM judge) | Zero hard deps (stdlib) | Fast, reproducible, offline retrieval + generation scoring in CI |
| RAGAS | Yes β most metrics use an LLM + embeddings | Heavier (LLM/embedding providers) | Rich, research-grade RAG metrics when calling a model is fine |
| TruLens | Yes β feedback functions call models | Heavier | Instrumented eval + observability of live RAG apps |
| DeepEval | Often β LLM-based metrics | Moderate | Pytest-style LLM/RAG test assertions |
When to use ragbench: you want deterministic, no-network retrieval and generation metrics (Precision@K, Recall@K, MRR, NDCG, AnswerOverlap) that produce the same scorecard every run β ideal for CI and A/B pipeline diffs. Reach for RAGAS, TruLens, or DeepEval when you specifically want LLM-graded metrics and don't mind the API calls; RAGAS in particular supports custom/local models if you'd rather not hit a hosted API. ragbench also ships an optional LLM judge if you want both worlds.
Part of the alvabillwu AI/LLM DevTools suite:
synthqaβ Synthetic QA evaluation dataset generatorembeddings-benchβ Embedding model benchmarking toolkitjudgekitβ Reusable LLM-as-judge harness for evaluationeval-suiteβ Unified evaluation suite for LLM outputstokencostβ LLM token cost calculator and visualizer
MIT Β© alvabillwu
β Like this? Star the repo to support open-source RAG evaluation tooling!