Structured Outputs
Structured Outputs allow the model to generate data that strictly conforms to JSON Schema, rather than free text. This makes output results more controllable and easier to parse, especially suitable for scenarios like data extraction, API response formatting, and configuration generation.
Core Concepts
| Feature | Description | Use Cases |
|---|---|---|
| JSON Schema Constraint | Define output structure through Schema | Data extraction, API responses |
| Strict Mode | Force model to follow Schema, reject invalid output | Production environment, automated processes |
| Nested Structure Support | Support objects, arrays, nested objects | Complex data structures |
| Type Safety | Automatically verify field types (string, number, boolean, etc.) | Type-sensitive applications |
Quick Selection Guide:
- Need structured data: Use
response_formatto specify JSON Schema - Only need valid JSON: Use
json_objectmode (no Schema required) - Complex data extraction: Use together with tool calling (Function Calling)
Why Use Structured Outputs?
Pain Points of Traditional Methods
# Traditional method: Let model generate freely, then manually parse
response = client.chat.completions.create(
model="Ling-2.6-flash",
messages=[{
"role": "user",
"content": "Extract name and age from the following text: Zhang San, 25 years old"
}]
)
# Output might be:
# "Name: Zhang San, Age: 25"
# "{'name': 'Zhang San', 'age': 25}"
# "According to the text, the name is Zhang San, age is 25 years old"
# Requires complex regex or LLM to parse again, unreliableAdvantages of Structured Outputs
# Structured outputs: Get data conforming to Schema directly
response = client.chat.completions.create(
model="Ling-2.6-flash",
messages=[{
"role": "user",
"content": "Extract name and age from the following text: Zhang San, 25 years old"
}],
response_format={
"type": "json_schema",
"json_schema": {
"name": "person_info",
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"}
},
"required": ["name", "age"]
}
}
}
)
# Output strictly is:
# {"name": "Zhang San", "age": 25}
# Can be directly parsed as Python object
import json
data = json.loads(response.choices[0].message.content)
print(data["name"]) # Zhang SanQuick Start
Basic Usage: JSON Object Mode
If you only need to ensure output is valid JSON, without strictly constraining structure:
Python
from openai import OpenAI
client = OpenAI(
base_url="https://api.ant-ling.com/v1",
api_key="YOUR_API_KEY"
)
response = client.chat.completions.create(
model="Ling-2.6-flash",
messages=[{
"role": "user",
"content": "List three renewable energy sources, return as JSON array"
}],
response_format={"type": "json_object"}
)
import json
data = json.loads(response.choices[0].message.content)
print(data)
# Output: ["solar", "wind", "hydro"] or similar valid JSONAdvanced Usage: JSON Schema Strict Mode
Precisely control output structure through JSON Schema:
Python
from openai import OpenAI
client = OpenAI(
base_url="https://api.ant-ling.com/v1",
api_key="YOUR_API_KEY"
)
response = client.chat.completions.create(
model="Ling-2.6-flash",
messages=[{
"role": "user",
"content": """Analyze the following product review:
"This phone has great battery life, but the price is a bit expensive."
Extract sentiment tendency and key points."""
}],
response_format={
"type": "json_schema",
"json_schema": {
"name": "sentiment_analysis",
"schema": {
"type": "object",
"properties": {
"overall_sentiment": {
"type": "string",
"enum": ["positive", "neutral", "negative"],
"description": "Overall sentiment tendency"
},
"key_points": {
"type": "array",
"items": {
"type": "object",
"properties": {
"aspect": {
"type": "string",
"description": "Aspect of review"
},
"sentiment": {
"type": "string",
"enum": ["positive", "neutral", "negative"],
"description": "Sentiment for this aspect"
},
"mention": {
"type": "string",
"description": "Original mention"
}
},
"required": ["aspect", "sentiment", "mention"]
}
}
},
"required": ["overall_sentiment", "key_points"]
}
}
}
)
import json
result = json.loads(response.choices[0].message.content)
print(json.dumps(result, ensure_ascii=False, indent=2))Example Output:
{
"overall_sentiment": "neutral",
"key_points": [
{
"aspect": "battery life",
"sentiment": "positive",
"mention": "battery life is great"
},
{
"aspect": "price",
"sentiment": "negative",
"mention": "price is a bit expensive"
}
]
}JSON Schema Details
Supported Types
| JSON Schema Type | Description | Example |
|---|---|---|
string | String | "name": {"type": "string"} |
integer | Integer | "age": {"type": "integer"} |
number | Number (including decimals) | "price": {"type": "number"} |
boolean | Boolean | "active": {"type": "boolean"} |
array | Array | "tags": {"type": "array", "items": {"type": "string"}} |
object | Object | "address": {"type": "object", "properties": {...}} |
Common Constraints
{
"type": "object",
"properties": {
"username": {
"type": "string",
"minLength": 3,
"maxLength": 20,
"description": "Username, 3-20 characters"
},
"email": {
"type": "string",
"format": "email",
"description": "Email address"
},
"age": {
"type": "integer",
"minimum": 0,
"maximum": 150,
"description": "Age"
},
"role": {
"type": "string",
"enum": ["user", "admin", "guest"],
"description": "User role"
},
"tags": {
"type": "array",
"items": { "type": "string" },
"maxItems": 10,
"description": "Tag list"
}
},
"required": ["username", "email"]
}Nested Structures
{
"type": "object",
"properties": {
"company": {
"type": "object",
"properties": {
"name": { "type": "string" },
"address": {
"type": "object",
"properties": {
"city": { "type": "string" },
"country": { "type": "string" }
},
"required": ["city", "country"]
}
},
"required": ["name"]
},
"employees": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"department": { "type": "string" }
},
"required": ["name"]
}
}
},
"required": ["company"]
}Typical Use Cases
1. Data Extraction and Parsing
Extract structured information from unstructured text:
schema = {
"name": "invoice_extraction",
"schema": {
"type": "object",
"properties": {
"invoice_number": {"type": "string"},
"date": {"type": "string", "format": "date"},
"vendor": {"type": "string"},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"description": {"type": "string"},
"quantity": {"type": "integer"},
"unit_price": {"type": "number"}
}
}
},
"total_amount": {"type": "number"}
},
"required": ["invoice_number", "date", "total_amount"]
}
}2. API Response Formatting
Ensure model output conforms to the format expected by backend API:
schema = {
"name": "api_response",
"schema": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["success", "error"]
},
"data": {"type": "object"},
"message": {"type": "string"},
"timestamp": {"type": "string", "format": "date-time"}
},
"required": ["status"]
}
}3. Configuration Generation
Generate configuration files conforming to specific format:
schema = {
"name": "app_config",
"schema": {
"type": "object",
"properties": {
"app_name": {"type": "string"},
"version": {"type": "string"},
"features": {
"type": "object",
"properties": {
"dark_mode": {"type": "boolean"},
"notifications": {"type": "boolean"},
"max_items": {"type": "integer", "minimum": 1}
}
}
},
"required": ["app_name", "version"]
}
}4. Multi-step Reasoning Results
Decompose complex reasoning process into structured steps:
schema = {
"name": "math_solution",
"schema": {
"type": "object",
"properties": {
"problem": {"type": "string"},
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"step_number": {"type": "integer"},
"description": {"type": "string"},
"calculation": {"type": "string"}
}
}
},
"final_answer": {"type": "string"},
"verification": {"type": "string"}
},
"required": ["problem", "steps", "final_answer"]
}
}Comparison with Tool Calling
| Feature | Structured Outputs | Tool Calling (Function Calling) |
|---|---|---|
| Main Purpose | Format model response | Let model call external functions |
| Execution Time | Only format output | May trigger actual function execution |
| Interaction Mode | Single response | May have multiple rounds of interaction |
| Use Cases | Data extraction, formatting | Need external data or operations |
| Schema Definition | response_format | tools parameter |
Selection Advice:
- Only need structured data → Use Structured Outputs
- Need to call APIs, query databases, etc. → Use Tool Calling
Best Practices
1. Provide Clear Descriptions
Add description to fields in Schema to help model understand intent:
{
"properties": {
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Confidence score, 0 means completely uncertain, 1 means completely certain"
}
}
}2. Use Required Wisely
Mark required fields clearly, but don’t over-constrain:
{
"properties": {
"name": { "type": "string" },
"email": { "type": "string" },
"phone": { "type": "string" }
},
"required": ["name"]
// phone and email are optional, adapt to different scenarios
}3. Use enum to Limit Values
When fields have fixed options, use enum to improve accuracy:
{
"sentiment": {
"type": "string",
"enum": ["positive", "neutral", "negative"]
}
}4. Handle Large Arrays
For arrays that might be long, set reasonable limits:
{
"items": {
"type": "array",
"items": { "type": "string" },
"maxItems": 100,
"description": "Return at most 100 items"
}
}5. Combine with System Prompts
Use system prompts to further guide the model:
messages=[
{
"role": "system",
"content": "You are a data extraction assistant. Please extract key information from the text provided by the user, strictly return in the specified JSON Schema format."
},
{
"role": "user",
"content": "Extract the following resume information: ..."
}
]Common Questions
Q1: What if the model doesn’t follow Schema?
- Check if Schema syntax is correct (can use online JSON Schema validation tools)
- Ensure Schema is not too complex, split into multiple simple Schemas if needed
- Clearly state output format requirements in prompts
- Use more powerful models (e.g., Ling-2.6-1T/Ling-2.6-flash)
Q2: How to handle optional fields?
Don’t set all fields as required, for optional fields:
{
"properties": {
"required_field": { "type": "string" },
"optional_field": {
"type": ["string", "null"],
"description": "Optional field, return null when no value"
}
},
"required": ["required_field"]
}Q3: How complex can Schema be?
It is recommended to follow these principles:
- Nested levels not exceeding 3-4
- Array item structures remain consistent
- Total number of fields controlled within 20
- Too complex Schema may affect model performance
Q4: Does streaming output support structured outputs?
Yes. After enabling streaming, the model will gradually generate JSON content:
response = client.chat.completions.create(
model="Ling-2.6-flash",
messages=messages,
response_format={"type": "json_schema", "json_schema": schema},
stream=True # Enable streaming
)
# Need to accumulate all chunks before parsing JSON
content = ""
for chunk in response:
if chunk.choices[0].delta.content:
content += chunk.choices[0].delta.content
# Parse after stream ends
data = json.loads(content)Q5: Does structured output increase latency?
Structured outputs require additional validation and constraint processing, may have slight latency increase. It is recommended to:
- For scenarios with high real-time requirements, weigh the necessity of using structured outputs
- Use simpler Schema to reduce processing time
- Consider caching results for common queries
Related Resources
- Streaming - Get structured responses in real-time
- Quickstart - Complete your first API call in 5 minutes
- Model Selection - Learn about characteristics of Ling, Ring, Ming models
JSON Schema Reference
For more JSON Schema syntax and advanced features, please refer to JSON Schema Official Documentation .