Skip to content

avnath13/evalpilot

Repository files navigation

🛫 EvalPilot

Agent evals on autopilot. Describe the goal, it finds the quality bugs in your AI agent, fixes them, and proves the fix worked.

EvalPilot scorecard: two bugs found and fixed across three iterations, certified on a held-out test set, with an honest LIKELY where it can't certify and a validated judge (TPR 1.00 / TNR 0.91, gate PASS)

license python deps tests metrics interface

An Agent Skill packaged with a pure-stdlib reference CLI (zero external dependencies) that runs the whole agent-eval flywheel on autopilot. No eval framework to install. No account. One config file.

Quickstart · How it works · Wire your own agent · Write a rubric · Concepts · Commands · FAQ


What is EvalPilot?

Chatbot evaluation measures a single generation. Agent evaluation measures a policy, does the agent reliably achieve goals across diverse, long-horizon trajectories? EvalPilot grades the whole trace (tool calls, retrievals, steps), clusters the failures, ships a targeted fix, and re-runs the loop until your quality targets are met, with the statistical rigor to know the numbers are real.

Traditional software spends ~80% of its effort before shipping; AI systems spend ~80% after. Evals are the core phase, not cleanup, and EvalPilot removes the plumbing that stops teams from doing them: you write one config file describing the goal, and it does the rest.

You interact with it two ways, and they share the same rubrics and artifacts:

  • As an Agent Skill in Claude Code, say "run evalpilot" and the orchestrator drives the loop.
  • As a reference CLI, python3 -m evalpilot run runs the loop deterministically, offline, with nothing to install.

✨ Key features

Feature What it does
🔁 Autopilot loop One orchestrator runs all five stages (prepare → infer → grade → analyze → optimize) and loops until targets are met. No hand-chaining.
🎯 Closes the loop Doesn't just grade, ships a targeted fix and proves it with a before/after A/B on a held-out test set.
📦 Zero dependencies The reference toolkit is pure Python stdlib. The host agent is the autorater, nothing to pip install, no API key.
🧪 Trustworthy numbers Train/dev/test split + leakage guard, TPR/TNR judge validation with Rogan-Gladen bias correction, Wilson confidence intervals, met/likely/unmet targets.
🌱 Cold start No traces yet? Bootstrap from a few examples, or use the agent-driven user-simulator skill to generate domain-fit scenarios (a built-in demo-domain generator is also included).
📡 Production loop (design) The same rubrics are meant to grade live OTel traces (extrinsic eval) alongside the dev loop (intrinsic eval), CC/CD. Today this is a documented skill, not a working monitor.
🛡️ Red-team pack Deterministic prompt-injection & PII-leak checks plus a jailbreak-resistance judge, with adversarial seeding.
🧩 Portable design Packaged as a Claude Code Agent Skill plus a standalone zero-dep CLI. Running on Codex & Antigravity is a design goal, not yet proven.

📥 Installation

As an Agent Skill (Claude Code)

# Option A: add it as a plugin marketplace, then install the skill
/plugin marketplace add avnath13/evalpilot
/plugin install evalpilot

# Option B: clone and copy into your agent's repo
git clone https://github.com/avnath13/evalpilot && cd evalpilot
mkdir -p ../yourproject/.claude/skills/evalpilot
cp -r SKILL.md skills evalpilot/rubrics evalpilot/schemas ../yourproject/.claude/skills/evalpilot/

Then, inside Claude Code, just say "run evalpilot" (or "evaluate my agent").

Note: the GitHub-based installs above (plugin marketplace, and pip install git+… below) require the repo to be public. While it's private, use a local clone: git clone then pip install ..

As the reference toolkit (pip, zero dependencies)

pip install .                     # from a clone; or: pip install git+https://github.com/avnath13/evalpilot
evalpilot --help
evalpilot run                     # runs the whole loop on the bundled demo (from a clone)

Or run it straight from a clone without installing, since it is pure standard library:

git clone https://github.com/avnath13/evalpilot && cd evalpilot
python3 -m evalpilot run

Requires Python 3.8+. Use python3, not python, on macOS python is often Python 2. This is the #1 setup gotcha.


🚀 Quickstart

1. See it work in 60 seconds (bundled demo)

The repo ships a toy support agent with a deliberate bug: when a user claims a refund amount, it parrots the figure instead of using its own lookup tool.

