Index Ai Academy
Phase 10 · Agent harnesses · Scaling & shipping

Evaluation harnesses

Run agents on tasks in fresh environments and grade what they leave behind.

About 40 minutes · A free account opens the whole lesson

Create a free account Try part of it here

Already have an account? Sign in to open this lesson

Why it matters

You change the system prompt, add a tool, or switch models. Is the agent better? Trying a few tasks by hand can't tell you: agents vary from run to run, and a change that fixes one task can break three others. An evaluation harness runs the agent across a fixed set of tasks, many times, in clean environments, and grades what it leaves behind. It's how teams improve agents with evidence instead of hope.

What you'll be able to do

  • Design agent eval tasks with a setup, an instruction and a grader that checks the outcome
  • Run each trial in a fresh environment, several times per task
  • Report pass@k and pass^k, and estimate pass@k without bias
  • Catch reward hacking, such as an agent editing the tests to make them pass

What it covers

  1. Anatomy of an agent eval
  2. Run each task several times
  3. Estimating pass@k
  4. The tempting estimate is biased
  5. Reward hacking
  6. A hidden test catches a cheat
  7. Use it
  8. pass@k and pass^k from one success rate
  9. One run proves very little

Anatomy of an agent eval

Think of a driving test. Everyone takes the same route in a prepared car, and the examiner cares whether you parked safely, not which hand you used on the wheel. Each task has three parts:

  1. Setup: the starting state, such as a repository at a certain commit, some files, a database.
  2. Instruction: what the agent is asked to do, as a user would ask it.
  3. Grader: code that checks the outcome: do the hidden tests pass, does the file contain the right value, is the bug gone?

Benchmarks like SWE-bench work this way: a real repository, a real issue, and the project's own tests as the grader. Grade the outcome, not the path. Many different tool sequences can solve a task, and grading the exact steps punishes good solutions you didn't think of.

Graders, from most to least trusted

graderexamplenotes
coderun tests, compare files, query the databasefast, cheap, repeatable; use when you can
modela rubric scored by an LLM judgefor open-ended output; check it against human scores
humanexpert reviewthe gold standard, but slow; use to calibrate the others

Fresh environments

A chemist washes the glassware between experiments. Each trial gets a brand-new copy of the setup: a new container, a clean checkout. If trials share state, one trial's leftover files can make the next pass or fail for the wrong reason.

Quick check
Two trials share one folder. The first leaves a helper file behind, and the second passes only because of it. What went wrong?
  1. The task needed a larger number of trials
  2. The grader checked the steps instead of the outcome
  3. The trials didn't each get a fresh copy of the setup
Show the answer

The trials didn't each get a fresh copy of the setup

Each trial needs its own brand-new setup. Here, the second trial's pass says nothing about the agent, because leftovers from the first one did the work.

Run each task several times

One free throw tells you little about a basketball player. Agents are not deterministic either, so one run per task measures luck as much as skill. Run each task n times and report:

  • pass@k: the chance at least one of k tries succeeds. Fits tasks where a person can retry, or pick the best of several.
  • pass^k: the chance all k tries succeed. Measures reliability, which matters for agents that run unattended.

An agent with a 60% success rate has pass@3 near 94% but pass^3 near 22%. Same agent, very different stories.

In plain words: pass@k asks "will one of these tries work?" pass^k asks "will every try work?"

Try it now

When a person can retry, pass@k is what matters. An unattended agent needs pass^k, which falls fast.

Quick check
A support agent will run 10,000 times a day with no human checking. Which metric matters most?
  1. The length of its replies
  2. pass^k: how often it succeeds every time
  3. pass@k: whether it succeeds at least once in k tries
  4. How many tools it calls
Show the answer

pass^k: how often it succeeds every time

Unattended runs get one shot each. Reliability across runs is what users feel.

Estimating pass@k

Run n trials, and c pass. The tempting estimate of pass@k, 1 - (1 - c/n) ** k, is biased. Think of your trials as marbles in a bag, with the passing ones green. You pick k marbles, and you fail only if none of them is green. The standard estimator, from the HumanEval paper, counts the ways to pick k of the n trials that are all failures:

pass@k = 1 - C(n - c, k) / C(n, k)

where C is "choose" (math.comb). If fewer than k trials failed, it's 1.

Worked example

The tempting estimate is biased

Say 2 of 5 trials passed. Compare the tempting formula with the standard one from this section, for picking 3 tries.

from math import comb

n, c, k = 5, 2, 3

tempting = 1 - (1 - c / n) ** k
unbiased = 1 - comb(n - c, k) / comb(n, k)

print("tempting:", round(tempting, 3))
print("unbiased:", round(unbiased, 3))
It runs right here in your browser, with nothing to install.

