Evaluation as an API is the API-first form of evaluation infrastructure. It means evaluation can be invoked, queried, compared, and acted on programmatically by CI systems, product code, agents, notebooks, and internal tools, instead of only being viewed in a dashboard.
The emphasis is the interface itself: structured inputs, structured outputs, stable evaluator identifiers, experiment identifiers, links back to the trace that was scored, score explanations, and hooks that let a caller act on a result. The sibling term “evals as APIs” describes the same pattern from the caller’s side, where the concern is depending on an eval service. This entry is about the contract that service has to offer.
The contract determines what you can do with a score. A number in a UI supports a conversation. A number returned with an evaluator version, an explanation, and a trace link supports a merge gate, an alert, and a regression test.
Build better agents with Arize
Trace, evaluate, and learn. Build agents that work with Arize AX and start tracing your runs today.
Prefer open source? Try Arize Phoenix for self-hosted, open source agent observability.
Key takeaways
- An eval API turns evaluation into a callable service with a request and response contract, which is what lets CI jobs, agents, and product code run the same evaluator and get comparable results.
- The request needs the material being judged plus enough identity to make the result meaningful: evaluator ID and version, the span being scored, and metadata for slicing.
- A response carrying only a score is close to useless in production. It needs a label, an explanation, the evaluator and judge model versions, and a pointer back to the evaluated trace.
- Sync, async, and batch are three call patterns with different latency and cost profiles. Inline blocking calls behave like guardrails; queued calls behave like measurement.
- Stable evaluator identifiers are what keep scores comparable over time. Change the judge prompt or model without a version bump and your history quietly stops meaning the same thing.
What the request carries
Field names vary by platform, but a usable eval request generally includes:
- The material to judge. The model
inputandoutputat minimum, plus the retrievedcontextfor groundedness evaluators or the arguments for tool correctness. - A reference, when one exists. An expected answer, present for dataset rows and absent for live traffic. Its presence decides which evaluators can run.
- An evaluator identifier and version. Which judge, at which revision. The most important field for comparability.
- A target identifier. The span, trace, or dataset row the score attaches to, so results join back to behavior instead of floating free.
- Metadata for slicing. Tenant, route, model version, prompt version, locale.
- An idempotency key. Retries are normal, and without one you will double-score spans and skew your own averages.
Programmatic evaluation of roughly this shape shows up across serving stacks, including evaluation workflows driven through a model platform API. The field list is stable across implementations because it follows from what callers need downstream.
What the response must return
This is where an eval API is either useful or decorative.
- A label or score. Prefer a small enumerated set such as
pass,fail, orneeds_reviewover free text, and treat fine-grained numeric scores from an LLM judge with caution. - An explanation. The reason for the label. Without it, a failing score creates work rather than direction.
- Version identity. Evaluator and judge model version, stored on the result rather than inferred from when it ran.
- A trace or span link. The path from a bad number to the actual conversation, which is the difference between a metric and a debugging tool.
- Cost and latency accounting. Tokens and time per evaluation, attributable per evaluator and route, so evaluation costs surface before the billing cycle does.
- Explicit error semantics. A distinct signal for “the evaluator ran and the output failed” versus “the evaluator could not run.” Collapsing those is expensive.
Sync, async, and batch
Synchronous and inline. The caller waits for a verdict before responding to the user. This is guardrail territory, where the answer changes what gets returned. It spends your latency budget and needs a hard timeout with a defined default.
Asynchronous and post-hoc. The caller emits the span and a sampled evaluation runs after the response ships. This is how most production quality measurement works: no user-facing latency, and room for a more careful judge.
Batch. A dataset is scored in bulk for an experiment or a CI run. Throughput and cost matter, single-call latency does not.
The same evaluator should be callable in all three modes. If your inline and batch evaluators are different code, their scores are not comparable, and someone will compare them anyway.
Why the contract matters more than the score
Once the response shape is dependable, callers can build on it. A CI job scores a dataset, compares against the base branch, and sets a check status. A monitor scores sampled spans and alerts on a slice. A review queue pulls everything marked needs_review. An agent can score its own intermediate steps and retry a failing one before returning anything, which only works when evaluation is callable from inside the harness.
None of those workflows care what the score looks like. They care that it is structured, versioned, attributable to a trace, and stable enough to write logic against.
Contract details teams get wrong
- Mutating an evaluator in place. Editing a judge prompt without a version bump makes last month’s scores incomparable, and the change is invisible in the data.
- Using a floating model alias. The provider’s next upgrade shifts your baselines with no change on your side.
- No idempotency. Retried calls create duplicate scores on the same span.
- Dropping explanations at storage time. Saving only the label removes the field that makes a failure debuggable.
- Free-text verdicts. Every caller writes its own parser, and each one differs.
FAQ
How is calling an eval API different from calling an LLM?
An LLM call returns text. An eval API returns a judged result with identity: a label from a known set, an explanation, evaluator and judge versions, a link to the scored trace, and error semantics you can branch on. Assembling that around a raw model call is what building an eval service means.
Should evaluation run inline or after the fact?
After the fact for quality measurement, which keeps evaluation out of the user’s latency path and lets you use a stronger judge on a sample. Inline only when the result changes the response, which is a guardrail decision, and then set a timeout and decide in advance what happens when it fires.
What should an eval API response include?
A label from a defined set, an explanation, evaluator and judge model versions, the span identifier, token and latency accounting, and a distinct error state for evaluator failure. That is enough to gate a merge, raise an alert, populate a review queue, and reproduce the result later.
How do I keep scores comparable when I change an evaluator?
Version the evaluator, store the version on every result, and rescore a fixed baseline set with both versions before switching. If the two disagree on the baseline, you know how much of any later movement belongs to the evaluator, and you can keep the old version running until the new one is trusted.