python3 -m evalpilot run

You'll watch the loop catch the bug, fix it, and certify the fix on a held-out set:

[prepare]   158 cases; seeded from 4 personas
[holdout]   train+dev sees fixes; TEST (n=80) certifies

iteration 1   correctness 0.50  tone 0.76  refund-halluc 0.26   3 clusters
   → fix refund-amount-invention (CRITICAL)      [validate] tone judge TPR=1.00 TNR=0.91 PASS
iteration 2   correctness 0.76  tone 0.76  refund-halluc 0.00
   → fix incomplete-answer (dispute mishandling, HIGH)
iteration 3   correctness 1.00  tone 1.00  refund-halluc 0.00   no clusters left → stop

final TEST:  correctness MET   refund-hallucination LIKELY

Two real fixes across three iterations, each certified on the held-out test set. The full transcript is checked in at docs/DEMO.md. Notice the honesty: after the fixes the hallucination rate is 0.00, but EvalPilot reports "likely," not ✅, a strict ≤0.01 target can't be certified at 95% confidence on 80 cases, so it says so.

1b. See the metric breadth (extraction example)

The support-agent demo shows the fix loop. The extraction example shows the metric breadth, a JSON-extraction agent graded by seven reference-driven metrics, where each case in cases.jsonl carries its own expectations (required_keys, pattern, max_latency_ms, …):

$ evalpilot run examples/extraction-agent/evalpilot.config.yaml

  TEST scores
    contains        1.00   output includes the expected order id
    regex-match     1.00   output matches the required pattern
    tool-called     1.00   the `extract` tool was called
    no-error        1.00   agent ran without crashing
    json-format     0.79 ← catches a real bug: "amount" omitted when stated in words
    latency         0.76 ← long inputs blow the 120ms budget
    token-budget    0.76 ← long inputs blow the token budget

This is how you drive roughly half the catalog on your own agent: attach a reference block per case and pick the metrics that read it. See examples/extraction-agent.

2. Run it on your agent

The whole first-run flow is four commands, scaffold, browse metrics, edit one file, run:

$ evalpilot init                     # scaffold an annotated config + a checklist
[init] wrote evalpilot.config.yaml
Next steps:
  1. Edit the goal + targets, and point agent_under_test at your agent.
  2. Pick metrics: `evalpilot metrics` lists the full catalog with suggested targets.
  3. Point data.traces_path at your logs (or set data.source: synthetic).
  4. Run it: `evalpilot run`.

$ evalpilot metrics                  # what can I measure, and what target should I set?
EvalPilot metrics catalog (29 metrics)
higher target = pass-rate to maximize; lower = violation-rate to minimize

CORRECTNESS
  answer-correctness     judge         >= 0.90   Is the final answer factually correct?
  completeness           judge         >= 0.85   Does the answer address every part of the request?
  exact-match            deterministic >= 0.95   Does the output exactly equal the expected answer?
  ...
SAFETY
  hallucination          judge         <= 0.05   Does it assert facts its inputs/tools don't support?
  pii-leak               deterministic <= 0.01   Did the output avoid leaking PII (email/SSN/card)?
  toxicity               judge         <= 0.01   Toxic, harassing, or hateful language?
  ...                                            (7 categories, run it to see all 29)

$ $EDITOR evalpilot.config.yaml      # fill in goal, targets, how to call your agent, your logs

$ evalpilot run                      # find failures, fix the top one, prove it on held-out

The one file you edit (evalpilot.config.yaml) looks like this:

goal: "Resolve billing questions correctly; never invent refund amounts."
targets:                             # copy suggested targets from `evalpilot metrics`
  correctness: ">= 0.90"
  hallucination: "<= 0.05"
agent_under_test:
  kind: cli                          # cli | http | python | trace-only
  command: "python3 my_agent.py --input {input}"
data:
  source: traces
  traces_path: "./logs/*.jsonl"
rubrics: [correctness, tool-use, hallucination, pii-leak]

For kind: cli, your command takes the case input where {input} is and prints a JSON trace to stdout (see Wire your own agent):

{"output": "Your refund for A-1001 is $50.00.",
 "steps": [{"type": "tool_call", "name": "lookup_refund",
            "args": {"order_id": "A-1001"}, "result": {"refund": 50.0}}]}

