Schema-first LLM outputs

Structured JSON and Schema Validation for LLM APIs

A language model response becomes operational data only after it satisfies a contract that the application understands.

JSON SchemaLLM outputValidation
Structured JSON and schema validation workflow for LLM API responses with types and required fields

Free-form language is flexible for people and difficult for software. An application that expects a company name, industry and array of tags cannot safely consume a paragraph and hope that every field appears in the same form.

A structured JSON LLM API defines the expected object before generation, validates the candidate response and returns a controlled error when the object cannot be accepted. This is the foundation of a reliable Enrich API.

Why structured JSON matters

Structured output makes downstream code simpler. Fields have names, values have types and missing information follows a defined rule. A database write can reject an invalid object before it corrupts a record. An agent can read a compact context object instead of parsing prose.

Structure also improves evaluation. A reviewer can score the accuracy of industry separately from the quality of summary. Schema-validity rate can be measured across model routes. Unexpected fields become visible rather than silently ignored.

JSON alone is not enough

A response can be valid JSON and still violate the application contract. A date may use the wrong format. A required field may be missing. A number may arrive as a string. A category may fall outside the allowed taxonomy. JSON Schema or an equivalent type system defines those deeper rules.

Start with the schema, not the prompt

Write the desired object as if another team will implement the producer. Name fields clearly, describe their meaning and avoid asking one field to carry several concepts.

{
  "$id": "ticket_triage_v2",
  "type": "object",
  "additionalProperties": false,
  "required": ["intent", "priority", "summary", "tags"],
  "properties": {
    "intent": {
      "type": "string",
      "enum": ["authentication", "billing", "bug", "how_to", "other"]
    },
    "priority": {
      "type": "string",
      "enum": ["low", "normal", "high", "urgent"]
    },
    "summary": {"type": "string", "maxLength": 240},
    "tags": {
      "type": "array",
      "uniqueItems": true,
      "maxItems": 8,
      "items": {"type": "string"}
    }
  }
}

The prompt or model request can then explain how to fill that contract. The validation layer remains the final authority.

Use controlled taxonomies

Enums reduce variation and make filters reliable. Keep the taxonomy small enough that examples and evaluation data cover every value. Add an other or unknown option when the input may not fit.

Model unknowns honestly

Many enrichment fields cannot always be known. The schema should represent that reality. A nullable field is explicit. An empty string is ambiguous. A guessed value is dangerous.

For each field, decide whether it is:

  • required and knowable: the request should fail if the field is absent;
  • required but nullable: the key must exist, but null is accepted when evidence is missing;
  • optional: clients can operate without the key;
  • derived: deterministic code calculates it after accepted fields are available.

Instruct the generation step to prefer null over unsupported inference. Validation cannot detect every invented value, so the request design must discourage invention before it happens.

Build a layered validation pipeline

Validation should include more than one check. A common pipeline contains:

  1. Parse validation: confirm that the response is valid JSON.
  2. Schema validation: enforce required fields, types, enums and size limits.
  3. Business validation: apply rules such as priority compatibility or date ranges.
  4. Evidence validation: confirm that high-impact fields have approved support when required.
  5. Policy validation: decide whether the object can be auto-accepted or needs review.

Return validation details separately from the data object. Clients need to know whether the object is accepted, repaired or rejected.

{
  "data": { ... },
  "validation": {
    "schema": "ticket_triage_v2",
    "valid": false,
    "errors": [
      {"path": "/priority", "code": "enum", "message": "Value must be low, normal, high or urgent"}
    ]
  }
}

Repair, retry or reject?

Not every invalid object deserves another model call. Use deterministic repair for safe transformations such as trimming whitespace or converting a numeric string. Do not silently repair a semantic value that changes meaning.

A bounded retry may be appropriate when the output is almost valid and the task deadline allows it. Send the validation error and original schema, then ask for a corrected object. Cap attempts and include retry cost in the request budget.

Reject the result when the input is invalid, evidence is insufficient for a required high-impact field or the retry budget is exhausted. A controlled error is part of a reliable API.

Keep repair metadata

If a response was repaired, record which fields changed and which method performed the repair. This helps operators distinguish model quality from validator behavior.

Version schemas for client stability

A schema becomes an API contract once clients depend on it. Additive optional fields may be compatible, but renamed fields, changed types and new required properties can break consumers.

Use explicit names such as company_profile_v1 and company_profile_v2. Let clients pin a version. Publish a migration guide and support an overlap period when a breaking change is necessary.

Store the schema version with every enriched record. Without it, a future reader cannot know which definitions or validation rules produced the object.

Test both structure and meaning

Schema tests should contain valid objects, invalid types, missing fields, extra fields, oversized strings and unsupported enum values. Semantic evaluation should use labeled records to check whether accepted values are correct.

Track at least these metrics by task and route:

  • first-attempt schema-validity rate;
  • validity after deterministic repair;
  • validity after model retry;
  • field accuracy for accepted objects;
  • null rate and unsupported-claim rate;
  • cost and latency per accepted object.

A schema does not guarantee truth, but it makes the output testable. Combined with evidence rules, evaluations and bounded retries, structured JSON turns model output into a safer application interface.

Define the output contract first

Write a small JSON Schema, allow honest unknowns and build validation tests before connecting the enrichment result to a database or agent.