Service 10

Evaluation and Guardrails

Test suites for non-deterministic systems, so you can tell an improvement from a regression, plus runtime checks that decide what your model is allowed to do before a user sees it.

On this page
  1. What evaluation and guardrails actually is
  2. Who it is for, and who it is not for
  3. What we actually build
  4. How it works technically
  5. Scoring methods, and what each one misses
  6. Telling an improvement from a regression
  7. The build process, stage by stage
  8. What you get at handover
  9. Where evaluation projects go wrong
  10. What it costs to run once live
  11. How to tell whether you need this
  12. How to start

What evaluation and guardrails actually is

The short answer

Evaluation and guardrails are two systems sharing one definition of correct. Evaluation is an offline test suite that scores model output against recorded cases, so a change can be called an improvement or a regression with evidence instead of opinion. Guardrails are runtime checks in the request path that inspect inputs and outputs and decide whether to allow, rewrite, retry, escalate or refuse. Evaluation tells you what your system does. Guardrails decide what it is permitted to do. Most teams build the second and skip the first, which is why they can block a bad answer but cannot say whether last week's prompt edit helped.

Both exist because an LLM system has no compile step and no stack trace. Change one clause in a prompt, every demo still looks fine, and the failure surfaces in the small fraction of inputs nobody tried. Conventional testing assumes identical inputs give identical outputs. That fails here, and not only because of temperature: providers batch requests and route across hardware generations.

So the unit of testing changes. You stop asserting that output equals a string and start asserting it has a property: it validates against the schema, it carries the account number from the source document, it cites only passages actually retrieved. Then you run each case several times and report a rate with an interval around it.

  • Two systemsEvaluation runs offline against recorded cases. Guardrails run inline on live traffic. They share scoring code and little else.
  • Rates, not verdictsScore as a pass rate with a confidence interval. One green run is not evidence of anything.
  • Two tiersA smoke tier under a minute on every commit, a full tier nightly and before release.
  • Every decision loggedA guardrail blocking without recording input, score, threshold and decision can only be argued about, never tuned.
The vocabulary, defined once
Golden set
A versioned collection of real inputs with recorded expectations, used as the fixed reference a system is scored against. Real means captured from production traffic or support tickets, not written by the person who wrote the prompt.
Scorer
A function taking one model output and one case and returning a score. Deterministic scorers use code, such as schema validation. Model-graded scorers use a second model to apply a rubric.
LLM-as-judge
Using a language model as a scorer, given a rubric and a candidate answer. It reaches criteria code cannot express, and carries biases toward longer answers and toward its own family's output.
Groundedness
The property that every factual claim traces to a passage the system actually retrieved. It is checkable, unlike truth, which is why grounded systems are testable and open-ended ones are not.
Fail-closed
A guardrail configured so a timeout or error blocks the request rather than letting it through unchecked. Fail-open is sometimes correct and must always be a written decision.

Who it is for, and who it is not for

For teams with a model already in front of users who cannot answer the question that decides every release: is this version better than the last one. If your answer is a demo and somebody's instinct, you are the reader.

  • You ship prompt or model changes more than once a month and each one is a small act of faith.
  • Your system reads customer documents or account data, where a confident wrong answer costs money.
  • Compliance has asked what stops the model saying something it should not, and the honest answer is a line in the prompt.
  • A provider is deprecating the model you built on and you cannot compare the replacement.
  • Your agent calls tools that write to systems, so a wrong decision is a wrong refund rather than a wrong sentence.

Who should not buy this yet

  • You have not shipped anything. An eval suite for a system with no users measures your imagination.
  • You have fewer than about fifty real examples. Collect for three weeks first, because a golden set invented at a desk encodes the assumptions that caused the bugs.
  • Four people use it internally and tell you the moment it breaks. Twenty cases in a spreadsheet is proportionate.
  • The output genuinely has no notion of better, which is rarer than claimed.
The proportionality test

Count the people who would notice a silent quality drop within a day. One or two, and you need cases rather than a platform. Zero, and you need this.

What we actually build

Five components, each existing because a specific thing goes wrong without it. Parts assembled around your system, in your repository, running in your CI.

ComponentWhat it isThe failure it prevents
Case storeVersioned inputs with source, capture date, difficulty tier, expectations as propertiesA test set drifting from the work the system does
RunnerExecutes cases through your production entry point, with repeats and cachingA harness that tests the prompt alone and misses retrieval and post-processing
Scorer libraryDeterministic first, model-graded only where code cannot express the criterionScoring what is easy instead of what the business cares about
Guardrail chainOrdered checks with per-stage timeouts, thresholds, fail modes, one decisionChecks bolted on after launch, doubling latency and breaking streaming
Threshold replayReplays recorded traffic against a proposed threshold before it shipsLearning your false positive rate from angry users instead of from data
The last row is the part most teams have never built and miss the most.
The harness must call what production calls

If your runner talks to the model directly, it tests your prompt and nothing else. Most real failures live in retrieval, tool argument construction, truncation and post-processing. Point the runner at the same function your API handler calls, with a flag swapping side effects for recorded doubles.

How it works technically

The eval side is a batch job. The guardrail side is a request-path filter chain. Different shapes, different latency budgets. They share only the scorer library, which is why scorers are pure functions with no knowledge of where they run.

The eval loop, end to end

  1. Cases load from version control, usually JSONL so a diff is readable in a pull request.
  2. The runner writes a manifest: model id with version suffix, temperature, top_p, seed where supported, prompt hash, index version, git commit. Without it you cannot compare two runs, and you will try anyway.
  3. Each case runs k times through the production entry point, under a concurrency cap and a token budget that aborts rather than surprising you.
  4. Deterministic scorers run first and locally, costing nothing. Model-graded scorers run only on what survived, which is where the eval bill goes.
  5. A human promotes the run to baseline, or does not. Automatic promotion turns your baseline into a random walk.

Repeats, and why one run lies

Take 300 cases with a true pass rate near 90 percent. The standard error is the square root of 0.9 times 0.1 divided by 300, about 1.7 percentage points, so a rough 95 percent interval is plus or minus 3.4 points. A run returning 91.5 percent against a baseline of 89 percent has told you nothing. That is arithmetic on assumed values, not a benchmark: run it on your own case count. Either grow the suite, or restrict the claim to the slice where movement survived its own interval.

The guardrail chain in the request path

Order the chain by cost, so millisecond checks run before model checks. Independent stages run concurrently, making chain latency the slowest stage rather than the sum. Every stage declares a timeout and, separately, what happens when it fires. Streaming complicates the output side: prose streams with cheap incremental checks, while tool calls and structured payloads are never streamed and get the full chain.

Deterministic scorersModel-graded scorers
Cost per caseEffectively zero, it is codeA second model call, often with a larger input than the original
CatchesSchema breaks, missing entities, forbidden strings, out-of-range tool argumentsTone, completeness, whether the question was answered, subtle unsupported claims
StabilityIdentical every time, which is the pointShifts when the judge updates underneath you
Correct useFirst line of suite and chain, and most of your scorersCriteria code cannot express, on a smaller set, calibrated against humans

Tool calls are the guardrail that pays for the project

For any agent that acts, validate three things in order and in code. The tool name against an allowlist derived from the caller's own permissions, so the agent can never do what the person it acts for could not. The arguments against the tool's schema, ranges and enums included, before dispatch. Then value-level policy, such as routing a refund above a threshold to a human. Injection classifiers help, but scope is the actual control: an agent never granted the delete tool cannot be talked into calling it.

Guardrail chain configyaml
# Order is the design: cheap deterministic checks first, so model checks
# only see what survived. Every stage declares a timeout AND, separately,
# what happens when that timeout fires.

input_chain:
  - id: pii_redact               # regex plus checksum for card and id formats
    action: redact_in_place
    on_timeout: fail_closed      # never pass unredacted text onward

  - id: scope_classifier
    model: small-classifier@pinned-version
    threshold: { out_of_scope: 0.82, abuse: 0.65 }
    timeout_ms: 400
    on_timeout: fail_open        # deliberate: the output chain still runs

output_chain:
  - id: schema_validate
    on_violation: repair_once    # feed the validator error back, once
    then: deterministic_fallback
    on_timeout: fail_closed

  - id: tool_call_policy
    allowlist_from: caller_scope # the agent cannot call what the caller cannot
    argument_schema: per_tool
    value_rules:
      - { tool: issue_refund, when: "amount > 5000", action: route_to_human }
    on_timeout: fail_closed

  - id: groundedness
    model: judge@pinned-version
    input: [answer, retrieved_passages]
    threshold: 0.7
    timeout_ms: 900
    on_timeout: fail_closed      # slow beats ungrounded, every time
    sample_rate: 1.0             # lower only once you know the false positives

  - id: pii_egress
    action: block
    on_timeout: fail_closed

logging:
  per_stage: [stage_id, score, threshold, decision, latency_ms, model_version]
  retention_days: 30
  redact_before_write: true

Scoring methods, and what each one misses

Pick scorers by what the failure costs, not by what is convenient to compute. The commonest mistake in this field is a suite measuring JSON validity beautifully while the business cares whether the number inside is right.

ScorerCatchesBlind toCost
Schema validationMalformed output, missing fields, wrong types, enum violationsEvery semantic error inside a well formed objectFree
Citation id checkAnswers citing passages never retrieved, the cheapest hallucination detector there isA correct citation attached to a wrong claimFree
Rubric judgeCompleteness, tone, whether the question was answered, unsupported claimsIts own biases, and anything the rubric did not anticipateHigh
Human reviewEverything, eventuallyScale, and your calendarHighest
Build the free rows first. They find more real bugs in week one than the expensive rows find in a quarter.

The four biases in a model judge

  • Position bias: shown two candidates, judges favour a position. Run each comparison twice with the order swapped, and discard pairs where the verdict flips.
  • Verbosity bias: longer answers score higher for the same content. Check whether your score correlates with token count. If it does, the judge is measuring effort.
  • Self-preference: judges rate their own model family higher. Judge with a different family than the one generating.
  • Calibration drift: the provider updates the judge and every historical score becomes incomparable. Pin the version, keep a human-labelled subset, re-score it whenever you move the pin.
Rubric grader system prompttext
You score one candidate answer against one recorded case.
Never rewrite the answer. Never write prose outside the JSON.

CASE
  question:        {{case.question}}
  reference_facts: {{case.reference_facts}}   # MUST appear
  forbidden:       {{case.forbidden}}         # MUST NOT appear
  allowed_sources: {{case.allowed_sources}}   # passage ids the answer may use
CANDIDATE
  {{candidate.text}}

RUBRIC. Score 0, 1 or 2. Give 2 only if fully met.
  factual_support  2 every claim traces to allowed_sources
                   1 one unsupported claim, conclusion unchanged
                   0 any unsupported claim that changes the conclusion
  completeness     2 all reference_facts / 1 one missing / 0 two or more
  contamination    2 nothing forbidden / 0 anything. No partial credit.
  instruction_form 2 shape exact / 1 one field mislabelled / 0 broken

RULES. Judge only what is written. Never reward length, confidence or tone.
A refusal scores 2 on contamination and 0 on completeness: correct behaviour,
not a bug, and the report keeps the two apart. If the case is ambiguous, set
needs_human true and leave scores null.

Return only this JSON, no code fence:
{ "factual_support": 0|1|2|null, "completeness": 0|1|2|null,
  "contamination": 0|2|null, "instruction_form": 0|1|2|null,
  "unsupported_claims": ["verbatim quote"],
  "missing_facts": ["the absent reference_fact"],
  "needs_human": false,
  "one_line_reason": "max 20 words, the deciding evidence" }
A judge is a dependency, not a tool

Teams version prompts, models and indexes, then let the scorer float. Six weeks later the pass rate moves four points and nobody can say whether the system changed or the judge did. Pin the judge in the run manifest.

Telling an improvement from a regression

The question this service exists to answer. The answer is not a number, it is a rule about what evidence licenses what claim, applied consistently enough that people stop arguing from anecdote.

Framework

The ChatGPTalker Evidence Ladder

Five rungs. A change may only be described in the language of the rung its evidence supports, and may only reach production from rung four upward. We write this into the release checklist because the argument in the room is always about confidence, and this turns it into a question of fact.

01
Rung one: it looked better

Someone preferred the output in a playground. A hypothesis, not a result. Most shipped regressions are rung one evidence described in rung four language.

02
Rung two: it passed the smoke set

Twenty to forty cases covering paths that must never break, run once, under a minute. Proof the change did not break the obvious, which licenses you to keep going, not to ship it.

03
Rung three: it passed the golden set once

Full suite, one repeat per case, pinned manifest. You have a number and no estimate of the noise around it. The phrase allowed is 'no regression detected', which is weaker than 'no regression'.

04
Rung four: it beat the baseline by more than the noise

Multiple repeats, a variance estimate from them, movement whose interval does not overlap the baseline's, per slice. The minimum rung for production, and where most improvements evaporate.

05
Rung five: it held on live traffic

