ek#
ek (Evaluation Kit) — a framework for building Knowledge Evaluation systems, evaluating the outputs of information-extraction systems. OCR is treated as the noisiest special case of a general problem, so the core is source-agnostic and the OCR pieces are optional.
import ek
ek.score("hello wrld", "hello world") # -> Score(value=0.0909..., metric='cer')
ek.score("hello wrld", "hello world", metric="wer").value # 0.5
ek.evaluate(
[("ct", "cat"), ("dg", "dog")], metric="cer"
).aggregate # 0.333... (global CER)
What it does#
Evaluating an extraction splits along two axes — is there a gold answer
(reference-based) or not (reference-free), and are we scoring one item or a whole
corpus. ek gives you both halves through two facades over one shared typed schema:
score()/evaluate()— reference-based: compare against gold, one item or a corpus, the metric chosen by output type (string → CER/WER, record → field-F1), aggregated correctly (global error-rate accumulation, micro-F1; never a naive mean) with optional per-slice cuts.estimate_quality()— reference-free: gather signals → calibrate → validate → decide accept/flag/block, with no gold answer.
Everything swappable is a strategy injected with a smart default, so the simple call works out of the box and every layer stays replaceable.
Evaluate an OCR engine#
The first concrete instance: measure OCR accuracy over a gold corpus. ek consumes
ocracy’s normalized OcrResult, so it can
benchmark any of its ~16 engines — or any image -> OcrResult callable of your own.
import ek.ocr
gold = {
"inv-1": {
"image": "scan.png",
"reference_text": "INVOICE 2024",
"slice": "invoices",
}
}
report = ek.ocr.evaluate_ocr(
"ocrmac",
gold,
metric="cer",
normalize=["lower", "collapse_whitespace"],
persist=True,
)
report.aggregate # corpus CER
report.per_slice # CER per document slice
report.detail["per_item"] # prediction, reference, score, confidence per document
Gold corpora, results, and runs persist to local dol stores under
~/.local/share/ek/.
Evaluate an AI agent — in cost per successful task#
The second instance. Agent evaluation is the same 2×2, but the evaluated object is an episode (tool calls + observations ending in a final state) and the unit that matters is cost per successfully completed task, not cost per token — because tokens spent on a failed episode are pure waste.
from ek.agents import TaskSpec, run_suite, per_million
tasks = [
TaskSpec("t1", input="2+2", gold="4", slice="easy"),
TaskSpec("t2", input="17*23", gold="391", slice="hard"),
]
report = run_suite(my_agent, tasks, k=8, price=per_million(3.0, 15.0))
report.pass_hat_k # reliability: succeeds on ALL 8 trials (the production number)
report.pass_at_k # capability: succeeds on ANY of 8 trials
report.success_ci # a Wilson interval — a point estimate is not a result
report.cost[
"cost_per_success"
] # Cost-of-Pass: dollars per *successful* task (inf if none)
report.per_slice # ...cut by difficulty
Two numbers, not one: an agent that “usually works” is not shippable, and pass^k is what
exposes it (a 90%-reliable agent is only ~43% reliable across 8 tries). Agent scores are
stochastic, so the regression gate compares intervals, not points, and refuses to compare
runs whose user-simulator or suite version changed:
from ek.agents import agent_regression_gate, save_agent_baseline
save_agent_baseline(report, "v1")
assert agent_regression_gate(
new_report, "v1"
) # fails only on a *real* regression, not noise
Also included: BFCL-style tool-call correctness (cost-weighted by the tool grammar, so a wrong
argument to a destructive tool costs more), an order-sensitive trajectory distance, and an
LLM-as-judge signal — with judge_validation(), because an unvalidated judge is a liability, not
a metric. None of this needs an extra: ek.agents is pure-python, and the bridges duck-type,
so it scores an Inspect/DeepEval run without importing either.
Install#
pip install ek # lean, permissive core (dol, config2py, jiwer, rapidfuzz)
pip install "ek[ocr]" # + the ocracy OCR fleet (install engines via ocracy extras)
pip install "ek[agents]" # + external agent harnesses to *run* (inspect-ai, deepeval, ragas)
pip install "ek[all]" # + the permissive capability tiers (metrics, calibration, ...)
Heavier or copyleft/non-commercial libraries are never installed by default, and a CI license
gate enforces it; see the extras in pyproject.toml.
CLI#
ek cer "hello wrld" "hello world" # character error rate
ek wer "hello wrld" "hello world" # word error rate
ek pass-k 10 9 --k 8 # pass@k (capability) vs pass^k (reliability)
ek cost-per-success 12.50 5 # dollars per successfully completed task
ek where # the local data folder
ek check tesseract # what an OCR engine needs to run
For contributors#
The architecture, conventions, and the research behind the design are documented for
agents and humans in AGENTS.md, the dev skills under skills/, and
the research reports under misc/docs/.
This documentation as a single file: ek.md (Markdown, for agents).
built 2026-10-14 03:58 UTC from 3c8454e (main) · ek 0.1.11 · about this build