Agent Testing

science

Testing a Non-Deterministic System

Conventional tests assert that an input produces an output. An agent given the same input twice will produce two different outputs, both of which may be correct. Agent testing therefore asserts on properties rather than strings: that a disclosure was made, that a tool was called with the right identifier, that the conversation reached a resolution within a budget. The hard part is not running the tests but writing criteria that stay meaningful as the wording moves underneath them.

category

Four Test Shapes

They differ in how much of the conversation is real, how much is fixture, and what the assertion is allowed to touch.

reply
Next-ReplyThe unit test

The conversation history is written by hand up to a chosen point, the agent produces one further turn, and the assertion applies to that turn only. The starting state is a fixture, identical on every run.

Asserts onOne generated turn
CatchesA wrong decision at a known state
forum
SimulationThe integration test

A scripted persona converses with the agent from the opening turn, bounded by a turn limit, with tools usually mocked. The assertion is on the outcome and optionally on the path taken to reach it.

Asserts onA whole conversation
CatchesLoops, dead ends, and states never reached
build
Tool CallThe contract test

Checks which tool was selected and with what arguments, independent of the surrounding language. The only agent assertion that is fully deterministic once the call has been made.

Asserts onSelection and arguments
CatchesWrong tool, wrong parameters, wrong extraction
move_to_inbox
ReplayThe regression test

A real conversation captured from production, converted into a fixture, and re-run against each change. The suite grows from incidents rather than imagination.

Asserts onBehaviour on cases that really occurred
CatchesRegressions on problems already solved once
compare_arrows

Next-Reply Against Simulation

These two look like variations of one another and behave like unit tests and integration tests. A next-reply test hand-authors the conversation history up to a chosen point, lets the agent produce exactly one more turn, and asserts on that turn alone. A simulation starts from nothing, drives a scripted persona through a whole conversation under a turn limit, and asserts on the outcome.

DimensionNext-ReplySimulation
Starting stateHand-written history, identical every runEmpty, reached by driving the conversation
What runsExactly one agent turnMany turns, bounded by a limit
AssertionOn the single reply producedOn the outcome, and optionally the path
VarianceLow. Only one generation differsHigh. Every turn compounds the last
Cost per runOne generation plus a judgeTwo agents talking for the length of the limit
CatchesA wrong decision at a known stateNever reaching the state, loops, dead ends
MissesWhether the state is reachable at allRare branches the persona never triggers
DebuggingImmediate. One turn to inspectArchaeology across a whole transcript

Next-reply earns its place through reachability. Asserting on behaviour at turn forty otherwise means driving thirty-nine probabilistic turns to arrive there, and the path differs every run. Writing the history directly pins the starting state so the test is about one decision rather than everything that led to it. Simulation then covers what pinning cannot: whether the agent reaches that state at all, and what it costs in turns.

Both rest on the same primitive, which is authoring the context window by hand rather than generating into it. That is the identical mechanism behind injecting a scripted utterance as an assistant turn, described in Deterministic Conversation.

rule

Writing Criteria

A judge evaluating whether a response met a criterion is itself a model, with all the variance that implies. Criteria written as observable facts hold up; criteria written as impressions drift with every model change.

FragileThe agent is helpful and professional
DurableThe agent states the call is recorded before asking any question

Helpfulness is an impression a judge scores differently across model versions. A stated fact before a stated event is checkable.

FragileThe agent handles the objection well
DurableThe agent acknowledges the objection and does not repeat the original offer

Well is doing all the work in the first version. The second names the behaviour that distinguishes good from bad.

FragileThe agent collects the right information
DurableThe agent obtains a postcode and a date of birth before offering a quote

Naming the fields and the ordering turns a judgement call into an observation.

FragileThe agent does not hallucinate
DurableEvery figure quoted appears in the tool results returned during the call

Absence of hallucination is unfalsifiable as written. Traceability to a source is checkable line by line.

Anchoring a judge with a handful of labelled examples, some passing and some failing, does more for consistency than lengthening the criterion. Pin the judge model and its temperature, or the same transcript will pass and fail across a week with nothing having changed.

build

Asserting on Tool Calls

Tool behaviour is the most mechanically checkable thing an agent does, and the assertions divide into four kinds. The fourth is the one most suites omit.

AssertionChecksMatchingMissed If Omitted
SelectionThat the correct tool was chosen from those availableExactA plausible neighbouring tool used instead, producing a confident wrong answer
Parameter valuesThat arguments carry the values the conversation establishedExact where precision mattersRight tool, wrong account, which is worse than not calling at all
Extraction accuracyThat values were lifted correctly from natural speech into structured fieldsNormalisedTranscription and formatting errors in dates, amounts and identifiers
Non-invocationThat a tool was NOT called when it should not have beenExactActions taken before verification, the failure nobody writes a test for
move_to_inbox

Tests Built From Real Traffic

The best test suite is a record of what has already gone wrong. Real conversations contain interruptions, accents, partial information and the specific confusions your users actually have, none of which a hand-written persona reliably invents.

1Select the conversation

Pick transcripts that failed, that a human had to rescue, or that took far more turns than they should have. Successful calls make weak tests.

Watch for: Selecting only failures builds a suite that says nothing about whether ordinary calls still work.

2Redact and anonymise

Real conversations carry personal data. A fixture is stored, copied and shared far more widely than a call recording, and outlives its retention policy.

Watch for: Redaction that changes the shape of an utterance changes what is being tested.

3Extract the assertion

Decide what should have happened, which is usually narrower than everything that did. One conversation typically yields one or two criteria worth keeping.

Watch for: Asserting on the whole transcript produces a test that fails on any harmless rewording.

4Pick the shape

If the failure was one bad decision at an identifiable point, it becomes a next-reply fixture. If it was a conversation that never converged, it becomes a simulation.

Watch for: Turning every incident into a full simulation makes the suite slow and its failures hard to read.

autorenew

Running Them Continuously

A suite of probabilistic tests behaves differently in a pipeline from a suite of deterministic ones. Every decision below has to be made explicitly or it will be made accidentally.

DecisionThe QuestionDefault That Usually Works
Gate or reportDoes a failing agent test block a release, or raise a flagGate on tool and safety assertions, report on judged quality
Flake toleranceHow many runs must pass before a test counts as passingBest of three for judged criteria, single run for deterministic ones
Suite costEvery run spends real inference on both agent and judgeFull suite nightly, a fast deterministic subset on every change
Judge pinningWhat happens when the judge model is upgradedPin the version, and rebaseline deliberately rather than discovering drift
Baseline driftHow you tell a real regression from ordinary varianceTrack pass rate over time rather than treating a single run as truth
alt_route

Choosing a Shape

You Want to KnowUseBecause
Does it make the right call in this exact situationNext-replyPins the state so the assertion is about one decision
Can it get someone from opening to resolutionSimulationOnly a full run reveals loops, dead ends and turn cost
Does it call the right thing with the right valuesTool callDeterministic and cheap, so it can run on every change
Did we break something we already fixedReplayThe case is real and the expected behaviour already agreed
Does it stay safe under a hostile callerSimulationAdversarial behaviour needs turns to develop, so a pinned state will not show it

Related: LLM Evaluation for benchmarks and judge design, Judge and Escalation for evaluation inside the runtime rather than in a suite, Turn-Taking for the interruption behaviours worth a scenario class of their own, Agentic Errors for the failure taxonomy a suite should cover, and Agentic Workflows for testing a graph rather than a single agent.