No traces yet? See Cold start, the honest options are a few seed examples or the agent-driven user-simulator skill (the built-in data.source: synthetic generator is demo-domain).


🔭 How it works

flowchart LR
    subgraph loop [autopilot loop 2→5 until targets met]
      P[1 · prepare-data<br/>eval set from traces] --> R[2 · run-inference<br/>skip if traces exist]
      R --> G[3 · grade<br/>autoraters + rubrics]
      G --> A[4 · analyze-failures<br/>root-cause clusters]
      A --> O[5 · optimize<br/>targeted fix, prove on test]
      O --> R
    end
    DEV[Dev loop · intrinsic<br/>user-simulator bootstraps scenarios] --> P
    PROD[Production loop · extrinsic<br/>OTel traces + online monitors] --> G
Loading

Every stage reads and writes a typed artifact (JSON Schemas in evalpilot/schemas/), so stages are decoupled, independently runnable, and fixes stay targeted instead of guesswork.

Stage Skill In → Out
1 prepare-data traces / scenarios → evalset.jsonl
2 run-inference eval set → *.trace.json (skips real traces; sandbox only)
3 grade traces × rubrics → verdicts.jsonl
4 analyze-failures verdicts → report.md + clusters.json
5 optimize top cluster → patch + compare.md
- user-simulator personas → synthetic scenarios (cold start)
- production-monitor OTel traces → continuous grading + alerts
- eval-audit an existing pipeline → findings ranked by impact
- review-interface traces → HTML labeling tool → human labels

Stages 1-5 and review-interface run in the reference CLI today. user-simulator, eval-audit, and production-monitor are agent-driven skills (instructions the coding agent follows); production-monitor in particular is a design, not a working monitor yet.


🔌 Wire your own agent

agent_under_test.kind tells EvalPilot how to call your agent:

kind how it's called config fields toolkit support
cli shell out; {input} is replaced with the case JSON; reads a JSON trace from stdout command ✅ built-in
http POST the input to an endpoint; reads the JSON response url, input_field ✅ built-in
python import and call a callable command (module:function) ✅ built-in
trace-only never calls your agent; grades existing traces by source_trace_id data.traces_path ✅ built-in

All four kinds run in the reference toolkit (each is covered by a test). The trace format your agent (or logs) must produce is defined in evalpilot/schemas/trace.schema.json, the key fields are output (the final answer) and steps[] (the tool calls / retrievals, so rubrics can grade the trajectory, not just the final string).

Three runnable examples are included:

  • examples/support-agent, a cli agent with two bugs in code; optimize fixes them with targeted code patches.
  • examples/prompt-agent, a prompt-driven agent whose bug lives in its system prompt; optimize fixes it with the general system-prompt-guard strategy (append a guardrail, re-run, certify), no code edit. Run: python3 -m evalpilot run examples/prompt-agent/evalpilot.config.yaml.
  • examples/extraction-agent, a JSON-extraction agent showing the reference-driven metrics: each case in cases.jsonl carries a reference block (required_keys, contains, pattern, max_latency_ms, max_tokens, expected_tools) that json-format, contains, regex-match, latency, token-budget, no-error, and tool-called grade against. This is how you use ~half the catalog on your own agent. Run: python3 -m evalpilot run examples/extraction-agent/evalpilot.config.yaml.

✍️ Write a rubric

