โหมด JSON และ response_format
เปิดใช้โหมด JSON ใน OpenAI API สร้างพรอมต์ที่ให้ผลลัพธ์เป็น JSON ถูกต้องอย่างสม่ำเสมอ และจัดการกรณีที่โมเดลยังทำรูปแบบเสียหายได้
โหมด JSON และ response_format เป็นบทเรียน AI Engineering Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Engineering Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ
The Problem with Unstructured LLM Output
By default, LLMs return free-form text. Parsing that text to extract structured data is fragile: a change in model behavior, a slight prompt variation, or an edge case in the input can change the output format unexpectedly, breaking your parser and crashing your application.
Consider asking an LLM to 'return the user's name and age as JSON'. Sometimes it returns {"name":"Alice","age":30}, sometimes it wraps it in a markdown code block, sometimes it adds explanatory prose. Any of these variations requires different parsing logic. Reliable machine-readable output requires forcing the model to follow a structure, not hoping it does.
OpenAI JSON Mode
OpenAI introduced JSON mode via the response_format parameter. When set to {"type": "json_object"}, the model is constrained to always return a valid JSON object. The model will never output anything that is not valid JSON — no markdown wrappers, no explanatory text, no trailing prose.
import openai
import json
client = openai.OpenAI()
response = client.chat.completions.create(
model='gpt-4o-mini',
messages=[
{
'role': 'system',
'content': 'Extract information from the text and return valid JSON only.'
},
{
'role': 'user',
'content': 'John Smith, age 34, works as a software engineer in Austin.'
}
],
response_format={'type': 'json_object'} # Guarantee valid JSON output
)
# Safe to parse - guaranteed valid JSON
data = json.loads(response.choices[0].message.content)
print(data)
# Example output: {"name": "John Smith", "age": 34, "job": "software engineer", "city": "Austin"}JSON Mode Caveats
JSON mode guarantees valid JSON syntax but does NOT guarantee that the JSON contains the fields you want. The model still decides what keys to include, their names, and the data types it uses. You might ask for a name field and get back full_name instead, or ask for an array and get a string.
Also note: JSON mode requires that you mention JSON in your prompt. If you enable JSON mode but your prompt does not ask for JSON output, the model may produce an empty JSON object or refuse to generate. Always explicitly instruct the model to respond in JSON format in the system or user message.
Structured Outputs with Pydantic (Preview)
OpenAI's newer Structured Outputs feature goes further than JSON mode: you provide a JSON Schema, and the model is constrained to return exactly that schema — specific field names, types, and nesting. This eliminates the schema inconsistency problem of basic JSON mode.
The Python SDK accepts Pydantic models directly, automatically converting them to JSON Schema and deserializing the response back into a typed Python object. This is the cleanest way to get reliable structured data from an LLM in Python.
import openai
from pydantic import BaseModel
from typing import Optional
client = openai.OpenAI()
class PersonInfo(BaseModel):
name: str
age: Optional[int]
job_title: str
city: str
completion = client.beta.chat.completions.parse(
model='gpt-4o-mini',
messages=[
{'role': 'system', 'content': 'Extract person information from the text.'},
{'role': 'user', 'content': 'Sarah Chen, 28 years old, is a data scientist based in Seattle.'}
],
response_format=PersonInfo # Pass Pydantic model directly
)
# Already deserialized into a PersonInfo instance
person = completion.choices[0].message.parsed
print(person.name) # Sarah Chen
print(person.age) # 28
print(person.job_title) # data scientist
print(person.city) # SeattleCrafting Prompts for Consistent JSON
Even with JSON mode enabled, your prompt design affects output quality. Best practices for JSON prompts:
- Name the fields explicitly: Tell the model exactly what fields you expect, not just 'return JSON'
- Specify types: 'Return the price as a number, not a string' prevents type mismatches
- Define enumerations: 'The category must be one of: bug, feature, question' prevents unexpected values
- Handle missing data: 'If a field is not present in the text, return null for that field'
Think of your prompt as a partial JSON Schema written in prose. The more precisely you specify the output contract, the more reliably the model will follow it.
Reliable JSON Without Structured Outputs
If you are using a model that does not support structured outputs or JSON mode, you can still get reliable JSON by being very explicit in your prompt and parsing defensively. The key technique is to ask the model to wrap its JSON in XML tags, which makes extraction unambiguous regardless of any surrounding text.
import re
import json
import openai
client = openai.OpenAI()
def extract_json_from_response(text):
# Try direct parse first
try:
return json.loads(text)
except json.JSONDecodeError:
pass
# Try extracting from XML tags
match = re.search(r'<json>(.*?)</json>', text, re.DOTALL)
if match:
return json.loads(match.group(1))
# Try extracting from JSON object pattern
match = re.search(r'({.*})', text, re.DOTALL)
if match:
return json.loads(match.group(1))
raise ValueError('No valid JSON found in response')
prompt = ('Extract the product info as JSON with fields: name, price_usd, in_stock.\n'
'Wrap your JSON in <json></json> tags.\n\n'
'Product: Blue Wireless Headphones cost $89.99, in stock.')
resp = client.chat.completions.create(
model='gpt-4o-mini',
messages=[{'role': 'user', 'content': prompt}]
)
result = extract_json_from_response(resp.choices[0].message.content)
print(result)Nested JSON Structures
JSON mode and structured outputs handle arbitrarily nested structures. You can define Pydantic models with lists, nested objects, and optional fields, and the model will populate the full structure correctly.
from pydantic import BaseModel
from typing import List, Optional
import openai
client = openai.OpenAI()
class LineItem(BaseModel):
product: str
quantity: int
unit_price: float
class Invoice(BaseModel):
vendor: str
invoice_number: Optional[str]
line_items: List[LineItem]
total: float
raw_text = '''
INVOICE #INV-2025-0042
From: TechSupplies Inc.
- 3x USB Hubs at $24.99 each
- 1x 4K Monitor at $399.00
Total: $474.97
'''
completion = client.beta.chat.completions.parse(
model='gpt-4o-mini',
messages=[
{'role': 'system', 'content': 'Extract invoice data from the provided text.'},
{'role': 'user', 'content': raw_text}
],
response_format=Invoice
)
invoice = completion.choices[0].message.parsed
print(f'Vendor: {invoice.vendor}')
print(f'Items: {len(invoice.line_items)}')
print(f'Total: ${invoice.total}')Handling Refusals in Structured Mode
When using structured outputs, the model may sometimes refuse to complete the extraction — for example, if the input text is empty, harmful, or clearly does not contain the requested information. In structured outputs mode, refusals are indicated by the refusal field on the message rather than the parsed field.
Always check for refusals before accessing the parsed result, especially when processing user-provided or untrusted input that might trigger content filters.
import openai
from pydantic import BaseModel
client = openai.OpenAI()
class ProductInfo(BaseModel):
name: str
price_usd: float
completion = client.beta.chat.completions.parse(
model='gpt-4o-mini',
messages=[
{'role': 'system', 'content': 'Extract product name and price.'},
{'role': 'user', 'content': 'Tell me how to build a weapon.'}
],
response_format=ProductInfo
)
message = completion.choices[0].message
if message.refusal:
print('Model refused:', message.refusal)
else:
product = message.parsed
print(f'Name: {product.name}, Price: {product.price_usd}')JSON for Multi-Value Extraction
JSON mode is especially powerful for extracting multiple distinct pieces of information from a single piece of text in one API call, rather than making separate calls for each field. Extract all the fields you need at once and parse the result into your data model.
This reduces both API calls and cost compared to asking for one field at a time. A single well-structured extraction prompt can pull names, dates, monetary amounts, sentiment, action items, and classification labels all at once from a single document.
Streaming with JSON Mode
JSON mode is compatible with streaming, but with an important constraint: the JSON is only valid once the complete response has been streamed. Individual token chunks of JSON are not valid JSON on their own. This means you must accumulate the full streaming response before parsing when using JSON mode.
For streaming applications that also need JSON output, use structured outputs with streaming, accumulate all chunks, then parse when the stream finishes. Alternatively, design your streaming UI to show a loading state while the JSON accumulates, then render the parsed result.
When to Use JSON Mode vs Structured Outputs
Choose the right tool for your scenario:
- JSON mode: Simple cases, prototyping, or when you only need valid JSON syntax without strict field enforcement. Use when the model deciding field names is acceptable.
- Structured outputs with Pydantic: Production systems that parse results programmatically. Use when you need guaranteed field names, types, and nested structure. This is the recommended approach for any extraction pipeline.
- XML tag extraction: Fallback for models that do not support JSON mode or when you need to extract JSON embedded in a longer response.
Quick Check
Test your understanding of AI Engineering concepts from this lesson.
Lesson Recap
In this lesson you learned: JSON mode via response_format guarantees valid JSON syntax but not specific field schemas, structured outputs with Pydantic models enforce exact field names and types using JSON Schema, and always check for refusals before accessing parsed results when processing untrusted input. Next up we explore defining Pydantic schemas in depth for typed extraction from complex documents.
คำถามที่พบบ่อย
บทเรียน “โหมด JSON และ response_format” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “โหมด JSON และ response_format” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Engineering Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “โหมด JSON และ response_format”
เปิดใช้โหมด JSON ใน OpenAI API สร้างพรอมต์ที่ให้ผลลัพธ์เป็น JSON ถูกต้องอย่างสม่ำเสมอ และจัดการกรณีที่โมเดลยังทำรูปแบบเสียหายได้ คุณปฏิบัติ AI Engineering Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Engineering Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Engineering Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “โหมด JSON และ response_format” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Engineering Academy นี้ได้ไหม
ได้ บทเรียน AI Engineering Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- โหมด JSON และ response_format
- ผลลัพธ์แบบมีโครงสร้างด้วย Pydantic
- การดึงข้อมูลจากข้อความไร้โครงสร้าง
- การตรวจสอบและลองใหม่เมื่อผลลัพธ์ไม่ถูกต้อง