Skip to content

Structured Output, Verification & Cost

The earlier pages got the model the right context and let it act. This page is about making the output trustworthy and operable in production: forcing it into a usable shape, checking its work, and running it affordably. This is where limitation #2 — no real thinking bites hardest: the model produces fluent, confident output that may be wrong, and it won't notice. Everything here is a guard against that.

For non-engineers: the model always sounds sure of itself, whether it's right or wrong. The techniques on this page are how a product tells the difference — structured forms it must fill in, and a second model that double-checks the first. (Measuring quality over time is the companion topic, covered in Evaluation and observability.)

Structured / schema-guided output

By default a model returns free-form text. For a product, you almost always want structured output — JSON (or a typed object) matching a schema you define. You force the model to fill in a schema rather than write prose.

Two benefits, one obvious and one subtle:

  1. Parseable & reliable (obvious). Downstream code can consume {file, line, severity, title, ...} directly — no fragile regex over prose, no "sometimes it adds a preamble" surprises.
  2. It constrains reasoning (subtle). Asking the model to produce specific fields channels its thinking. A schema with broken_invariant, severity, and suggestion fields makes the model actually reason about each, instead of writing a vague paragraph. The schema is a thinking scaffold, not just an output format.

This is the production counterpart to schema-guided reasoning in prompting. AuditAgent leans on it everywhere: findings, verifier verdicts, file annotations, and triage targets are all schema-bound. Its file-annotation schema, for example, forces the model to pick from a fixed taxonomy — triage_label ∈ {scan, maybe, no_scan}, a closed set of classifications, a criticality tier, a 0–10 relevance score — rather than free-associating. Enum-bounded fields are especially powerful: they make invalid output structurally impossible.

Tip: validation should happen at the boundary. If the model returns output that doesn't match the schema, reject and retry rather than letting malformed data leak downstream. Anthropic's API now does this natively: structured outputs constrain the whole response to a JSON Schema (output_config.format), and strict: true on a tool definition guarantees its inputs validate exactly — while the SDK's parse() helper validates the response against your schema and re-prompts on a mismatch for you. See Anthropic's structured outputs docs.

Verifiers: checking the model with the model

Because the model can't reliably check its own confidence, a strong pattern is a separate verification pass — ideally by a different model than the one that produced the output.

AuditAgent's verifier is a good template. For each candidate finding, every model other than the one that emitted it is asked to render a structured verdict: confirmed | rejected | uncertain, plus a confidence score and a reason. The combined result takes a majority vote (ties → uncertain). Crucially, the verifier is fed more context than the original detector had — the surrounding function, related callers/callees, alternate implementations of the same interface — so it's a genuine second look, not an echo.

Two ideas generalize well beyond security:

  • Cross-model verification beats self-verification. A model asked "are you sure?" tends to agree with itself. A different model, or even the same model with a fresh context and an explicit skeptical framing, catches more.
  • Amplify confirmed results. Once a finding is verified, AuditAgent runs a "variant search" — it generalizes the confirmed finding into a pattern and looks for the same shape elsewhere. "Find one, find ten." The verification gate applies to variants too, so quality stays high.

Non-determinism is the default

The same prompt can yield different outputs on different calls. This is not a bug to eliminate — it's a property to design around:

  • Don't depend on exact output. Depend on schema-valid output and validated content.
  • Deduplicate. When you fan out across models or chunks, you'll get overlapping results. AuditAgent dedupes findings by the function they live in (and falls back to line-proximity), keeping the best of each group and using model agreement as a confidence multiplier.
  • Make the deterministic parts deterministic. Push as much logic as possible into non-LLM code (parsing, scoring, graph walks). Those parts are reproducible and testable; reserve non-determinism for the genuinely judgment-based step.

Measuring quality is its own discipline. Verification tells you a single output is trustworthy. Knowing whether the feature is getting better or worse over releases requires evals (a labelled set, precision/recall tracking, regression gates) and observability (tracing every call). Both are covered in depth on the next page — Evaluation and observability. The rest of this page covers the other production must-have: keeping cost under control.

Cost & latency at scale

Cost optimization for a product is a different discipline than picking a model for your IDE assistant. At scale, with thousands of calls, the levers are:

  • Prompt caching. If a large system prompt or retrieved context is reused across calls, cache it. For AuditAgent this was the single biggest cost lever — system prompts were 70%+ of input tokens on some strategies; enabling caching cut a representative scan from ~$13 to an expected $4–6. The default cache TTL is short (~5 minutes), so it helps within a burst of related calls; a longer 1-hour TTL option exists for prefixes reused across bigger gaps, at a higher write cost.
  • Batch API for non-latency-sensitive passes. Verification, annotation, and other work that doesn't need an immediate answer can go through the Batch API at roughly half price. If a step doesn't block a user waiting on a response, batching it is nearly free savings.
  • Model tiering. Use a cheap, fast model for high-volume mechanical steps and a strong model only where judgment is needed. AuditAgent uses a Haiku-class model for per-file annotation (thousands of cheap calls) and a stronger model only for the actual analysis and reranking. Spending the same model on every step is the most common way to overpay.
  • Do work without the LLM wherever possible (see the pre-process-first principle).
  • Budget the work. Cap chunks/targets per run (top_n), tool calls, and turns — both to control quality and to bound spend.

Takeaways

  • Use schema-guided output: it makes results parseable and sharpens the model's reasoning. Prefer closed enums where you can.
  • Verify with a different model and more context; don't trust self-checks.
  • Treat non-determinism as normal: validate, dedupe, and keep deterministic logic out of the LLM.
  • Tune cost with prompt caching, model tiering, and explicit budgets — the levers compound at scale.
  • Measure quality with evals and trace every call — see Evaluation and observability.

Sources