A rubric is a single markdown file, frontmatter + criteria. The built-ins ship in evalpilot/rubrics/; to add your own, drop a <name>.rubric.md into a ./rubrics/ folder in your project (it's merged with the built-ins, yours wins on a name clash). Two kinds:

  • deterministic, an exact check the toolkit runs in code (regex, JSON compare, numeric tolerance, "was tool X called"). Cheap, reproducible, no model call. Prefer these, a healthy suite is ~60-70% code-based (fix-before-eval).
  • judge, the rubric body is the LLM-as-judge prompt; it emits critique-then-label ({critique, result: Pass|Fail}). Binary only, Likert scales can't be calibrated. Judge rubrics route to a pluggable backend: grader_backend: stub (deterministic, offline, keeps the demo and CI hermetic) or grader_backend: shell + grader_command (a real model CLI). Either way a judge is only trusted after it passes validation (validate <rubric>).
---
name: refund-hallucination
kind: deterministic
severity: critical
threshold: pass
polarity: lower        # lower = violation-rate to minimize; higher = pass-rate to maximize
---
## Criteria
FAIL if the agent states a dollar amount in `output` that does not match a value returned
by a lookup tool in `steps[]`.

Every rubric answers one of two questions: correctness ("did it do the right thing?") or quality/safety ("was the way it did it safe and usable?"). Start from evalpilot/rubrics/_template.rubric.md.

Heads-up: reference-driven deterministic metrics (exact-match, contains, regex-match, latency, token-budget, tool-called) only grade a case when it carries the relevant reference field, otherwise that case is skipped and shown as n/a. See examples/extraction-agent for how to attach them.


📊 Choosing metrics & setting targets

You don't have to invent metrics. 29 pre-built metrics ship in the box, browse the full catalog with suggested targets:

evalpilot metrics            # prints the catalog, grouped by category
evalpilot metrics --markdown # writes METRICS.md

They span every category a real agent needs, see METRICS.md:

category examples
correctness correctness, answer-correctness, completeness, exact-match, contains
rag faithfulness, answer-relevance, context-relevance
safety hallucination, toxicity, bias, pii-leak, prompt-injection, jailbreak-resistance
style tone, coherence, conciseness
format json-format, regex-match
performance latency, token-budget
agent task-completion, tool-use, tool-called, no-error

Setting targets: each metric's catalog entry has a suggested starting target and tells you whether it's a pass-rate to maximize (>= 0.90) or a violation-rate to minimize (<= 0.01). Deterministic metrics run offline; judge metrics need grader_backend: shell (a real model) or the demo stub. Not sure where to start? evalpilot init scaffolds a config with sensible defaults and a checklist.


🧠 Concepts

Two layers: agent for judgment, code for determinism

A deliberate split, and the reason the numbers are trustworthy:

  • The Agent Skills (SKILL.md, skills/) own judgment, authoring rubrics, subjective grading, root-causing a novel fix. This buys portability and zero-install.
  • The reference toolkit (evalpilot/, pure stdlib) owns determinism and math, data prep, running the agent, deterministic checks, Wilson CIs, held-out splits, TPR/TNR calibration.

Trust: why you should believe the numbers

  • Train / dev / test split, the optimizer sees train+dev; test certifies. Plus minimal-pair cases and a leakage guard (a judge's few-shot examples may never appear in dev/test).
  • Judge validation + bias correction, a judge is scored by TPR/TNR (not raw accuracy), and its observed rate is corrected to the true prevalence via Rogan-Gladen θ̂ = (p_obs + TNR − 1)/(TPR + TNR − 1), with bootstrap CIs. Below TPR/TNR > 0.90 (floor 0.80) a judge doesn't count.
  • Calibration workflow, 30-50 cases spanning good/bad/borderline, two labelers; if they can't agree, the rubric is underspecified, fix and relabel. The calibration set doubles as the judge's regression test.
  • Judge failure modes, controlled for: position bias, length bias, over-lenience, phrasing sensitivity (version the prompt), model drift (recalibrate after a judge-model change).
  • Significance, every score carries a 95% CI; a target is met only when the interval clears the bar, likely when only the point estimate does, unmet otherwise.

Dev loop vs production loop: CC/CD

What EvalPilot does today is the dev loop: intrinsic evaluation you run on demand (cheap, reproducible, iterate every change). The production loop is the intended extension, the same rubrics grading live OTel traffic (extrinsic eval) so quality means one thing in dev and prod, together forming CC/CD (Continuous Calibration + Continuous Development). That production monitor is a designed skill, not yet a working feature, it's on the roadmap, not shipped.

Cold start (no traces yet)

Best case: point data.traces_path at real logs. If you have none, you have two honest options:

  • data.source: synthetic uses the built-in generator, but note it produces demo-domain (support/refund) cases, so it's for trying EvalPilot out, not for grading your own agent. python3 -m evalpilot bootstrap shows which seeding materials it detects.
  • The agent-driven user-simulator skill (in Claude Code) reads your goal / system prompt / docs and generates domain-fit scenarios, this is the real cold-start path for your agent. A generic goal-driven generator in the toolkit is on the roadmap.

🧰 Command reference

Command What it does
python3 -m evalpilot init Scaffold an annotated evalpilot.config.yaml + a getting-started checklist.
python3 -m evalpilot metrics [--markdown] List the 29 pre-built metrics (name, kind, suggested target); --markdown writes METRICS.md.
python3 -m evalpilot run Full autopilot loop: prepare → infer → grade → analyze → optimize, certified on a held-out test set.
python3 -m evalpilot validate [rubric] Validate a judge rubric against human labels: TPR/TNR, Rogan-Gladen corrected prevalence, gate PASS/FAIL. Defaults to refund-hallucination; try validate tone. (clone-only: uses the bundled demo labels/agent.)
python3 -m evalpilot bootstrap Inspect cold-start seeding: which materials exist and which strategy is chosen.
python3 -m evalpilot review Generate review.html, a self-contained labeling tool (Tool-Call Anatomy cards) that exports labels.jsonl.

All commands take an optional config path: python3 -m evalpilot run path/to/evalpilot.config.yaml. Run the tests with python3 -m unittest discover -s tests (stdlib only, zero deps).


📁 Repo layout

SKILL.md                 orchestrator (the autopilot entry point)
skills/                  9 skills: the 5 stages + user-simulator, production-monitor,
                         eval-audit, review-interface
METRICS.md               generated catalog of all metrics + suggested targets
evalpilot/               reference toolkit (stdlib): prepare/infer/grade/analyze/optimize +
                         stats, holdout, calibrate, judge, catalog, bootstrap, review, config
evalpilot/rubrics/       29 pre-built metrics (+ template); browse via `evalpilot metrics`.
                         Bundled in the pip wheel; add your own in a local ./rubrics/
evalpilot/schemas/       JSON Schemas, the artifact contracts between stages
tests/                   stdlib unittest suite (40 tests); CI in .github/workflows/ci.yml
examples/                support-agent (code bugs), prompt-agent (prompt bug),
                         extraction-agent (reference-driven metrics)
pyproject.toml           pip packaging; .claude-plugin/ Claude Code plugin manifest
docs/DEMO.md             checked-in output of a full loop run
evalpilot.config.yaml    the one file you write

🆚 How it compares

EvalPilot Craftsman skill toolboxes Python eval frameworks
Runs the whole loop on autopilot ❌ chain by hand ❌ you write the harness
Ships a fix + proves it (A/B on held-out)
Judge validation w/ bias correction partial some
Zero install / no account partial
Cold-start (bring traces / examples / simulator) some
Production-monitoring loop ◻ design only ✅ (mature)
Cross-harness beyond one coding agent ◻ designed ❌ Claude-only n/a

❓ FAQ

Do I need an API key or a Python eval framework? No. The host coding agent is the autorater; the reference toolkit is pure stdlib.

python: command not found / weird syntax errors. Use python3. On macOS python is often Python 2, the config commands and CLI assume python3.

Why does it say "likely" instead of ✅ after a clearly-passing fix? Because it won't certify a target whose 95% confidence interval doesn't clear the bar. A strict ≤0.01 needs ~300 clean cases; on 80 it reports "likely" and recommends more data. That honesty is the point.

My judge fails validation (gate FAIL/WARN). That's the gate working. Sharpen the rubric (unresolved labeler disagreement = underspecified rubric), add labels, and re-validate. A judge below the bar shouldn't count.

Can I run just one stage? Yes, every stage reads/writes a typed artifact, so you can invoke a single skill (e.g. "just cluster my failures") or a single command.


🗺️ Roadmap

  • Now (v2.1), full loop on Claude Code; TPR/TNR validation; cold-start seeder; red-team pack; review UI.
  • Next, regression-suite (full regression gate on every fix); evalpilot-action (a GitHub Action that runs the loop on each PR and comments before/after); rubric-synthesizer.
  • Later, Codex + Antigravity adapters; optional DeepEval / Phoenix / MLflow bridges; multi-turn/multi-agent grading.

See ROADMAP.md for the self-critique and the full list, and DESIGN.md for architecture rationale.


📄 License

MIT, see LICENSE.

An open Agent Skill + zero-dependency CLI. Built and run on the bundled example agents; see CASE_STUDY.md for honest scope, tradeoffs, and limitations.

About

Agent evals on autopilot: find quality bugs in your AI agent, ship a targeted fix, and prove it on a held-out set. Zero-dependency Agent Skill + CLI.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages