Structured LLM Outputs With Pydantic: Reliable JSON Schema in Python is a hands-on guide for AI developers who need a dependable system rather than another chatbot demonstration. It presents a reproducible setup path, a realistic workflow, tests for failure, and the controls that matter when generated text meets real users or external tools. Choose a model and SDK version supported by your account and validate all behavior in a non-production environment.
Why asking for JSON is not enough
A document-processing pipeline may require three keys—customer_name, urgency and summary—but a free-form model can return markdown, omit a field or invent a new one. Telling the model “please return JSON” is less reliable than enforcing a supported JSON Schema. Structured outputs make it easier to connect language models to software that expects predictable types. This tutorial focuses on a safe extraction workflow. Even when the JSON is schema-valid, its facts may still be wrong, so validation must extend beyond parsing.
Set up Python and Pydantic models
Use a virtual environment and install openai and pydantic. Define a BaseModel class for a support classification result with fields such as category: str, urgency: str and summary: str. An enum for urgency is preferable to an unrestricted string if your application expects only low, medium or high. Avoid deeply nested schemas without a use case; model and API support for schema features has limits. Keep the extraction specification and your downstream database schema reviewed together.
Use the SDK’s parse helper
According to the Responses API structured-output documentation, the Python SDK can accept a Pydantic model via client.responses.parse(model=MODEL, input=MESSAGES, text_format=TicketClassification). The parsed object is available as response.output_parsed when a valid structured response is returned. Supply a concise system instruction explaining what to extract and what to do when source text lacks information. Read the provider’s current schema compatibility requirements and supported models before deploying. A helper removes repetitive parsing code but does not remove the need to handle network failures and refusals.
Design a realistic ticket extraction test
Feed three examples: “Checkout fails when I pay with Visa,” “Please change our billing contact next month,” and an empty or nonsensical message. Decide how unknown category and missing dates should be represented in your schema. If a field is optional in the business sense, model nullability explicitly within the subset supported by the API rather than hoping the model omits required keys. A high-priority result should be checked against explicit business rules before creating a production incident. Structured outputs solve shape, not business truth.
Handle refusals, truncation and incomplete generations
Applications need a branch for model refusal, upstream timeouts and outputs that are incomplete due to limits. Do not assume output_parsed is non-null for every successful HTTP response. Check the response status or refusal fields supported by the SDK and return a typed error result. Avoid showing raw parsing exceptions to end users. When a source contains prompt-injection text, treat it as data to classify rather than authority to change the schema or call external tools.
Keep downstream effects under application control
A classifier should not directly delete tickets, approve refunds or send messages based solely on generated JSON. Validate extracted facts against trusted systems, require approval for consequential changes, and store the original evidence reference for audit. Measure field accuracy, missing-value behavior and category confusion on a human-labeled set. Keep schema versioning explicit across producers and consumers; changing an enum or required field can break integrations even when the model is behaving well. Version your prompts and schema along with application releases.
Practical acceptance test: prove the application works
Build a small test fixture before allowing real customers to interact with the system. Include a typical request, a confusing request, an explicitly out-of-scope request and a deliberately malformed input. Define the acceptable answer shape and whether the system should abstain, return a validation error or request approval. Record the exact model identifier, prompt revision and configuration used. When the assistant can invoke a tool, mock that tool in unit tests and prove that authorization is checked even when the model proposes an unauthorized argument. Include at least one request with adversarial instructions inside user-provided data.
After local tests, use a staging environment with synthetic or sanitized data to check network, credentials, health routes, timeouts and monitoring. Avoid interpreting the ability to generate plausible sentences as a successful end-to-end task. A good release criterion measures task completion and safe failure behavior in the same suite.
Production engineering checklist
Protect provider credentials and tool tokens, scope permissions to authenticated identities, and establish limits for request length, concurrency and cost. Separate read-only information retrieval from state-changing operations. Add predictable timeouts, bounded retries for transient errors, monitoring of upstream status and a process for disabling compromised integrations. Avoid retaining sensitive prompts unless necessary, protected and documented. Keep deployment configuration in reviewable version control and use tests to catch changes in schema or model behavior. If the system influences payments, legal obligations, hiring or other significant decisions, include appropriate human oversight and clear boundaries.
Frequently asked questions
Can an API key be placed in a Docker image or source file?
No. Treat it as a secret and inject it at runtime through an approved secret-management mechanism. Rotate leaked keys and prevent their appearance in build logs, telemetry and repositories.
How can I avoid unsupported or unsafe model output?
Restrict the task, use typed responses where possible, verify claims or permissions against trusted systems, test refusals and anomalies, and require confirmation for consequential actions. A good prompt helps, but deterministic application controls remain essential.
Documentation and further learning
Follow the official API or tooling documentation for version-specific examples and supported features. Our guides to RAG evaluation and prompt injection defense provide complementary approaches for testing evidence quality and tool trust boundaries.
Test a structured extraction with real edge cases
A useful support-ticket schema might define category as an enum, urgency as low/medium/high, and summary as a string. Test a clear outage report, a vague “it’s broken” complaint, and a message that contains instructions trying to change the result format. The returned object should maintain the schema, and your application should still verify the business meaning. For missing information, define an explicit unknown or nullable representation consistent with the supported schema subset.
Document what happens if the model refuses or reaches an output limit. A parsed value is not proof that the extracted facts are correct. Pair field-level evaluation with the LLM reliability and evaluation guide before connecting the output to a ticket queue.




