Molten glass poured into precise interlocking moulds on a line, a caliper measuring each cast piece, one mismatched mould set aside.

The moment an LLM's output stops being read by a human and starts driving a UI — a plan, a product card, a price estimate, an enriched field — free-text is a liability. It has to be typed: generated against a strict schema, parsed by real code, and tested so a prompt edit can't silently produce something the parser chokes on. This is the discipline that turns "the model usually returns JSON" into "the model's output is a contract our build enforces".

Why UI-driving output must be typed

Free-text output has no guarantees: no promise a field exists, no promise a number is a number, no promise the shape is stable across model versions or prompt tweaks. A UI built on that is one phrasing change away from a blank card or a crash. Typed output flips the relationship — the schema is the contract, the model fills it, and anything that doesn't fit the schema is caught before render. You stop trusting the model to be well-behaved and start verifying it. This is the same shift, one layer up, as grounding an assistant in live tools: don't trust, verify.

Strict JSON at temperature zero

Two settings do most of the work. Temperature zero for anything structured — you are not writing poetry, you want the same input to yield the same output, which also makes caching and evaluation tractable. And a strict schema the model must fill: named fields, explicit types, required-vs-optional marked. In our enrichment pipeline we split generation into two calls — core structured fields in one, longer PDP content in another — because mixing a large free-text block with tight typed fields in a single response degrades both. Keep the typed call small and sharp; give prose its own call.

A schema is also where you encode business rules the model shouldn't have to remember. Enumerate the fields that can only take known values (a unit, a category, a currency) as closed enums rather than free strings, and the model physically cannot return a novel typo'd variant you then have to clean. Constrain what you can at the schema boundary, validate the rest after generation, and you shrink the surface where a fluent model can quietly do the wrong thing — which is the whole game with output that a UI will render without a human reading it first.

Bind the prompt to its parser in CI

Here is the practice we would evangelize to any team shipping LLM features: a prompt and its parser must be tested together, in the build. Prompts drift as people tune them; parsers drift as the code evolves; nothing keeps them honest with each other unless a test does.

From production

In one of our products the worked example embedded in the prompt is fed through the actual production parser during the build. If someone edits the prompt in a way the parser can no longer consume — renames a field, changes the shape of an example — the build fails before it ships. It has caught prompt edits that looked completely reasonable in review and would have produced unparseable output for every real request. A contract test is the only thing that keeps a prompt and its parser from drifting apart silently.

This is the structured-output half of a broader discipline; the deployment half — canaries, bake periods and rollback for the prompt itself — lives in prompt management.

Honest uncertainty: ranges and null over a fake zero

Typed output makes it tempting to demand a clean number for every field. Resist it. The most important schema-design decision is representing not knowing honestly:

  • Use ranges where a point estimate would be false precision. A goal-fit score or a delivery estimate is a range, not a spuriously exact figure.
  • Prefer null over a fabricated zero. Missing data must render as absent, never as "0" — a fake zero is a lie the UI will faithfully display as fact. Make the field nullable and teach the UI to show "unknown".
  • Carry a confidence signal — and check it's real. If the field marked "confident" is wrong as often as the one marked "uncertain", the signal is decorative; validate it the way you'd validate any other claim (see LLM evaluation).

Conservative backfill: repair on confident matches only

When validation finds a gap in structured output, the instinct is to fill it. Do so only on a confident, deterministic match — never by asking the model to guess. Our rule: "grilled chicken breast" may inherit chicken-breast nutrition data because the match is unambiguous; bare "chicken" may not, because it isn't. The failure mode you are guarding against is papering over a gap with plausible fiction, which is worse than an honest blank because it looks correct. Backfill is repair, not invention.

SituationWrong instinctRight rule
Missing numeric fieldEmit 0Emit null; UI shows "unknown"
Uncertain estimateOne precise numberA range with bounds
Gap after validationAsk the model to guessDeterministic backfill on confident match only
Prompt editedShip and hopeFail the build if the parser can't consume it

Two-call generation and why we split

A final structural note. When one response has to carry both tight typed fields and a paragraph of marketing prose, quality on both suffers — the model hedges the structure to serve the prose or flattens the prose to serve the structure. Splitting into two focused calls (typed core fields, then content) costs a little more per product but produces cleaner output on each, and it lets you cache and validate the two independently. Splitting also lets each call use the model and settings that suit it — a cheap, deterministic pass for the fields, a slightly warmer one for the copy — and it means a failure in one doesn't force you to regenerate the other. The same logic keeps enrichment reliable; we cover the economics of running these calls cheaply in LLM cost optimization, and the guardrails that validate the output in LLM guardrails. Typed, tested, and honest about what it doesn't know — that's the whole standard for any output a machine downstream will trust without a human in the loop.

Key takeaways

  • Any output that drives a UI must be typed — a strict schema is a contract you verify, not a hope the model behaves.
  • Generate structured output at temperature zero against a strict schema; give free-text prose its own separate call.
  • Bind the prompt to its parser with a build-time test — feed the prompt's worked example through the real parser so a bad edit fails CI.
  • Model uncertainty honestly — ranges over false precision, null over a fabricated zero, and validate any confidence signal.
  • Backfill is repair, not invention — fill gaps only on confident deterministic matches, never by asking the model to guess.
  • Split typed fields and prose into separate calls so each stays clean, cacheable and independently testable.

Frequently asked questions

How do you get reliable structured output from an LLM?
Generate against a strict schema at temperature zero, parse the result with real code, and reject anything that doesn't fit the schema before it reaches the UI. Then add a build-time test that feeds the prompt's own worked example through the production parser, so a prompt edit that breaks the shape fails CI instead of production.
What is a prompt-to-parser contract test?
A build-time check that the example inside a prompt still parses cleanly through the actual production parser. Prompts and parsers drift independently as people tune and refactor; the contract test is the only thing that catches an edit that quietly makes the output unparseable, before it ships.
Should an LLM field ever return zero for missing data?
No. A fabricated zero is a lie the UI will display as fact. Make the field nullable, return null when the data is genuinely missing, and render it as "unknown". Where a value is uncertain rather than missing, return a range instead of a spuriously precise number.
When is it safe to backfill a missing field automatically?
Only on a confident, deterministic match — "grilled chicken breast" can inherit chicken-breast data because the match is unambiguous; bare "chicken" cannot. Never fill a gap by asking the model to guess, because plausible fiction that looks correct is worse than an honest blank.

Typed output you can build a UI on.

The schema and contract-test discipline here runs across enrichment and the AI assistant on the marketplace we operate.

Request early access See the live marketplace →