EvalRAG
A from-scratch CLI + library for evaluating RAG pipelines — no RAGAS, TruLens, or DeepEval wrappers.
Answers "how do I know my RAG pipeline is actually working well?" by producing automated, reproducible quality scores across three metrics:
- Faithfulness — is every claim in the answer grounded in the retrieved chunks?
- Answer relevance — does the answer actually address the question?
- Context precision — did the retriever surface relevant chunks, ranked high?
Every score is traceable to an explicit, inspectable decision (the raw judge output is kept). It exits non-zero when a metric falls below its threshold, so it works as a CI gate.
Install
# From PyPI (the import package is `evalrag`):
pip install rag-scorer
# Or straight from GitHub, no clone:
pip install git+https://github.com/lucasmonteverdi1/evalrag.git
# Or with uv, from a clone:
uv sync --all-groups
You need an OpenRouter API key (one key, any vendor's models):
export OPENROUTER_API_KEY="sk-or-..."
Evaluate your RAG pipeline
1. Write an adapter
EvalRAG treats your pipeline as a black box. Implement one method — run(question) that
returns (retrieved_chunks, generated_answer):
# my_eval.py
from evalrag.types import Chunk
class MyRAGAdapter:
def run(self, question: str) -> tuple[list[Chunk], str]:
# Whatever your pipeline is (LangChain, LlamaIndex, raw code — doesn't matter):
docs = my_retriever.search(question)
answer = my_llm.generate(question, docs)
return [Chunk(id=d.id, text=d.text) for d in docs], answer
adapter = MyRAGAdapter() # module-level instance evalrag will import
2. Provide questions
A JSON list of questions to evaluate. expected_answer / source_chunk_id are optional
(the latter enables context precision's deterministic, no-LLM path):
[
{"question": "What is the capital of France?", "source_chunk_id": "doc-42"},
{"question": "What is the return policy?"}
]
3. Run
evalrag --adapter my_eval:adapter --inputs questions.json --out-dir eval-out
This runs your pipeline over each question, scores all three metrics, writes
eval-out/report.json + eval-out/report.html, and exits 0 if every metric is at
or above its threshold, 1 if any falls below, 2 on a config/usage error.
Note:
--adapterimports and runs the module you name, so only pass a spec you trust (likepytest --plugin). Don't derive it from untrusted input.
Don't have questions yet? Generate them from your documents instead of --inputs:
evalrag --adapter my_eval:adapter --generate documents.json
# documents.json: [{"id": "doc-42", "text": "..."}, ...]
Try it with no code using the bundled demo adapter:
echo '[{"question":"What is the capital of France?"}]' > q.json
evalrag --adapter evalrag.demo_adapter:demo_adapter --inputs q.json
Reading the reports
Each run writes two files to --out-dir:
report.html — open in a browser. Top section is a per-metric score table plus
an overall number (informational only — gating is per-metric, not on the overall).
Below that, each evaluated case shows its question, the pipeline's answer, and every
metric's score + rationale. Expand "raw judge output" on any metric to see the
judge's verbatim reasoning — this is the traceability guarantee: no score is a black box.
report.json — the same data, machine-readable, for dashboards or diffing across
runs:
{
"summary": {
"n_cases": 2,
"per_metric": { "faithfulness": 1.0, "answer_relevance": 1.0, "context_precision": 1.0 },
"overall": 1.0 // informational, NOT used for gating
},
"cases": [
{
"question": "...",
"generated_answer": "...",
"metrics": [
{ "metric": "faithfulness", "score": 1.0, "rationale": "1/1 claims grounded",
"raw_judge_output": "..." } // the judge's full response, kept verbatim
]
}
]
}
How to read the numbers: each metric is 0.0–1.0, higher is better. A metric fails
(and the run exits non-zero) when its mean score is below the threshold in
configs/thresholds.yaml. The terminal prints a [PASS]/[FAIL] line per metric and a
final Result: PASS/FAIL.
Use in CI
evalrag's exit code gates the build:
# .github/workflows/eval.yml
- run: pip install git+https://github.com/lucasmonteverdi1/evalrag.git
- run: evalrag --adapter my_eval:adapter --inputs questions.json
env:
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
Thresholds live in configs/thresholds.yaml (override with --thresholds-config).
Use as a library
Every metric is importable and takes (EvalCase, judge):
from evalrag.scorer.faithfulness import score_faithfulness
result = score_faithfulness(eval_case, judge) # -> MetricResult(score, rationale, ...)
Configuration
configs/models.yaml— judge and system-under-test models (the judge must differ from the model being evaluated, to avoid self-preference bias). Secrets come from env vars named here (api_key_env), never stored in YAML.configs/thresholds.yaml— per-metric pass thresholds.configs/prompts.yaml— pinned judge-prompt versions.
Troubleshooting
ModuleNotFoundError: No module named 'evalrag.cli' during local development.
Only affects the editable dev install (uv sync), never a pip install of the package.
It happens if you mix uv pip install/uninstall with uv sync. Reset the environment:
rm -rf .venv && uv sync --all-groups
Then use uv run evalrag .... (Don't mix uv pip and uv sync in the same venv.)
Design
See AGENTS.md for the full architecture, metric definitions, and the scorer-first build order.
Metadata
Release files for rag-scorer 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| rag_scorer-0.1.0.tar.gz | 27.4 kB | Without provenance | Details for rag_scorer-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| rag_scorer-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for rag_scorer-0.1.0-py3-none-any.whl |
Total release size: 69.0 kB
Release files / rag_scorer-0.1.0.tar.gz
| Download URL | rag_scorer-0.1.0.tar.gz |
|---|---|
| Size | 27.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4e727eeed546bae97e69b466be137dad54cff1fb035b540e55e9cce9ece44234
|
|
BLAKE2b-256 checksum How to use checksums |
438d02461e59aebcbf1f8d494509e6e40f8039a9038bedb445255a706204e8bf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / rag_scorer-0.1.0-py3-none-any.whl
| Download URL | rag_scorer-0.1.0-py3-none-any.whl |
|---|---|
| Size | 41.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
771b021b29bb94dfacf505e9c8eb89f284cc8edd94fff55844a07a4fc383135d
|
|
BLAKE2b-256 checksum How to use checksums |
f28dd93a6df861af2b1beb23374910f186eb736437f5901a7d5c2c429c7f58b7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for rag-scorer 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.