Technical branch for developers Assemble manually
Structured outputs for business processes
Structured outputs aren’t just “JSON instead of text.” They’re the foundation for building resilient AI agents and integrations. In this article: how to do it right—with examples, pitfalls, and a ready-to-use checklist.
What are structured outputs and why does a business need them?
Structured outputs — This is an LLM response format where the result is presented in a strictly defined structure (usually JSON) that matches a pre-defined schema. Unlike free-form text, such responses can be used directly in code: stored in a database, passed to an API, validated, logged, and automated.
For business, this means:
- Eliminating “human” parsing (“need to extract the amount from the text”)
- Guaranteed data structure—even if the model makes a mistake, it returns JSON, not “broken” text.
- Direct integration with systems: CRM, ERP, backend, workflow engines
- Automatic validation and retry capability
How it works: pipeline from prompt to JSON
flowchart TD
A[User Request] --> B[Prompt with Schema]
B --> C[LLM API Call]
C --> D{Is Response Valid?}
D -->|Yes| E[JSON Object]
D -->|No| F[Retry / Fallback]
E --> G[Schema Validation]
G --> H[Use in Business Logic]
Key point: the schema is defined to API call. This can be a JSON Schema, Pydantic model, or built-in type (e.g., in OpenAI—`response_format`).
Example: from prompt to JSON in Python
Basic example with OpenAI API (via Pydantic):
from pydantic import BaseModel
from openai import OpenAI
class InvoiceData(BaseModel):
amount: float
currency: str = "RUB"
invoice_id: str
status: "paid" | "unpaid" | "overdue"
client = OpenAI()
completion = client.beta.chat.completions.parse(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Extract data from the invoice. Use only the information provided in the text."},
{"role": "user", "content": "Invoice №INV-2024-089 dated 05/12/2024: amount 45 000 RUB, status — paid."}
],
response_format=InvoiceData
)
invoice = completion.choices[0].message.parsed
print(invoice.amount, invoice.status) # 45000.0, 'paid'
Important: parse() instead of create(), and the model itself guarantees that the response will conform to the schema (or return an error).
Business Case: Automating Incoming Email Processing
Scenario: A client sends an email requesting a change to the payment deadline. You need to:
- Extract order ID, new date, reason
- Verify that the order exists and is not overdue.
- Create a task in Jira / CRM
Without structured outputs: 3 steps—LLM → text → regex → data. With it: 1 step—LLM → JSON → data.
Example schema for the query:
class RequestChange(BaseModel):
order_id: str
new_due_date: str # ISO 8601
reason: str
priority: "low" | "medium" | "high"
After that—just call the API, validate, and send the data to the CRM.
Common mistakes and how to avoid them
- Too complex a scheme → Model “hallucinates” (returns JSON but with false data). Solution: break into subtasks, use step-by-step reasoning.
- No fallback logic → On error, the pipeline crashes. Solution: Always handle errors.
ValidationErrorand return fallback values (null, default, human review). - Type Ignoring →
"45 000"instead of45000.0Solution: Use strict validation (Pydantic v2, strict=True). - No logging → Impossible to debug why the model “incorrectly” parsed. Solution: Log input, output, and errors (including raw response).
Structured Outputs Implementation Checklist
- [ ] Schema described as JSON Schema / Pydantic and versioned
- [ ] Specified in the API call
response_format(or equivalent) - [ ] There is a handler
ValidationErrorand fallback logic - [ ] Logs raw response + parsed object + error (if any)
- [ ] Conducted test validation on 10–20 real-world examples
- [ ] SLA defined: time allocated for parsing and retries
Next step: from outputs to agent
Structured outputs — not an endpoint, but the foundation for agents that:
- Parse input → Make decision → Call tool → Return structured result
- Can handle errors and retry calls
- Integrated into queues (e.g., RabbitMQ) for scaling.
Next — in the Telegram channel and in the following articles: how to build an agent with tool-calling, how to test its behavior, and how to make a production-ready workflow.