← All articles

Article

Structured outputs need contracts, not parser patches

AI AutomationWorkflowOperations

A structured output is not reliable because it looks like JSON once in a demo. It is reliable when the team has agreed what the output means, who validates it, what happens when it is incomplete, and which downstream decision is allowed to trust it.

That is the difference between a parser patch and an output contract.

Most LLM automations start with a generous prompt and a hopeful parser. The first run works. The second run returns a missing field. The third run invents a category that downstream code does not understand. Someone adds a regex. Someone else adds a retry. A product manager asks whether the automation is safe enough to put in front of a customer, and the team answers with anecdotes instead of a contract.

The thesis is simple: structured outputs need contracts, not parser patches. If an LLM workflow is becoming part of an operational process, the output schema is not a technical detail. It is the interface between probabilistic generation and accountable work.

Tools are making this abstraction more practical. The BAML documentation frames prompts as functions that can produce type-safe structured outputs, be previewed in an editor, and fit into maintainable workflows rather than living as loose strings. That matters, but the tool is not the point. The operating habit is the point: define the contract before hardening the parser.

Parser patches hide ownership

A parser patch feels productive because it converts a visible failure into a passing run. The automation no longer crashes when a field arrives as a string instead of an enum. It retries when the model wraps JSON in prose. It trims a prefix, normalizes a date, or maps a near match to an allowed value.

Some of that plumbing is necessary. Production systems need tolerant edges. But parser patches become dangerous when they absorb decisions that should be explicit. If a lead scoring workflow receives confidence: null, should the sales task be created, held for review, or dropped? If a support triage workflow returns urgency: high without evidence, should it page a human? If a claims extraction workflow returns a value outside the allowed policy type, should the case be corrected, rejected, or escalated?

Those are not parsing questions. They are product, operations, and risk questions.

This is similar to the argument in AI automation needs failure classes, not retries: a retry is useful only after the team knows what kind of failure it is trying to recover from. Structured outputs need the same discipline. A missing optional note is not the same as a missing customer identifier. An invalid enum is not the same as an output that is valid but unsupported by evidence.

When ownership is hidden in parser code, the workflow becomes hard to audit. Engineers know which exceptions are swallowed. Operators know which cases feel strange. Product leaders know the desired customer experience. Nobody shares one artifact that says what the automation is allowed to produce.

What belongs in an output contract?

An output contract should be small enough to read and concrete enough to test. It is not a twenty-page governance document. It is the agreed interface for one automation output.

Start with the schema. Name every field, its type, and whether it is required. Avoid vague containers such as metadata unless the downstream consumer genuinely treats them as opaque. If the workflow needs a decision, model the decision directly. If it needs evidence, give evidence its own field. If it needs uncertainty, define how uncertainty is represented.

Then define allowed states. Nullable fields are not a weakness if they are intentional. A null can mean unknown, not applicable, withheld, or failed to extract. Those are different states. If the same empty value can mean four things, the downstream team will eventually guess. The contract should make the state legible.

Add validation rules. Some rules are syntactic: the date must be ISO formatted, the category must be one of five values, the amount must be numeric. Other rules are semantic: a refund recommendation must cite a policy clause, a high-risk classification must include the triggering evidence, a customer-facing summary must not include internal notes. The second group is where many LLM workflows fail quietly.

Add the fallback path. If validation fails, where does the work go? Retry once with a narrower prompt? Route to a human queue? Return a safe default? Ask the user for missing information? The fallback should match the business consequence. A failed internal enrichment step may be skipped. A failed compliance classification should not be guessed.

Finally, name the owner. The owner is not always the engineer who wrote the integration. Product may own the meaning of the fields. Operations may own the review queue. Legal or security may own specific blocked states. Engineering may own the validator and telemetry. The contract should say who changes the schema, who approves new enum values, and who receives alerts when validation starts failing.

Which fields deserve the most attention?

The fields that deserve the most attention are the fields that trigger action.

A generated summary can be imperfect and still useful if a human reads it before acting. A generated status that closes a ticket, sends a customer email, approves a refund, changes a CRM stage, or calls another tool has a different burden. The contract should be stricter where the workflow becomes less reversible.

This is why structured output design and observability design belong together. In AI agent observability needs trace contracts, the central point is that traces should show the work, not just the fact that a model ran. The output contract gives those traces something to inspect. Did the model provide evidence for the decision? Did the validator reject a required field? Did the fallback route fire because of schema failure, policy failure, or low confidence?

A useful contract separates four cases that teams often blur.

First, the model did not follow the format. That is a structured output failure.

Second, the model followed the format but left required work incomplete. That is a validation failure.

Third, the model produced a valid output that the business does not trust enough to automate. That is a review threshold.

Fourth, the model produced a valid output and the downstream system could not accept it. That is an integration contract mismatch.

Each case needs a different response. Treating all four as parser problems guarantees messy automation.

Where should validation fail?

Validation should fail as close as possible to the output boundary, before the result can create operational side effects.

That sounds obvious, but many workflows validate too late. They let the LLM output move into a spreadsheet, a ticketing system, a CRM, or an internal dashboard, and only discover the ambiguity after a person acts on it. By then the cost is social as much as technical. Someone has to ask whether the automation was wrong, whether the process was unclear, or whether a human misread the output.

A better pattern is to create a narrow gate immediately after generation. The gate checks structure, required fields, allowed values, evidence requirements, and confidence thresholds. It then emits one of a few operational states: accepted, needs review, needs more input, failed safely, or blocked.

Those states should be boring. Boring is good. Boring states make dashboards easier, queues clearer, and incidents less dramatic. The goal is not to make the model look certain. The goal is to make uncertainty routable.

This is where type-safe workflow tools help. BAML is one example because its docs emphasize typed outputs, prompt functions, editor preview, and generated clients across languages. But the same operating contract can be implemented with other schema validators, function calling interfaces, JSON schema, custom tests, or internal workflow engines. The important part is that the schema, validator, fallback, and owner exist before the team adds another clever recovery rule.

Audit one automation before adding another retry

The practical move is not to rewrite every LLM workflow this week. Pick one automation whose output already causes small moments of distrust.

Find one real output. Put it next to the downstream action it triggers. Then ask five questions.

What fields does the action actually need?

Which fields are required, optional, nullable, or forbidden?

What validation proves the output is usable rather than merely well-formed?

What happens when the output is incomplete, unsupported, or outside the allowed states?

Who owns changes to the contract?

If the team cannot answer those questions, another retry will only make the automation fail later and less visibly.

Structured outputs are not a formatting trick. They are a coordination surface. They let product define meaning, operations define safe handling, and engineering enforce the boundary. The moment an LLM output moves work from one system to another, the team needs more than a parser that usually survives. It needs a contract that says what can be trusted, what must be reviewed, and what should stop.