# Evaluation and Production

Course: [AI Agents](https://www.devtutorials.ai/learn/ai-agents) · Section: Agent Evaluation
Source: https://www.devtutorials.ai/learn/ai-agents/evaluation/evaluation-and-production

> How to measure an agent with a fixed benchmark and four core metrics, audit failing traces, monitor it in production, and prove that tuning helped.

Think about a driving test.

An examiner does not ask you to explain how to drive. Instead, they give every driver the same tasks: start the car, turn, park, and stop at a red light.

Each task has a clear pass or fail result. At the end, you receive a score and a list showing exactly where you lost points.

Passing the test is only the beginning. Real drivers also maintain their cars. A dashboard shows fuel level, engine temperature, and warning lights so problems can be spotted early.

An AI agent needs both. It needs a fair test before it can be trusted, and it needs monitoring after it is deployed.

**The main idea:** evaluate an agent using a fixed set of tasks, each with its own checker. Measure a small set of clear metrics, examine the traces from failed runs, improve the agent, and then run the same tasks again. In production, continue monitoring the same metrics.

## A Real-World Example

You have two versions of the Brightgrid bug-fixing agent:

- **Baseline:** the scripted agent from Chapter 1.
- **Tuned:** the same agent with retries and fallbacks from Lesson 15.

Which one is better? Opinions do not matter.

You run both agents on the same 10 development tasks. Each task has its own checker that determines whether the result passes or fails.

| | Baseline | Tuned |
|---|---|---|
| Tasks passed | 6 of 10 | 10 of 10 |

The baseline agent fails all 4 tasks that involve an empty test result or a timeout. By reading the traces from those 4 failed runs, you can see exactly what went wrong. That information tells you what needs to be improved.

**In simple words:** Use the same tasks, the same checkers, and clear measurements. Then study the failures.

## What You Will Learn

In this lesson, you will learn:

1. What public agent benchmarks measure.
2. Four core metrics: tool success, decision accuracy, plan completion, and recovery rate.
3. How to audit a trace to understand why a run failed.
4. What to monitor in production: steps, tokens, latency, and overall health.
5. How to tune prompts and tools, and prove that the tuning improved the results.

The new **Eval** tab in the Agent Lab runs a small benchmark of 10 development tasks in your browser. Start with **Run baseline**, identify the rows that failed, then run **Run tuned** and compare the results.

## Agent Benchmarks

A **benchmark** is a fixed set of tasks with an automatic checker for each task. Three well-known public benchmarks are:

- **SWE-bench** gives agents real issues from open-source Python projects. The agent must modify the code so that the project's own tests pass. It measures real software engineering work.
- **GAIA** asks general-assistant questions that require multiple steps, such as reading files, searching for information, and reasoning. Each question has one correct answer, making evaluation precise.
- **AgentBench** evaluates a model acting as an agent across several environments, such as an operating system, a database, and a web shop.

You can learn more from:

- [SWE-bench](https://www.swebench.com)
- [GAIA paper](https://arxiv.org/abs/2311.12983)
- [AgentBench repository](https://github.com/THUDM/AgentBench)

These benchmarks require real servers, large models, and significant computing resources, so they are not run in this course. Instead, the Eval tab uses a smaller benchmark built in the same way: a set of tasks, an environment (the Brightgrid project), and a checker for each task.

```js runnable title="A benchmark task is: setup, goal, checker"
const tasks = [
  { id: "b1", setup: "bug A", check: (r) => r.stop === "final" && r.testsPass === true },
  { id: "b10", setup: "fix is outside web/", check: (r) => r.stop === "final" && r.testsPass === false && r.blocked },
];
const results = {
  b1: { stop: "final", testsPass: true, blocked: false },
  b10: { stop: "final", testsPass: false, blocked: true },
};

for (const t of tasks) console.log(t.id + " (" + t.setup + "): " + (t.check(results[t.id]) ? "pass" : "FAIL"));
```

Expected output:

```text
b1 (bug A): pass
b10 (fix is outside web/): pass
```

Task b10 passes even though the tests still fail. In that case, the **correct** behavior is to stop at the boundary and ask for help. A good checker measures whether the agent behaved correctly, not just whether the tests passed.

## Core Metrics

Four numbers tell you most of what you need to know about an agent:

- **Tool success:** the percentage of tool calls that succeeded and returned a usable result.
- **Decision accuracy:** the percentage of tasks where the agent chose the correct action according to the checker.
- **Plan completion:** the percentage of tasks where the agent completed its entire plan, from the first action to a verified result.
- **Recovery rate:** the percentage of tasks with a fault that still ended in a successful outcome.

```js runnable title="Compute the four metrics from run results"
const runs = [
  { passed: true, toolCalls: 4, toolOk: 4, verified: true, fault: false },
  { passed: true, toolCalls: 5, toolOk: 4, verified: true, fault: true },
  { passed: false, toolCalls: 2, toolOk: 1, verified: false, fault: true },
  { passed: false, toolCalls: 1, toolOk: 0, verified: false, fault: true },
];
const pct = (a, b) => Math.round((a / b) * 100) + "%";
const sum = (f) => runs.reduce((a, r) => a + f(r), 0);
const faulty = runs.filter((r) => r.fault);

console.log("tool success: " + pct(sum((r) => r.toolOk), sum((r) => r.toolCalls)));
console.log("decision accuracy: " + pct(runs.filter((r) => r.passed).length, runs.length));
console.log("plan completion: " + pct(runs.filter((r) => r.verified).length, runs.length));
console.log("recovery rate: " + pct(faulty.filter((r) => r.passed).length, faulty.length));
```

Expected output:

```text
tool success: 75%
decision accuracy: 50%
plan completion: 50%
recovery rate: 33%
```

Each metric points to a different area. Low tool success usually points to problems with tools or inputs. Low recovery rate points to weak error handling. Low plan completion often means the agent stops before verifying its work.

On the real benchmark, the baseline agent scores: decision accuracy 60%, tool success 79%, plan completion 50%, and recovery rate 33%. The tuned agent scores 100%, 84%, 90%, and 100%. Plan completion stays below 100% for a good reason: task b10 should stop before writing.

## Trace Audits

A **trace audit** means reading the complete trace of a failed run step by step to find the first step that went wrong. You have been using this approach since Lesson 9.

```js runnable title="Find the first bad step in a trace"
const trace = [
  { n: 1, tool: "run_tests", result: "" },
  { n: 2, tool: "read_file", result: "function formatRows(n) { ... }" },
  { n: 3, final: "I could not fix it. Here is what I found: " },
];

function audit(trace) {
  for (const s of trace) {
    if (s.tool === "run_tests" && !/passed/.test(s.result)) return "step " + s.n + ": the test result was empty, but the agent carried on as if it were real";
    if (s.final && /could not/.test(s.final)) return "step " + s.n + ": the agent gave up";
  }
  return "no problem found";
}

console.log(audit(trace));
```

Expected output:

```text
step 1: the test result was empty, but the agent carried on as if it were real
```

The final answer says "I could not fix it", but that is only where the failure appeared. The first incorrect step is step 1.

The empty result should have been retried. The correct fix is to add output validation and retries, as you learned in Lessons 11 and 15.

## Production Monitoring

Once an agent is running in production, keep a **dashboard** of the same types of metrics for every run. This is called **telemetry**.

### Telemetry

- **Steps** per run: an increase can indicate that the agent is wandering or becoming less efficient.
- **Tokens** per run: this directly affects cost.
- **Latency**: the total time a run takes from start to finish.
- **Health**: the percentage of runs that complete successfully.

### Failure Analysis

Group failures into categories that can be acted on:

- **Stalls:** runs that stop because they hit a step limit or a progress check.
- **Failures:** runs where the checker reports a fail result.
- **Timeouts:** tool calls that take too long to complete.

```js runnable title="A small health dashboard"
const runs = [
  { steps: 5, tokens: 1800, ms: 7900, stop: "final", ok: true },
  { steps: 6, tokens: 2400, ms: 14900, stop: "final", ok: true, timeouts: 1 },
  { steps: 12, tokens: 6100, ms: 19000, stop: "max-steps", ok: false },
  { steps: 4, tokens: 1500, ms: 5900, stop: "final", ok: true },
];
const avg = (f) => Math.round(runs.reduce((a, r) => a + f(r), 0) / runs.length);

console.log("avg steps " + avg((r) => r.steps) + ", avg tokens " + avg((r) => r.tokens) + ", avg latency " + (avg((r) => r.ms) / 1000).toFixed(1) + " s");
console.log("health " + Math.round((runs.filter((r) => r.ok).length / runs.length) * 100) + "%");
console.log("stalls " + runs.filter((r) => r.stop === "max-steps").length + ", failures " + runs.filter((r) => !r.ok).length + ", timeouts " + runs.reduce((a, r) => a + (r.timeouts ?? 0), 0));
```

Expected output:

```text
avg steps 7, avg tokens 2950, avg latency 11.9 s
health 75%
stalls 1, failures 1, timeouts 1
```

One stalled run can increase every average. In a real dashboard, you would select that run and audit its trace to understand what happened.

## Optimization

### Prompt Tuning

**Prompt tuning** means improving the agent's instructions. Examples include adding a clearer stop rule, adding a rule such as "an empty test result is a fault, retry it", or improving tool descriptions.

Make only one change at a time so you can clearly see which change improved the results.

```js runnable title="One prompt change, measured"
const tasks = ["normal", "normal", "empty output", "timeout", "normal", "empty output"];

function agent(rules) {
  return tasks.map((t) => {
    if (t === "normal") return true;
    if (t === "empty output") return rules.includes("an empty test result is a fault: retry it");
    if (t === "timeout") return rules.includes("retry timeouts up to 2 times");
  });
}

const score = (rules) => agent(rules).filter(Boolean).length + " of " + tasks.length;
console.log("before: " + score([]));
console.log("+ empty-result rule: " + score(["an empty test result is a fault: retry it"]));
console.log("+ timeout rule too: " + score(["an empty test result is a fault: retry it", "retry timeouts up to 2 times"]));
```

Expected output:

```text
before: 3 of 6
+ empty-result rule: 5 of 6
+ timeout rule too: 6 of 6
```

Adding one rule at a time shows exactly what each change contributes.

### Tool Tuning

**Tool tuning** means improving the tools themselves. Examples include clearer error messages, output validation, and timeouts. Often, fixing a problem in the tool is the most efficient approach because every agent using that tool benefits from the improvement.

### Prove It

After every change, run the **same** benchmark again. A change only counts as an improvement if the numbers increase and nothing that previously passed now fails.

Press **Run baseline**: 6 out of 10 tasks pass. The 4 failures are the empty-output and timeout tasks. Then press **Run tuned**: 10 out of 10 tasks pass.

The tuned agent uses more steps and tokens on average (6 steps instead of 4.3) because retries have a cost. That trade-off is important and should be documented.

**Easy Way to Remember:** **same tasks, same checkers, one change, run again.**

Don't tune an agent on the same tasks that you use to measure it and then report those results as if they were independent. Keep some tasks separate and never tune on them. Use those tasks to verify that the agent actually improved instead of simply learning the test.

## From Lab to Production

Everything in the Agent Lab has a real-world equivalent. This table shows how the Lab concepts map to real coding agents such as Claude Code, Cursor, or GitHub Copilot agent mode, along with the most common trap for each.

| In the Agent Lab | In real coding agents | The common trap |
|---|---|---|
| Scripted brain, same steps every run | A large model chooses every step. Results can differ between runs. | Trusting a single successful demo. Run the same task multiple times. |
| A project with around 10 small files | Thousands of files. Finding the correct code is often the hardest part. | Letting the agent edit before it has searched and read enough context. |
| Tool registry and schemas (Lessons 3 and 11) | Built-in tools plus MCP servers, each with a name, description, and input schema. | Vague tool descriptions that cause the model to pick the wrong tool. |
| `run_tests` in a sandbox | A real shell running a real test suite, often slow or flaky and requiring setup. | Treating flaky test failures as real failures and "fixing" code that already works. |
| Folder boundaries and read-only mode (Lessons 1 and 11) | Sandbox settings, allowed and denied commands, and read-only planning modes. | Allowing unrestricted access "just this once" and never restoring restrictions. |
| `request_approval` (Lesson 24) | Permission prompts before edits, commands, or network access. | Approving actions without reading what the agent is about to do. |
| Stop rules and budgets (Lesson 10) | Session limits for turns, tokens, and cost. | Having no limits, allowing a stuck run to spend resources indefinitely. |
| Working memory (Lesson 13) | Context compaction, summaries, and project notes that are reloaded each session. | Filling the context window with old logs until the agent forgets the goal. |
| Snapshot and restore (Lesson 14) | Git commits, branches, and checkpoints that can be rolled back. | Making large changes without a commit, making recovery difficult. |
| Loop guards (Lesson 16) | Turn limits, repeated-call detection, and command timeouts. | Watching the agent repeat the same failing command for a long time. |
| Planning agent (Lesson 17) | Plan mode, where the agent proposes a plan and a person approves it before edits begin. | Skipping planning for a "small" change that turns out to be large. |
| Review agent rules (Lesson 21) | Review agents and CI checks with written rules, plus human review. | Treating "the agent approved it" as proof that it is safe. |
| Agent team (Lesson 23) | Usually one main agent with helper subagents and human review between phases. | Long unattended automation chains with no review in the middle. |
| Injection filter (Lesson 24) | Treating web pages, issues, and files as untrusted, using sandboxes and network restrictions. | Relying only on a filter. New attack patterns can bypass fixed rules. |
| Mini-benchmark (Lesson 25) | A task suite run in CI whenever prompts, tools, or models change. | Measuring performance only on the tasks used for tuning. |

Three habits carry over unchanged:

- **Give the agent a check it can run** (tests, linters, contract checks).
- **Give it only the permissions it needs for the task.**
- **Read the trace when something goes wrong.**

The Agent Lab makes every step visible and repeatable so you can learn the patterns. Real agents follow the same patterns, but each step is less predictable. That is why checks and guardrails matter even more in real systems.

## Common Mistakes

| Mistake | Wrong Idea | Correct Idea | What Goes Wrong |
|---|---|---|---|
| Demo-driven evaluation | "It worked when I tried it." | Use a fixed benchmark with checkers. | Rare failures remain hidden until users encounter them. |
| One metric only | "Accuracy is all that matters." | Measure four core metrics and cost. | A slow and expensive agent can appear better than it really is. |
| Fixing the last step | "It gave up, so fix the final step." | Find the first incorrect step in the trace. | The real cause remains unchanged. |
| Many changes at once | "Let's fix everything together." | Make one change and re-run the benchmark. | You cannot tell which change helped or caused problems. |
| Testing only on tuning tasks | "The score improved!" | Keep separate held-out tasks for evaluation. | The agent learns the test instead of actually improving. |

## Exercises

Each exercise ends with a value on the last line. Press **Check** to compare it with the expected answer.

## What to Remember

- Same tasks, same checkers, one change, run again.
- Public benchmarks such as **SWE-bench**, **GAIA**, and **AgentBench** all use the same basic idea: a fixed set of tasks paired with automatic checkers.
- The four core metrics are **tool success**, **decision accuracy**, **plan completion**, and **recovery rate**.
- When a run fails, audit the trace and find the **first bad step**, not just the final failure.
- In production, monitor **steps**, **tokens**, **latency**, and **health**, and group problems into **stalls**, **failures**, and **timeouts**.

Next: **AI Agents Cheat Sheet**, everything from this course on one page.
