Harness engineeringLesson 08

Evals and Traces

Outcome evals tell you whether the task worked. Trajectory evals tell you how. Learn to instrument both without drowning in logs or fooling yourself with a judge.

Advanced26 min readUpdated November 2026Compare two runs in the trace →

Evals and Traces

A harness that feels better is not evidence. A benchmark that went up is not evidence either, unless you know what it measured, on which tasks, with which graders and how much noise. Evals are how harness engineering becomes a science instead of a sequence of opinions.

Two questions, two evals

Every agent run answers two different questions:

  • Outcome: Did the task reach the desired end state? Tests pass, JSON validates, the ticket is correct, the patch applies.
  • Trajectory: How did it get there? Which tools, how many steps, what context, which approvals, which retries, which risks?

You need both. A correct answer from a dangerous path is a latent incident. A failed answer with a great trajectory is still a failure. Optimizing only the outcome rewards luck; optimizing only the trajectory rewards process theater.

Figure 8.1Event trace
A trace is a timeline of spansA single agent task contains model calls, tool calls, an approval wait, a compaction event, a retry and a final verification. Spans record duration, tokens and parent-child relationships so a failure can be located rather than guessed.The final answer is the least useful part of the traceONE TASK · SPANS ACROSS MODEL, TOOLS AND HUMAN POLICYMODELTOOLSPOLICYplanchoose toolsummarizeretryverifyread testread srceditre-readrun testsaskcompactWHAT A SPAN SHOULD RECORDname, parent, start, duration, statusmodel, tokens in / out, cost, tool argsretry reason, approval decision, error classFAILURES THE TRACE EXPOSESthe edit failed because compaction dropped a constraintthe retry passed, but only after re-reading the same filethe final answer was right, but the path was unsafeEVALS NEED MORE THAN OUTCOMESOutcome eval asks “did it work?” · trajectory eval asks “how did it work?”Pair both. A correct answer from a dangerous path is a latent incident, not a pass.Instrument at the harness boundary. The model provider cannot see your tool calls, approvals or compaction policy.
A trace records spans across model, tools, policy and human approval. The final answer is the least informative part of the run.

What a span should record

A span is a timed operation with a parent. For agent systems, the minimum useful set is:

FieldWhy
trace_id, span_id, parent_idreconstruct the tree
name, kindmodel, tool, approval, compaction, retry
start, duration, statuslatency and outcome
model, input_tokens, output_tokens, costeconomics
tool, args, result, error_classdebugging
policy_decision, approvalsafety audit
task_id, tenant, sessionattribution
context_tokens, compactioncontext health

Do not log raw prompts and outputs by default. They contain secrets, personal data and customer content. Use redaction at write time, field-level access controls and retention limits. A trace store is a production database with a privacy budget.

Building an eval set

Start with real tasks, not synthetic puzzles. A good eval set has:

  • Representative distribution. The same mix of simple, ambiguous and long tasks your users actually bring.
  • A defined environment. Repo snapshot, fixtures, tool versions, model versions, seeds.
  • Acceptance criteria. A deterministic check where possible; a rubric where not.
  • Held-out cases. Tasks not used while tuning prompts or tools.
  • Failure cases. Regressions from real incidents, with the exact trace.
  • A cost and latency profile. A harness that is correct but 10× slower may be unusable.

For coding tasks, the outcome check is often a test suite plus a diff review. For research tasks, it may be citation coverage and factual checks. For operational tasks, it is the final system state.

A small, well-chosen set of 30–100 tasks is more useful than a giant noisy benchmark. You will run it constantly, inspect failures and trust the result.

Graders

Three families:

Deterministic. Tests, schema validation, diff checks, exit codes, exact match. Cheap, reproducible, and the default whenever possible.

Rubric / human. A structured checklist scored by a person or a carefully prompted judge. Useful for style, completeness and judgment. Expensive and subjective.

LLM judge. A model scores an output against criteria. Convenient, but it has biases: verbosity, position, self-preference and agreement with confident prose. Treat it as a measurement instrument that needs calibration.

If you use a judge:

  • Give it the rubric, the evidence and the reference answer where available.
  • Ask for a structured verdict with a reason, not a 1–10 vibe score.
  • Randomize answer order for pairwise comparisons.
  • Calibrate against human labels on a sample.
  • Track judge–human agreement, not just judge scores.
  • Re-run the judge when the judge model changes.