Shadow mode or a sticky canary on real users, scored by the same scorers, with the decision log as a second signal. Real inputs contain distributions your golden set does not.

A pass rate without an interval is a number that will eventually be used to justify a decision it cannot support.The line at the top of every eval report we write
Slices beat aggregates, always

Report by input length band, customer tier, document type and language. An aggregate holding steady while one slice collapses is the commonest way a real regression ships.

The build process, stage by stage

  1. Traffic read and failure taxonomyWeek 1

    We read two weeks of real traffic plus tickets, and write down the failure modes visible in your own logs with rough frequencies. Nothing is built. The output is the list of things worth testing, always different from what the team expected.

  2. Case capture and the golden setWeek 1 to 2

    Sampled from production, stratified so the hard and the rare are over-represented rather than drowned. Every case carries source and capture date so the set can be aged out deliberately.

  3. Runner, manifest and smoke tierWeek 2

    The harness is wired to your production entry point, side effects swapped for recorded doubles. The smoke tier lands in CI now, because a suite nobody runs is a document.

  4. Scorers, deterministic then model-gradedWeek 2 to 4

    Schema, entity, forbidden pattern, citation id and tool argument validity come first: cheap, stable, and they find most of the real bugs. Then a rubric, run against a human-labelled subset and rewritten until agreement satisfies you. A rubric never compared to a human is a random number generator with good manners.

  5. Baseline, slicing and the reportWeek 4

    Repeats configured, variance measured, slices defined with your team, first baseline promoted by a named person. From here the suite has an opinion about your changes.

  6. Guardrail chain and threshold replayWeek 4 to 5

    The chain is assembled with explicit timeouts and fail modes, then replayed against recorded traffic. Thresholds come from what each candidate would have blocked, not from a round number.

  7. Shadow, then enforce, then hand overWeek 5 to 6

    The chain runs in shadow long enough to see the false positive rate, then enforcement switches on one stage at a time. Handover names who reads the blocked sample weekly, who promotes a baseline, who re-labels the calibration subset monthly.

Why week one builds nothing

Every eval project that goes wrong went wrong in week one, by writing cases from the team's mental model of the work. Those cases pass on day one because they encode the same assumptions the system does. The cases that matter come from traffic.

What you get at handover

Everything lives in your repository, on your CI, with no dependency on us to run a suite or change a threshold. If any of this is missing, the handover has not happened.

Handover checklist
0 of 6 done
The last item is not a formality

Every suite has a boundary. Ours will not catch a wrong tone in a language nobody on the team reads, or a failure mode that has never appeared in your traffic. Writing it down separates a suite people trust from one people over-trust.

Where evaluation projects go wrong

The honest section. Six failures we see repeatedly, including in work we have had to repair.

  1. The golden set is written by the person who wrote the prompt. It passes almost everything on day one and then never catches anything, because it encodes exactly the assumptions that produced the bugs.
  2. Scoring the measurable instead of the important. JSON validity is easy, so it gets measured, while the real risk is a confident wrong figure inside a valid object.
  3. The judge floats. The scorer model is unpinned, the provider updates it, and every historical number becomes incomparable at a moment nobody can identify afterwards.
  4. Guardrails bolted on after launch. Two model calls land in front of a request already at the edge of acceptable latency, and someone disables the checks during a busy week.
  5. Nobody reviews false positives. Guardrails degrade the product silently for legitimate users, who do not complain, they leave. Sample blocked requests weekly and read them.
  6. Treating the eval score as the goal. Once a number is the target, cases leak into the prompt as examples and the suite becomes a mirror.
The failure that costs the most

Automatic baseline promotion. It looks like hygiene and it is the worst thing you can do. Each run silently becomes the new reference, degradations accumulate one interval at a time, and after two months the system is measurably worse while every comparison showed no regression.

What it costs to run once live

Two separate bills. The suite is billed when you run it, a function of your commit rhythm. The chain is billed on every request, a function of your traffic. The second surprises people, because a check costing a fraction of a cent multiplies by every call.

Eval suite running cost

Substitute your own price and case count. The default of 3 per million tokens is a stated assumption for this arithmetic, not a quote, and prices change often enough that you should check yours. Tokens per case means the whole round trip, judge call included.

0Cost per full run
0Cost per month
0Model calls per run

Repeats multiply everything, which is why the full tier runs on a schedule and the smoke tier on every commit. Caching unchanged cases against an unchanged manifest removes most of the bill.