The two disagree by 12 points on the same five runs, and that's without changing any model. So when you compare harnesses, make sure both reports used the same formula, or the winner may only be down to the arithmetic.

Reward hacking

Tell someone the floor only has to look clean, and the dirt may end up under the rug. Agents optimize for what the grader checks, sometimes in ways you didn't intend. Coding agents have been seen deleting failing tests, special-casing test inputs, or editing the grader. Defenses:

  • Keep grading tests hidden from the agent, or restore them before grading.
  • Mark some files protected; any change to them fails the trial.
  • Read transcripts of passing trials now and then, not only failing ones.
Worked example

A hidden test catches a cheat

An agent told to make the tests pass may special-case the inputs it can see. Hidden tests with different inputs tell you whether it solved the real problem.

def honest_add(a, b):
    return a + b

def cheating_add(a, b):
    if (a, b) == (2, 3):      # the one input in the visible test
        return 5
    return 0

visible = [((2, 3), 5)]
hidden = [((10, 4), 14), ((0, 0), 0), ((-1, 1), 0)]

def score(fn, tests):
    return sum(fn(*args) == want for args, want in tests), len(tests)

for fn in [honest_add, cheating_add]:
    print(fn.__name__, "visible:", score(fn, visible), "hidden:", score(fn, hidden))
In the lesson you can change this and run it.

Both look perfect on the visible test. Notice the cheat even passes two hidden cases by luck, because its answer of 0 happens to be right for them. So a thin hidden set can miss a cheat too, and graders need varied inputs.

Use it

Track cost and turns as well as success. A car that's 2% faster and burns twice the fuel may not be an upgrade, and a change that adds 2% success but doubles cost may not be worth it. Keep a small, fast suite that runs on every change to the harness, like unit tests, and a large one that runs before releases.

Quick check
Five trials, two passed. What's the unbiased pass@2? What does this print?
from math import comb

n, c, k = 5, 2, 2
print(round(1 - comb(n - c, k) / comb(n, k), 2))
  1. 0.64
  2. 0.4
  3. 1.0
  4. 0.7
Show the answer

0.7

There are 10 ways to pick 2 of 5 trials, and 3 of them pick only failures. So 1 − 3/10 = 0.7.

Worked example

pass@k and pass^k from one success rate

The same agent, measured two ways.

from math import comb

p = 0.6
for k in (1, 3, 5):
    print(f"k={k}: pass@k={1 - (1 - p) ** k:.2f}  pass^k={p ** k:.2f}")

n, c, k = 10, 6, 3
print("unbiased pass@3 from 6 of 10:", round(1 - comb(n - c, k) / comb(n, k), 3))
In the lesson you can change this and run it.

With trial counts, the unbiased estimate (0.967) differs from plugging 0.6 into the formula (0.936). The gap grows as n gets smaller.

Quick check
How do you catch an agent that passes by editing the tests?
  1. Protect or hide the tests, and fail any trial that changes them
  2. Ask the agent whether it cheated
  3. Run fewer trials
  4. Trust the pass rate
Show the answer

Protect or hide the tests, and fail any trial that changes them

Protected files and hidden tests close the shortcut. Reading some passing transcripts helps too.

One run proves very little

Agents vary from run to run. A task that passes once might pass 6 times in 10. So a single run can mislead you in either direction, and a jump from 60% to 80% on a few tasks may be nothing but noise. Run each task several times, and compare the runs with some statistics before you believe a change helped.

Grade the result, not the route

It's tempting to check that the agent took the steps you expected: read this file, then call that tool. But a good agent might solve the problem another way, and it would fail your check for being clever. Worse, an agent can take all the right steps and still leave a broken result. Check what's true at the end instead. Do the tests pass? Is the file correct? Is the record in the database?

Be suspicious of big jumps

A student who goes from a D to an A overnight deserves a second look. When a pass rate leaps overnight, look before you celebrate. Check whether the agent found a way to game the grader, or whether a task leaked its answer. Read a handful of transcripts from runs that now pass.

Pass rate isn't the whole story

Two versions with the same pass rate aren't equal if one takes 40 turns and $3 a task, and the other takes 8 turns and 40 cents. Report cost, turns and time beside the pass rate, so that a change that wins on one and loses badly on another doesn't slip through.

Practice what you just read

  • 3 code examples you can edit and run
  • a practice exercise that checks your code
  • a 5-question quiz
  • 5 review cards for spaced repetition

Create a free account

Try a quiz question

Why grade an agent's outcome rather than the exact sequence of tool calls?

  1. Many paths can solve a task, and grading steps punishes valid solutions
  2. Tool calls are secret, and can't be read back after a run has finished
  3. Outcomes are always easier to check, since each one is a single pass or fail
  4. Step grading is too fast, and misses what happens in between the tool calls

Answer it at the end of the lesson to see if you're right, and why.

Before this lesson