เมื่อจบคู่มือนี้ คุณจะสามารถเรียกใช้ structured outputs ของ OpenAI จากโค้ดของคุณเองได้: ส่ง JSON Schema ให้โมเดล, ตั้งค่า strict: true และรับผลตอบกลับที่ตรงกับรูปแบบที่ต้องการ จากนั้นคุณจะได้ส่งคำขอแรก, parse ผลลัพธ์, จัดการกรณีปฏิเสธ/ตัดทอน และสร้างชุดการทดสอบ API ใน Apidog เพื่อยืนยันว่า payload ตรงตาม schema จริง
สิ่งที่คุณต้องมีก่อนเริ่มต้น
Structured outputs จำกัดการสร้างผลลัพธ์ของโมเดลให้เป็นไปตาม JSON Schema ที่คุณกำหนด เมื่อส่ง schema พร้อม strict: true โมเดลจะสร้างผลลัพธ์ที่มีคีย์, ประเภทข้อมูล และค่า enum ตรงตามข้อกำหนด แทนที่จะต้องเขียนโค้ดกัน parsing พังจาก JSON ที่รูปร่างไม่แน่นอน
Structured outputs ต่างจากการ prompt แบบ “ตอบกลับเป็น JSON เท่านั้น” เพราะคำสั่งแบบนั้นรับประกันได้แค่ในเชิงพฤติกรรม ไม่ใช่ข้อบังคับระดับ schema โมเดลอาจเพิ่มข้อความอธิบาย, คืนชนิดข้อมูลผิด หรือขาดฟิลด์ที่จำเป็นได้ ส่วน structured outputs บังคับใช้ข้อจำกัด ณ เวลาถอดรหัส
ก่อนเริ่ม คุณต้องมี:
- OpenAI API key ที่ตั้งค่าไว้ใน environment variable ชื่อ
OPENAI_API_KEY - โมเดลที่รองรับ schema แบบเข้มงวด
- JSON Schema ที่อธิบาย output ที่ต้องการ
เลือกโมเดลที่เหมาะสม
Structured outputs ใช้งานได้ในโมเดล OpenAI รุ่นใหม่ตั้งแต่ตระกูล GPT-4o และต่อเนื่องถึงซีรีส์ GPT-5 เอกสารของ OpenAI แนะนำให้เริ่มโปรเจกต์ใหม่ด้วยโมเดลเรือธงล่าสุด (gpt-5.5 ในขณะที่เขียน)
โมเดลรุ่นเก่าและโมเดลยุค gpt-3.5 รองรับ JSON mode แต่ไม่รองรับการบังคับใช้ schema แบบเข้มงวด หากคุณต้องพึ่ง strict: true ให้ตรวจสอบ model ID ที่ใช้จริงก่อน deploy เพราะความสามารถนี้ผูกกับเวอร์ชันของโมเดล
OpenAI มี 2 ฟีเจอร์ที่คล้ายกันแต่ไม่เหมือนกัน:
JSON mode
{
"response_format": {
"type": "json_object"
}
}
JSON mode รับประกันว่า output เป็น JSON ที่ถูกต้องตามไวยากรณ์ แต่ไม่รับประกันว่าฟิลด์, ชนิดข้อมูล หรือ enum จะตรงกับ schema ของคุณ
Structured outputs
{
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "schema_name",
"strict": true,
"schema": {}
}
}
}
Structured outputs รับประกันทั้ง JSON ที่ถูกต้องและรูปร่างที่ตรงกับ schema
| โหมด JSON | Structured outputs แบบเข้มงวด | |
|---|---|---|
| พารามิเตอร์ | response_format: {"type":"json_object"} |
response_format พร้อม type: "json_schema" และ strict: true
|
| JSON ถูกต้อง | ใช่ | ใช่ |
| ตรงกับ schema | ไม่ | ใช่ |
| บังคับฟิลด์ที่จำเป็น | ไม่ | ใช่ |
| บังคับ type และ enum | ไม่ | ใช่ |
| ยังควร validate ต่อไหม | ควรเสมอ | ควรสำหรับกฎระดับค่าและ regression test |
หมายเหตุเรื่อง API: Chat Completions ใช้ response_format ส่วน Responses API รุ่นใหม่แสดงแนวคิดเดียวกันภายใต้ text.format พร้อม type: "json_schema" กฎของ schema เหมือนกัน ต่างกันแค่ตำแหน่งของฟิลด์ใน request
ส่งคำขอ structured output ครั้งแรก
ตัวอย่างนี้ดึงข้อมูลจากข้อความ ticket support ให้เป็น object ที่มี schema ชัดเจน
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.5",
"messages": [
{
"role": "system",
"content": "Extract the ticket into the schema."
},
{
"role": "user",
"content": "My checkout 500s every time I use a saved card. Started today. Account: acct_8842."
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "support_ticket",
"strict": true,
"schema": {
"type": "object",
"properties": {
"summary": {
"type": "string"
},
"category": {
"type": "string",
"enum": ["billing", "bug", "account", "other"]
},
"severity": {
"type": "integer"
},
"account_id": {
"anyOf": [
{ "type": "string" },
{ "type": "null" }
]
}
},
"required": ["summary", "category", "severity", "account_id"],
"additionalProperties": false
}
}
}
}'
จุดที่ต้องสังเกต:
-
type: "json_schema"เปิด structured outputs -
strict: trueบังคับให้ output ตรง schema - ทุก property อยู่ใน
required -
additionalProperties: falseป้องกันคีย์ส่วนเกิน - ฟิลด์ที่อาจไม่มีค่าใช้
anyOfร่วมกับnull
อ่านผลตอบกลับ
โมเดลจะคืน message.content เป็น string JSON ที่ตรงกับ schema เช่น:
{
"summary": "Checkout returns HTTP 500 when paying with a saved card",
"category": "bug",
"severity": 3,
"account_id": "acct_8842"
}
ในแอปจริง คุณควร parse JSON หลังจากตรวจสอบว่าไม่มี refusal และผลลัพธ์ไม่ถูกตัดทอน
ตัวอย่าง Python:
import json
msg = response.choices[0].message
if msg.refusal:
handle_refusal(msg.refusal)
else:
ticket = json.loads(msg.content)
process_ticket(ticket)
เขียน schema ให้อยู่ใน subset ที่รองรับ
Structured outputs รองรับเพียง subset ของ JSON Schema เพื่อให้ OpenAI บังคับใช้ข้อจำกัดได้อย่างน่าเชื่อถือและ cache schema ที่ compile แล้วได้
กฎสำคัญ:
- root ต้องเป็น object
ใช้ไม่ได้:
{
"type": "array"
}
ใช้ object ห่อแทน:
{
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["items"],
"additionalProperties": false
}
- ทุก property ต้องอยู่ใน
required
Structured outputs ไม่มี optional field แบบดั้งเดิม หากค่าขาดได้ ให้ทำเป็น nullable:
{
"account_id": {
"anyOf": [
{ "type": "string" },
{ "type": "null" }
]
}
}
- ทุก object ต้องมี
additionalProperties: false
วิธีนี้ทำให้โมเดลไม่สร้างคีย์ที่ schema ไม่ได้ประกาศไว้
- schema มีข้อจำกัดด้านขนาด
โดยทั่วไป schema รองรับ object properties ได้ประมาณ 100 รายการ และซ้อนกันได้สูงสุด 5 ระดับ หาก schema กว้างหรือลึกเกินไป อาจถูกปฏิเสธ ควร flatten เท่าที่เหมาะสม
- บาง keyword ไม่ได้ถูกบังคับใช้โดยโมเดล
keyword อย่าง pattern, format, minLength และ minimum ไม่ได้รับประกันจากโมเดล ถ้าคุณต้องการ regex, date format หรือช่วงตัวเลขที่เข้มงวด ให้ validate ซ้ำในแอปหรือ test pipeline
ดังนั้น “JSON ที่รับประกัน” หมายถึงรูปร่างของ object ถูกล็อก ไม่ได้หมายความว่ากฎทางธุรกิจถูกต้องทั้งหมด ถ้าคุณเคยใช้ oneOf/anyOf/allOf เพื่อสร้าง optional หรือ union fields แนวคิดจะคล้ายกัน: schema คุมโครงสร้าง ส่วน business validation ต้องทำต่อเอง
จัดการ refusal และ output ที่ถูกตัดทอน
มีกรณีที่ output จะไม่ตรง schema โดยตั้งใจ: เมื่อโมเดลปฏิเสธคำขอที่ไม่ปลอดภัย โมเดลจะคืน refusal แทน content ที่เป็น JSON ตาม schema
ตรวจสอบ refusal ก่อน parse เสมอ:
import json
msg = response.choices[0].message
if msg.refusal:
handle_refusal(msg.refusal)
return
ticket = json.loads(msg.content)
กรณีอื่นที่ต้องระวัง:
- response ถูกตัดกลางคันเพราะถึง
max_tokens - ใช้ parallel tool calls ร่วมกับ structured outputs
ถ้าคุณใช้ tool calls ร่วมด้วย ให้ตั้งค่า:
{
"parallel_tool_calls": false
}
ทดสอบ structured outputs ใน Apidog
โหมดเข้มงวดช่วยบังคับ schema ตอนโมเดลสร้างผลลัพธ์ แต่ยังไม่แทนที่การทดสอบ เพราะ model ID อาจถูกเปลี่ยน, schema อาจถูกแก้, prompt อาจเปลี่ยน หรือเส้นทาง refusal อาจทำงานต่างจากเดิม
คุณสามารถใช้ Apidog เพื่อสร้าง request, assertion และ mock สำหรับ workflow นี้
การแบ่งหน้าที่ควรเป็นแบบนี้:
- OpenAI structured outputs: สร้าง JSON ให้ตรง schema
- Apidog: ตรวจสอบ response ที่ได้รับเทียบกับ schema และทำให้ความผิดพลาดถูกจับได้ใน CI
ขั้นตอนใช้งาน
- สร้าง request
สร้าง request ไปยัง Chat Completions ใน Apidog ใส่ headers และ body ที่มี response_format ตามตัวอย่างด้านบน จากนั้นบันทึกไว้ใน collection
- เพิ่ม assertion สำหรับ response
ตรวจสอบค่าหลัก เช่น:
-
categoryต้องเป็นbilling,bug,accountหรือother -
severityต้องเป็น integer -
account_idต้องเป็น string หรือnull
Apidog สามารถตรวจสอบ response เทียบกับ JSON Schema ได้โดยแนบ schema เดียวกับที่คุณส่งให้ OpenAI
- รันใน CI
ใส่ collection เข้า pipeline เพื่อให้ทุกการเปลี่ยน model, prompt หรือ schema ถูกทดสอบซ้ำ หาก response ผิด contract ให้ build fail ทันที
- สร้าง mock API
ก่อนต่อ OpenAI จริง หรือเมื่อต้องการทดสอบ frontend/consumer โดยไม่ใช้ token ให้ตั้งค่า mock API ที่คืนตัวอย่าง response ตาม schema เดียวกัน
แนวทางนี้ช่วยให้ทีมที่ consume structured output ทำงานต่อได้โดยไม่ต้องรอ integration เสร็จทั้งหมด คุณสามารถดาวน์โหลด Apidog แล้วจัดการ request, assertion และ mock ในที่เดียว
คำถามที่พบบ่อย
JSON mode ถูกแทนที่ด้วย structured outputs แล้วหรือยัง?
ยังไม่ถูกแทนที่ JSON mode ยังใช้ได้และยังรับประกัน JSON ที่ valid แต่ไม่บังคับ schema สำหรับโค้ดใหม่ที่มีรูปแบบข้อมูลชัดเจน ควรใช้ structured outputs พร้อม strict: true
root schema เป็น array ได้ไหม?
ไม่ได้ ระดับบนสุดต้องเป็น object ให้ห่อ array ไว้ใน property เช่น:
{
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["items"],
"additionalProperties": false
}
ทำ optional field อย่างไร?
Structured outputs กำหนดให้ทุก property อยู่ใน required ถ้าค่าหายได้ ให้ใช้ nullable field:
{
"nickname": {
"anyOf": [
{ "type": "string" },
{ "type": "null" }
]
}
}
คีย์ nickname จะมีเสมอ แต่ค่าเป็น null ได้
ใช้ strict mode แล้วข้าม validation ได้ไหม?
ข้ามการ validate รูปร่างพื้นฐานได้ในหลายกรณี แต่ยังควร validate กฎระดับค่า เช่น regex, format, min/max และ business rules เพราะ keyword บางตัวไม่ได้ถูกบังคับใช้โดยโมเดล นอกจากนี้ refusal และ truncation ยังต้องจัดการแยกต่างหาก หากยังไม่คุ้นกับ schema อ่านพื้นฐานได้ที่บทนำ JSON Schema
ควรใช้โมเดลใด?
Structured outputs ใช้งานได้กับ GPT-4o และรุ่นใหม่กว่า รวมถึงซีรีส์ GPT-5 เอกสาร OpenAI แนะนำให้ใช้โมเดลเรือธงปัจจุบันสำหรับโปรเจกต์ใหม่ แต่คุณควรตรวจสอบ model ID ที่ใช้จริงว่ารองรับ strict: true ก่อนนำไป production
สรุป
workflow ที่ควรใช้คือ: เลือกโมเดลที่รองรับ structured outputs, ส่ง schema ผ่าน response_format พร้อม strict: true, เขียน schema ให้อยู่ใน subset ที่รองรับ, ตรวจ refusal ก่อน parse, และ validate กฎระดับค่าซ้ำเมื่อจำเป็น จากนั้นใช้ Apidog เพื่อยืนยัน response เทียบกับ schema และสร้าง mock สำหรับส่วนอื่นของระบบ โมเดลช่วยรับประกันรูปร่าง ส่วน test suite ช่วยพิสูจน์ว่าสัญญานั้นยังไม่พังเมื่อระบบเปลี่ยนแปลง

Top comments (0)