Cost lineWhat drives itIf you ignore it
Guardrail token spendModel checks in the request path, once per request per stage, scaling with trafficPer-request cost roughly doubling with nobody attributing it to the checks
Added latencySequential model checks, and stages that could have run concurrentlyA product that feels slow, then checks disabled in the busiest week
Human calibrationA domain expert labelling a sample so the judge stays honest, a few hours monthlyJudge scores drifting from human judgement with no signal that it happened
Model migrationProvider deprecations, arriving on their schedule and not yoursAn emergency migration with no way to compare old to new

The line teams cut first is human calibration, and it is the line keeping the rest honest. For this arithmetic across a whole system, the total cost of ownership guide works through it line by line.

How to tell whether you need this

Five questions. Answer them honestly and the decision makes itself in either direction. We would rather you concluded no than paid us to build something out of proportion to your problem.

  1. When you last changed a prompt, what evidence did you have that it helped? A demo and a feeling means you are shipping from rung one.
  2. If your provider deprecated your model tomorrow with sixty days notice, could you compare the replacement quantitatively this week? If not, that migration will be done blind, and it will happen.
  3. What is the worst output your system could produce today, and what stops it reaching a user? If the answer is a sentence in the prompt, you have an instruction rather than a control.
  4. Can you name the slice of traffic your system is worst at? If not, an aggregate number is hiding something specific.
  5. When a guardrail blocks something, can someone see what and why within a minute? If not, thresholds get tuned by argument for as long as the system exists.

Three or more bad answers means the gap is real, and the fix is weeks of work rather than a platform. If all five are fine, catching regressions when the model changes is more use than this page.

Where this sits next to other work

Evaluation gives you the score. Agent observability gives you the trace explaining a specific score. Prompt systems give you the versioning that makes a score attributable to a change. Bought separately, that is the order.

How to start

A scoping call and a look at two weeks of your real traffic. Not a proposal deck. We want the inputs your system actually receives, because that is where the case set comes from.

  • A sample of real traffic, redacted if it must be, covering a fortnight so the weekly rhythm is visible.
  • The incident that prompted you to look into this. It usually names the first slice to score.
  • The name of the person who will own this after handover. If that name does not exist, fixing that comes first, and we will say so.

You leave with a written scope: a case count, a scorer list, and the failure modes worth testing first in priority order, whether or not you build it with us. Related reading: building a golden dataset from real work.

Cite this

ChatGPTalker, Evaluation and Guardrails: evaluation is an offline test suite scoring model output against recorded cases so a change can be called an improvement or a regression with evidence, while guardrails are runtime checks in the request path deciding whether to allow, rewrite, retry, escalate or refuse.

Questions we get asked

What is the difference between evaluation and guardrails?
Evaluation runs offline against recorded cases and answers whether a change improved the system, reported as a pass rate with a confidence interval. Guardrails run inline on live traffic and decide what a single request may do: block, rewrite, retry, escalate or refuse. They share scoring code, because a check worth running in production is usually worth asserting in the suite.
How many test cases does a golden set need?
Enough that the noise is smaller than the movement you care about. With a pass rate near 90 percent and 300 cases, the standard error is about 1.7 percentage points, so movement under roughly 3 points is indistinguishable from chance. In practice coverage binds harder than statistics, since a large set holding eleven cases for your second language is still blind there.
Can I use a model to grade another model's output?
Yes, for criteria code cannot express, under three conditions. Pin the judge to a version and record it in the run manifest, because an unpinned judge silently invalidates historical comparisons. Judge with a different model family than the one generating. Keep a human-labelled subset you re-score whenever judge or rubric changes, so you know your agreement rate rather than assuming it.
Should guardrails fail open or fail closed?
It depends per stage, and it must be a written decision rather than a default nobody chose. Anything preventing data leaving, such as a PII egress check, fails closed without exception, because a slow response is recoverable and a leak is not. A topic classifier at a few hundred milliseconds can reasonably fail open with a logged event, provided a later stage still constrains the damage.
What happens when the provider deprecates the model we built on?
You run the full suite against the replacement, compare per slice rather than in aggregate, and find where the new model is worse, because it will be worse somewhere even when the aggregate improves. Then you fix those slices with prompt changes and re-run. Teams without a suite do this migration by trying it and waiting for complaints, which is how a deprecation notice becomes an incident.

Tell us what is eating the hours.

Send the process, the volume and the tools it touches. You get a scoped plan with a build shape and a timeline, not a brochure.

Start a project