Model-agnostic LLM evaluation that feels like pytest.
Project description
____ ______ __
/ __ \____ ___ ____ / ____/___ ____/ /____
/ / / / __ \/ _ \/ __ \/ __/ / __ \/ __ / ___/
/ /_/ / /_/ / __/ / / / /___/ / / / /_/ (__ )
\____/ .___/\___/_/ /_/_____/_/ /_/\__,_/____/
/_/
Model-agnostic LLM evaluation that feels like pytest.
Install
pip install openeval-ai
Optional extras:
pip install "openeval-ai[openai]" # OpenAI adapter
pip install "openeval-ai[anthropic]" # Anthropic adapter
pip install "openeval-ai[semantic]" # semantic_sim scorer
Quickstart (10 lines, zero config)
from openeval import EvalCase, run
from openeval.scorers import exact_match
cases = [EvalCase(input="2+2", expected_output="4")]
def my_model(prompt: str) -> str:
return "4"
summary = run(my_model, cases, {"exact": exact_match})
print(summary.pass_rate) # 1.0
Why OpenEval
- Scorers are just Python functions — composable, testable, versionable.
- Model-agnostic — OpenAI, Anthropic, Ollama, or any callable.
- CI-first — pytest plugin + GitHub Action for evals on every PR.
Architecture
flowchart LR
M[Your Model] --> A[Adapter]
A --> R[Runner / Async Runner]
R --> S[Scorers]
S --> E[EvalSummary]
E --> H[HTML Report]
E --> C[CLI]
E --> G[GitHub Action]
Comparison (benchmarks)
Benchmarks live in benchmarks/ and use a fully offline mock model for reproducibility.
Measured on 2026-03-20 with uv run benchmarks/run_all.py (see benchmarks/results.json).
Task A: 20-case Q&A (exact match), mock model with 10ms latency per call.
| Tool | Setup (LOC) | Setup time (s) | Run time (s) | Notes |
|---|---|---|---|---|
| OpenEval | 38 | 0.090 | 0.203 | ✅ |
| DeepEval | 44 | 2.250 | 0.261 | ✅ |
| Promptfoo | 50 | — | — | not run |
Notes:
- Promptfoo is optional in the harness; set
OPENEVAL_BENCH_PROMPTFOO=1to run it. - Promptfoo may require Node.js
>=20.20.0or>=22.22.0(newer thanv22.17.x).
Built-in scorers
| Scorer | What it does |
|---|---|
exact_match |
1.0 if output equals expected |
contains |
1.0 if expected appears in output |
regex(pattern) |
1.0 if output matches a regex |
semantic_sim |
cosine similarity via embeddings (optional extra) |
llm_judge(judge_fn) |
judge output quality 0.0–1.0 (bring your own judge) |
Built-in suites
| Suite | What it tests |
|---|---|
hallucination |
admits uncertainty vs fabricates |
factuality |
basic factual QA |
instruction_following |
formatting/constraint compliance |
Run a suite:
from openeval.suites import factuality
summary = factuality.run(lambda _: "Paris")
print(summary.pass_rate)
GitHub Action
# .github/workflows/eval.yml
name: LLM Eval
on: [pull_request]
jobs:
eval:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: OWNER/openeval-action@v1 # replace OWNER
with:
suite: hallucination
model: openai:gpt-4o-mini
threshold: "0.8"
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CLI
# Run a suite
openeval run --suite factuality --model ollama:llama3.2
# Parallel (async) + HTML report
openeval run --suite hallucination --model openai:gpt-4o-mini --async --concurrency 20 --output report.html
Async evaluation
import asyncio
from openeval import EvalCase, arun
from openeval.scorers import exact_match
cases = [EvalCase(input="2+2", expected_output="4")]
async def model(_prompt: str) -> str:
return "4"
summary = asyncio.run(arun(model, cases, {"exact": exact_match}, concurrency=20))
print(summary.pass_rate)
Examples
examples/01_basic_qa.pyexamples/02_openai_eval.pyexamples/03_compare_models.pyexamples/04_rag_eval.pyexamples/05_chatbot_eval.pyexamples/06_code_eval.pyexamples/07_custom_scorer.pyexamples/08_cicd_integration.py
Contributing
See CONTRIBUTING.md.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file openeval_ai-0.1.0.tar.gz.
File metadata
- Download URL: openeval_ai-0.1.0.tar.gz
- Upload date:
- Size: 136.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd46eb0735cb57e56bad113ab639f7dd55fdc9ff4cb478913e7eead16ee6bd0e
|
|
| MD5 |
5dc1923623a5ef579c9cade5b87506df
|
|
| BLAKE2b-256 |
b4753babdb08da4766cd781320268fefc9b36933753220993d5ac593a3e0113c
|
File details
Details for the file openeval_ai-0.1.0-py3-none-any.whl.
File metadata
- Download URL: openeval_ai-0.1.0-py3-none-any.whl
- Upload date:
- Size: 30.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
120ad8c7e589d983fd0ba535040bc736ce9851059fc3790cd9c2b579cfec43bc
|
|
| MD5 |
612ece1bdb8f6db090eca24bd7ec5cbb
|
|
| BLAKE2b-256 |
89b6f8197e70a1e635f61741a1637e8e24f71d6b82c6a7dd3f7b350355046957
|