Skip to main content

A small, focused eval harness for evaluating AI systems in Python. Zero dependencies.

Project description

eval-harness

tests

A small, focused Python library for running structured evaluations of AI system outputs against expected results, using pluggable graders — aimed at developers who need a lightweight, ready-to-use eval loop.

Why this exists

Writing a reliable eval loop from scratch is boilerplate most developers repeat: load cases, call a system, compare outputs, aggregate stats, save results. eval-harness packages that loop into a composable, install-ready library with validated I/O, structured result types, and three grading strategies out of the box. Reach for it when you want to focus on your system under test, not the scaffolding around it.

Install

pip install -e .

Requires Python 3.9+.

Quick start

Point the harness at a set of cases, hand it your system and a grader, and it runs the loop for you:

from eval_harness import load_cases, run_eval, summarize, save_results, normalized_match

def my_system(text: str) -> str:
    return call_your_model_here(text)  # replace with your real system

cases = load_cases("cases.json")
results = run_eval(cases, my_system, normalized_match)
summary = summarize(results)

save_results(results, "results.json", summary)
print(f"Pass rate: {summary['pass_rate'] * 100:.1f}%")

The system under test is any callable of shape (input: str) -> str. Because you inject it, the harness stays independent of any particular model or provider — it evaluates whatever you hand it.

Cases file format

Cases are a JSON array of objects, each with exactly two string keys, input and expected:

[
  { "input": "What is 2 + 2?", "expected": "4" },
  { "input": "What is the capital of France?", "expected": "Paris" },
  { "input": "Translate 'hello' to Spanish", "expected": "hola" }
]

Loading is strict by design: a missing file, invalid JSON, a non-array top level, a missing key, or a non-string value each raises immediately rather than silently producing a partial or empty run. An eval's value is a trustworthy number, so bad input fails loudly instead of quietly corrupting the result.

Graders

A grader is any callable of shape (output: str, expected: str) -> bool. Three are included:

Grader Matches when
exact_match output equals expected exactly (case- and whitespace-sensitive)
normalized_match they match after trimming surrounding whitespace and lowercasing
contains_match expected appears anywhere inside output (empty expected never matches)

Because every grader shares the same shape, they are interchangeable — swap one for another without touching the runner. You can also pass your own function; if it takes (output, expected) and returns a bool, it works.

Results

run_eval returns one EvalResult per case, each carrying its EvalCase, the system's actual_output, and a status:

Status Meaning
PASSED the system ran and the grader accepted the output
FAILED the system ran but the grader rejected the output
ERROR the system raised while producing the output

The three states are a real distinction: a wrong answer and a crash are different failures, and the harness keeps them separate. A system that raises on one case does not stop the run — that case is recorded as ERROR and the loop continues, so one bad case never invalidates the whole batch.

summarize rolls the results into totals and a pass rate:

{"total": 3, "passed": 2, "failed": 1, "errored": 0, "pass_rate": 0.67}

Command line

A thin CLI runs the full pipeline on a cases file against a built-in example system — useful as a runnable demo:

python -m eval_harness cases.json --grader exact

--grader accepts exact, normalized, or contains (default: exact). The CLI's example_system is a documented stand-in that always returns a fixed string; for real evaluation, use the library and inject your own system as shown in the quick start.

Testing

The library ships with 26 tests across 7 test files, covering all three graders (including edge cases like empty and whitespace-only inputs), the runner's pass / fail / error branching, case and result serialization in both directions, and the summarizer's counts and pass-rate calculation — including the empty-run guard.

pytest

Design notes

  • Injected dependencies. The system under test and the grader are handed in, not built in. This keeps the runner independent of any model, makes every component testable in isolation, and lets graders be swapped freely.
  • Structured results over booleans. Outcomes are a three-state enum, not a bool, because "wrong" and "errored" are genuinely different and a report needs to tell them apart.
  • Strict boundaries. Input is validated where it enters the system; bad data fails loudly rather than propagating a silent, misleading result.

Roadmap

Planned work is tracked in ROADMAP.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

eval_harness_lite-0.1.0.tar.gz (11.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

eval_harness_lite-0.1.0-py3-none-any.whl (9.3 kB view details)

Uploaded Python 3

File details

Details for the file eval_harness_lite-0.1.0.tar.gz.

File metadata

  • Download URL: eval_harness_lite-0.1.0.tar.gz
  • Upload date:
  • Size: 11.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for eval_harness_lite-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c7841ed855887cc9476ee0c38680e494dbc4c3d54994c831931df56ad38e5739
MD5 a170a7425c13807107cf33321f784ced
BLAKE2b-256 4ca0e2ebbfc83dff8f49aa1b889b4e25ebc3c013f926538ab9b332bf9c7f69ef

See more details on using hashes here.

File details

Details for the file eval_harness_lite-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for eval_harness_lite-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 81e6842478b218fbf1f1e4d8772a18789fd04dd5bceab35d4330c425d3ab6b70
MD5 4694e0c7e30ed3cf25f1104a0b080092
BLAKE2b-256 b28ba2226d6ea1295b9b2cce16cdbccaf6344e010cc6364af2862141ac5fe4fd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page