Structured output prompts help turn an LLM response into data that an application can parse, validate, store, and use safely. This guide provides a reusable pattern for JSON schemas, field rules, examples, validation, retries, and fallbacks that you can adapt as your workflow, model, or API changes.
Overview
Free-form text is useful for conversation, but it creates friction when an application expects predictable fields. A support workflow may need a category, priority, and short summary. An extraction pipeline may require an array of entities with a name, type, and confidence note. In each case, the model should produce an agreed structure rather than an answer that a developer must interpret with fragile string operations.
Structured output prompts address this problem by defining the expected shape and the rules for filling it. A good implementation has two layers:
- Prompt-level instructions: explain the task, field meanings, allowed values, missing-data behavior, and boundaries.
- Application-level validation: check the returned data with a JSON parser and, where appropriate, a JSON Schema validator or equivalent type system.
The prompt is not a substitute for validation. Models can misunderstand ambiguous instructions, return incomplete data, or produce a value that is syntactically valid JSON but unsuitable for your application. Treat the model response as untrusted input, even when the provider offers a structured-output or schema-constrained mode.
For broader prompt design patterns, see System Prompt Examples: Reusable Templates for Reliable AI Assistants. If your structured response is generated from retrieved documents, the same principles can be applied within a retrieval-augmented generation pipeline.
Template structure
A reliable structured output prompt separates the task from the data contract. The following template is intentionally provider-neutral:
Role: You extract issue details from the supplied text.
Task:
Return one JSON object describing the issue. Do not add commentary outside the JSON object.
Output fields:
- category: one of "billing", "technical", "account", or "other"
- priority: one of "low", "medium", or "high"
- summary: a short factual description
- customer_name: a string when stated; otherwise null
- requested_actions: an array of strings; use [] when none are stated
Rules:
1. Use only information present in the input.
2. Do not guess missing names, causes, or actions.
3. Use null for an unknown customer_name, not an empty string.
4. Use the exact enum values listed above.
5. Return valid JSON matching the output contract.
Input:
{{text}}
This structure makes several decisions explicit. It defines the top-level type, names every field, limits enum values, distinguishes unknown data from an empty value, and states what to do when an array has no items. These details reduce ambiguity more effectively than simply saying “return JSON.”
A corresponding JSON Schema might look like this:
{
"type": "object",
"additionalProperties": false,
"required": ["category", "priority", "summary", "customer_name", "requested_actions"],
"properties": {
"category": {"type": "string", "enum": ["billing", "technical", "account", "other"]},
"priority": {"type": "string", "enum": ["low", "medium", "high"]},
"summary": {"type": "string"},
"customer_name": {"type": ["string", "null"]},
"requested_actions": {"type": "array", "items": {"type": "string"}}
}
}
Schema syntax and supported features vary by provider and API mode, so treat this as a design example rather than a drop-in request body. Before implementation, confirm how your chosen API handles required fields, nullable values, strictness, refusals, and incomplete responses.
How to customize
Start with the smallest useful contract. Every field creates another decision the model and your application must handle. Add a field only when it supports a real downstream action, search filter, database column, or evaluation criterion.
Choose types deliberately
Use strings for text, numbers for measurable quantities, booleans for genuine yes-or-no states, arrays for repeated items, and objects for related groups of fields. Avoid using a string that contains JSON, such as {"items": "[... ]"}. Nested data should be represented as an actual array or object so the application does not need a second parsing step.
Define missing-data behavior
Decide whether an absent value should be null, an empty array, an empty string, or an omitted field. These are not interchangeable. Use null when a field is relevant but unknown, and an empty array when the field is a collection with no detected members. If omission is allowed, make that choice explicit in both the schema and the application.
Use enums for controlled values
Enums are useful for routing, filtering, and workflow states. Explain each value in the prompt, then validate it in code. If your categories are likely to evolve, keep the enum in one shared definition so the prompt, schema, tests, and database logic do not drift apart.
Keep evidence separate from conclusions
For extraction or RAG workflows, consider fields such as evidence, source_id, or quoted_text alongside the derived answer. This does not prove that the model is correct, but it gives reviewers and evaluators something concrete to inspect. Do not ask the model to invent citations or source identifiers when they are not present in the input.
Examples
Example: sentiment classification
A compact contract for a sentiment analyzer could include label, explanation, and text_span. The label might be restricted to positive, neutral, or negative. If the input is too short or ambiguous, add an explicit needs_review boolean rather than forcing an inaccurate label.
{
"label": "neutral",
"explanation": "The message states a status without clear approval or dissatisfaction.",
"text_span": null,
"needs_review": false
}
Example: keyword extraction
For a keyword extraction tool, define whether results should be words, phrases, or both. A useful object might contain keywords, , and language. Set a maximum number only if the limit matters to the interface or storage layer, and explain how duplicates and generic terms should be handled.
Validation and error handling
After receiving a response, parse it, validate its schema, and apply application-specific checks. For example, a valid JSON object may still contain an overly long summary, an invalid identifier, or a category that is no longer active.
- Attempt to parse the response as JSON.
- Validate required fields, types, enums, and additional properties.
- Run domain checks, such as length limits or identifier formats.
- Record the failure category without storing sensitive raw input unnecessarily.
- Retry only when the failure is likely recoverable, using a short correction instruction.
- Use a safe fallback, human review queue, or explicit failure state when validation still fails.
A retry should not blindly resend the same request. Include the validation error in a controlled repair prompt, ask for the corrected JSON only, and cap the number of attempts. If the output affects an external action, require stronger checks or human confirmation before execution. The LLM application reliability checklist provides a useful companion for evaluation, monitoring, and cost control.
When to update
Revisit a structured output prompt whenever the contract or its operating conditions change. The most important triggers include:
- Schema changes: a field is renamed, made optional, split into multiple fields, or assigned new enum values.
- Workflow changes: another service consumes the output, a new database constraint is introduced, or an automated action is added.
- Observed failures: logs show malformed JSON, frequent nulls, incorrect categories, truncation, or repeated repair attempts.
- Model or API changes: a provider changes its structured-output mode, supported schema features, refusal behavior, or response limits.
- Input changes: documents, languages, formatting, or retrieval sources differ from the data used during testing.
Maintain a small test set containing normal inputs, missing fields, conflicting details, long inputs, empty inputs, and adversarial or irrelevant text. Run it whenever you change the prompt, schema, model, or parser. Track not only whether JSON parses, but also whether the values are useful and whether the application handles failure safely.
For a practical maintenance routine, review the contract alongside your prompt engineering checklist, inspect validation failures by category, and update the prompt and schema together. Keep a version identifier with stored outputs when reproducibility matters. Structured output works best as a maintained interface: clearly defined, validated at the boundary, tested against representative inputs, and revised when the surrounding system changes.