A judge that agrees with humans 70% of the time is a noisy signal. That can be useful for triage; it is not a finish line.

Statistics without a statistics degree

Eval results are samples. If 18 of 30 tasks pass, the point estimate is 60%, but the uncertainty is wide. A rough 95% confidence interval for a proportion is

p^±1.96p^(1−p^)n.\hat{p} \pm 1.96\sqrt{\frac{\hat{p}(1-\hat{p})}{n}}.

For p^=0.6\hat{p}=0.6 and n=30n=30, that is about 0.6±0.1750.6 \pm 0.175 — roughly 43% to 78%. A “5-point improvement” on 30 tasks is noise. Either use more tasks, pair the comparison on the same tasks, or report the interval and stop over-claiming.

For paired comparisons, look at the discordant pairs: tasks where A passed and B failed, versus B passed and A failed. A simple sign test or bootstrap on the difference is more informative than comparing two independent percentages.

Also watch for contamination. If the eval tasks, solutions or tests appeared in training data, the score may measure memorization. Keep a private holdout and rotate it.

Trajectory metrics

Outcome alone hides the cost of success. Useful trajectory metrics:

  • Steps to completion and steps wasted on retries.
  • Tool error rate by tool and error class.
  • Context utilization and compactions per task.
  • Approvals per task and time waiting for humans.
  • Risk events: unapproved writes, network calls, secret access attempts.
  • Cost per completed task, including retries and failed runs.
  • Trace completeness: percentage of spans with required fields.

A harness change might improve success from 70% to 75% while doubling cost and approvals. Is that better? Only if the product says so.

Reading a trace

A practical debugging sequence:

  1. Find the first divergence. Where did the run stop matching the intended path? Not the last error — the first wrong turn.
  2. Check the context at that moment. Was the relevant constraint present? Had compaction removed it?
  3. Check the tool result. Did the tool return what the agent thought it did?
  4. Check the policy. Was the action allowed, denied or approved? By whom?
  5. Check the model step. Was the output malformed, or did the harness misparse it?
  6. Check the budget. Did a timeout or step limit truncate the work?
  7. Compare with a passing run. What was different in context, tools or state?

The trace should let you answer these without re-running the task. If it cannot, the instrumentation is incomplete.

Offline, online and canary evals

  • Offline evals run on a fixed dataset before deployment. They catch regressions and compare harness versions.
  • Online evals sample real traffic and score outcomes or judge quality. They catch distribution shift.
  • Canary evals route a small percentage of traffic to a new harness and compare against a control.
  • Shadow evals run the new harness on copies of real requests without serving the result. Useful but expensive.

No single layer is enough. Offline evals are reproducible but stale. Online evals are real but noisy and privacy-sensitive. Canaries are real and controlled but slow. Combine them.

A minimal eval harness

interface EvalCase {
  id: string;
  task: string;
  fixture: string;
  acceptance: (world: World) => Promise<Check>;
}

interface Check {
  pass: boolean;
  evidence: string;
  details?: unknown;
}

async function runCase(c: EvalCase, harness: Harness) {
  const run = await harness.run({ task: c.task, fixture: c.fixture });
  const check = await c.acceptance(run.world);
  return {
    id: c.id,
    pass: check.pass,
    evidence: check.evidence,
    trace: run.traceId,
    steps: run.steps,
    costUsd: run.costUsd,
    durationMs: run.durationMs,
    riskEvents: run.riskEvents,
  };
}

Run it on every harness change. Store the trace IDs with the results. When a case fails, the first question is “what changed in the trace?”, not “which prompt should we tweak?”

Privacy and retention

Traces are useful because they are detailed, which makes them sensitive. Decide:

  • What is redacted at write time (secrets, tokens, PII).
  • Who can read raw prompts versus aggregates.
  • How long traces are retained.
  • Whether traces can leave the region.
  • How a user can request deletion.
  • Whether eval datasets can be derived from customer data.

“We log everything for debugging” is a policy decision with legal and security consequences. Write it down.

Next: cost and routing — why the cheapest token may be the most expensive completed task.

Sources and further reading

One question before you go

retrieval check
What is a trajectory eval?
Why: Trajectory evals catch wasteful, unsafe or brittle paths that a lucky final answer would hide.
Type at least two characters. Search is indexed after the production build.
Lessons · labs · glossary↑↓ to browse · esc to close