เมื่อจบคู่มือนี้ คุณจะสามารถเรียกใช้ structured outputs ของ OpenAI จากโค้ดของคุณเองได้: เพียงแค่ส่ง JSON Schema ให้โมเดล, ตั้งค่า strict: true และรับผลตอบกลับที่รับประกันว่าจะตรงกับรูปแบบที่คุณต้องการ คุณจะได้ส่งคำขอครั้งแรก, อ่านผลตอบกลับ, จัดการกรณีพิเศษ, และ สร้างชุดการทดสอบ API ใน Apidog ที่ยืนยันว่า payload เป็นไปตามที่กำหนดจริง
สิ่งที่คุณต้องมีก่อนเริ่มต้น
Structured outputs กำหนดข้อจำกัดในการสร้างของโมเดลเพื่อให้ผลลัพธ์เป็นไปตาม JSON Schema ที่คุณระบุ เมื่อคุณส่ง schema โดยตั้งค่า strict: true โมเดลจะไม่สามารถสร้างฟิลด์ที่ละเมิดข้อกำหนดนั้นได้ คีย์ที่จำเป็นทุกตัวจะปรากฏ, ประเภททุกตัวจะตรงกัน, และค่า enum ทุกตัวจะเป็นหนึ่งในรายการที่คุณระบุ คุณจะหยุดเขียนโค้ดสำหรับป้องกันการ parsing และเริ่มเชื่อถือ payload ได้
นี่เป็นการอัปเกรดที่แท้จริงจากทางเลือกอื่น การสั่งงานแบบอิสระ เช่น "ตอบกลับด้วย JSON เท่านั้น" มักจะใช้ได้จนกว่าจะไม่ได้ผล เพียงแค่การเบี่ยงเบนเหตุผลเล็กน้อย คุณก็จะได้ข้อความเชิงอธิบายที่ห่อหุ้มออบเจกต์ของคุณ หรือวันที่ที่คุณคาดหวังจะเป็นจำนวนเต็ม Structured outputs เปลี่ยนข้อตกลงจากคำสั่งที่คาดหวังให้เป็นข้อจำกัดที่ถูกบังคับใช้ ณ เวลาถอดรหัส
ในการทำตาม คุณต้องมี:
- คีย์ OpenAI API ที่ตั้งค่าเป็น
OPENAI_API_KEY - โมเดลที่รองรับการบังคับใช้ schema แบบเข้มงวด (ดูรายละเอียดเกี่ยวกับโมเดลด้านล่าง)
- JSON Schema ที่อธิบายรูปแบบที่คุณต้องการ
เลือกโมเดลที่เหมาะสม
Structured outputs มีให้ใช้งานในโมเดลล่าสุดของ OpenAI โดยเริ่มต้นจากตระกูล GPT-4o และต่อเนื่องไปถึงซีรีส์ GPT-5 เอกสารของ OpenAI ปัจจุบันแนะนำให้เริ่มต้นโปรเจกต์ใหม่บนโมเดลเรือธงล่าสุด (gpt-5.5 ในขณะที่เขียน) โมเดลรุ่นเก่าและโมเดลยุค gpt-3.5 รองรับโหมด JSON แต่ไม่รองรับการบังคับใช้ schema แบบเข้มงวด หากคุณพึ่งพา strict: true โปรดยืนยันว่า ID โมเดลเฉพาะรองรับคุณสมบัตินี้ก่อนที่คุณจะนำไปใช้งาน เนื่องจากคุณสมบัตินี้เชื่อมโยงกับเวอร์ชันของโมเดล และ OpenAI จะอัปเดตเวอร์ชันเหล่านี้ไปข้างหน้า
เป็นประโยชน์ที่จะรู้ว่าคุณกำลังใช้คุณสมบัติใดอยู่จริง ๆ เพราะ OpenAI มีสองคุณสมบัติที่เกี่ยวข้องกันซึ่งอาจทำให้สับสนได้ง่าย
โหมด JSON (response_format: { "type": "json_object" }) รับประกันว่าผลลัพธ์เป็น JSON ที่ถูกต้องตามหลักไวยากรณ์ แค่นั้นเอง มันไม่รู้จักฟิลด์ของคุณ, ประเภทของคุณ หรือคีย์ที่คุณต้องการ คุณยังคงต้องตรวจสอบรูปแบบด้วยตัวเอง
Structured outputs (response_format ที่มี type: "json_schema" และ strict: true) รับประกันว่าผลลัพธ์เป็น JSON ที่ถูกต้อง และ ตรงกับ schema ของคุณ OpenAI อธิบาย structured outputs ว่าเป็นการพัฒนาของโหมด JSON: ทั้งสองสร้าง JSON ที่ถูกต้อง แต่มีเพียง structured outputs เท่านั้นที่บังคับใช้ตาม schema สำหรับงานใหม่ คุณควรเลือก structured outputs
| โหมด JSON | Structured outputs (เข้มงวด) | |
|---|---|---|
| พารามิเตอร์ | response_format: {"type":"json_object"} |
response_format ที่มี type: "json_schema", strict: true |
| JSON ที่ถูกต้อง | ใช่ | ใช่ |
| ตรงกับ schema ของคุณ | ไม่ | ใช่ |
| บังคับใช้ฟิลด์ที่จำเป็น | ไม่ | ใช่ |
| บังคับใช้ประเภทและ enum | ไม่ | ใช่ |
| คุณยังคงต้องตรวจสอบความถูกต้องในขั้นตอนถัดไป | เสมอ | แนะนำ (ดูด้านล่าง) |
ข้อควรทราบเกี่ยวกับ API: ปลายทาง Chat Completions ใช้ response_format ดังที่แสดงด้านบน ส่วน Responses API รุ่นใหม่จะแสดงสิ่งเดียวกันภายใต้ text.format พร้อมด้วย type: "json_schema" กฎของ schema เหมือนกัน; แตกต่างกันแค่ส่วนห่อหุ้มเท่านั้น ตรวจสอบเอกสารปัจจุบันสำหรับเส้นทางฟิลด์ที่แน่นอนบนปลายทางที่คุณเรียกใช้
ทำการร้องขอครั้งแรกของคุณ
สมมติว่าคุณกำลังดึงข้อมูลตั๋วสนับสนุนออกมาเป็นบันทึกที่มีประเภท นี่คือคำขอ Chat Completions พร้อม 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
}
}
}
}'
อ่านผลตอบกลับ
โมเดลจะส่งข้อความกลับมา ซึ่ง content เป็นสตริง JSON ที่ตรงกับ schema นั้น ตัวอย่างเช่น:
{
"summary": "Checkout returns HTTP 500 when paying with a saved card",
"category": "bug",
"severity": 3,
"account_id": "acct_8842"
}
สังเกตว่า account_id ใช้ anyOf กับ null นั่นคือวิธีที่คุณสร้างฟิลด์เสริม ซึ่งนำไปสู่กฎที่คุณต้องปฏิบัติตามเมื่อคุณเขียน schema ของคุณเอง
อยู่ภายในกลุ่มย่อยของ Schema
Structured outputs รองรับกลุ่มย่อยของ JSON Schema การมีกลุ่มย่อยนี้เพื่อให้ OpenAI สามารถบังคับใช้ข้อจำกัดได้อย่างน่าเชื่อถือและแคช schema ที่คอมไพล์แล้ว กฎที่ควรจดจำ:
- รูทต้องเป็นออบเจกต์ คุณไม่สามารถทำให้ระดับบนสุดเป็นอาร์เรย์หรือสตริงเปล่าได้ ห่อหุ้มรายการในคุณสมบัติของออบเจกต์
- ทุกคุณสมบัติจะต้องอยู่ในรายการ
requiredไม่มี "optional" ในความหมายปกติ หากต้องการทำให้ฟิลด์เป็นค่าว่างได้ (nullable) ให้ใช้anyOfกับประเภทnullดังในตัวอย่างข้างต้น additionalPropertiesต้องเป็นfalseสำหรับทุกออบเจกต์ สิ่งนี้จะป้องกันไม่ให้โมเดลสร้างคีย์เพิ่มเติม- มีข้อจำกัดเรื่องขนาด Schema สามารถมีคุณสมบัติของออบเจกต์ได้ประมาณ 100 รายการ โดยมีการซ้อนกันสูงสุด 5 ระดับ Schema ที่ซ้อนกันลึกเกินไปหรือกว้างเกินไปจะถูกปฏิเสธ ดังนั้นควรทำให้แบนราบเท่าที่จะทำได้
- คีย์เวิร์ดบางตัวไม่ถูกบังคับใช้ คีย์เวิร์ดที่ใช้สำหรับการตรวจสอบความถูกต้องเท่านั้น เช่น
pattern,format,minLengthและminimumไม่ได้รับการรับประกันจากโมเดล หากคุณต้องการให้ regex หรือช่วงตัวเลขถูกบังคับใช้ คุณยังคงต้องตรวจสอบด้วยตัวเองหลังจากที่ได้รับผลตอบกลับ - ความหน่วงในการเรียกใช้ครั้งแรก คำขอแรกที่มี schema ใหม่จะใช้เวลาในการคอมไพล์ (โดยปกติเป็นวินาที บางครั้งอาจถึงหนึ่งนาทีสำหรับ schema ที่ซับซ้อน) หลังจากนั้นจะถูกแคชและทำงานได้เร็วขึ้น
เนื่องจากคีย์เวิร์ดการตรวจสอบความถูกต้องไม่ถูกบังคับใช้ คำว่า "JSON ที่รับประกัน" จึงไม่ได้หมายถึง "ธุรกิจที่รับประกันว่าถูกต้อง" โครงสร้างถูกล็อกแล้ว ค่าภายในยังคงควรได้รับการทดสอบ หากคุณเคยสร้างแบบจำลอง ฟิลด์เสริมหรือฟิลด์รวมด้วย oneOf/anyOf/allOf รูปแบบทางความคิดก็จะคุ้นเคย: schema จะจำกัดรูปร่าง แต่คุณยืนยันค่าจริงแยกต่างหาก
จัดการกับการปฏิเสธและการตัดทอน
มีกรณีหนึ่งที่ผลลัพธ์จะไม่ตรงกับ schema ของคุณโดยเจตนา หากโมเดลปฏิเสธคำขอที่ไม่ปลอดภัย มันจะคืนค่าฟิลด์ refusal ในข้อความแทนเนื้อหาที่เป็นไปตาม schema โค้ดของคุณควรแยกการทำงานตามเงื่อนไขนี้ก่อนที่จะ parsing:
msg = response.choices[0].message
if msg.refusal:
handle_refusal(msg.refusal)
else:
ticket = json.loads(msg.content)
ตอนนี้การปฏิเสธสามารถตรวจจับได้ด้วยโปรแกรม ซึ่งสะอาดกว่าการสแกนข้อความเพื่อหาคำขอโทษ มีอีกสองวิธีที่ผลตอบกลับอาจไม่เป็นไปตาม schema: การถึง max_tokens กลางออบเจกต์ (JSON จะถูกตัดทอน) หรือการใช้การเรียกใช้เครื่องมือแบบขนาน ซึ่ง structured outputs ไม่รองรับ ตั้งค่า parallel_tool_calls เป็น false เมื่อคุณรวมทั้งสองสิ่งนี้
วิธีทดสอบใน Apidog
โหมดเข้มงวดจะบังคับใช้ schema ณ เวลาสร้าง ไม่ได้ทำให้คุณไม่ต้องทดสอบ โมเดลอาจถูกสลับ, schemas อาจเปลี่ยนแปลง, เพื่อนร่วมทีมอาจแก้ไขอาร์เรย์ required หรือเส้นทางการปฏิเสธอาจเปลี่ยนไป คุณต้องการการทดสอบที่ส่งสัญญาณความล้มเหลวดังขึ้นเมื่อผลตอบกลับไม่ตรงตามสัญญา นั่นคือสิ่งที่ Apidog เข้ามามีบทบาท

เพื่อความแม่นยำในการแบ่งงาน: โหมดเข้มงวดของ OpenAI คือสิ่งที่สร้าง JSON ที่ถูกต้องตาม schema ส่วน Apidog ไม่ได้บังคับใช้ schema ที่โมเดล สิ่งที่ Apidog ทำคือตรวจสอบความถูกต้องของ ผลตอบกลับที่คุณได้รับ เทียบกับ schema ที่คุณคาดหวัง เพื่อให้คุณสามารถตรวจจับความเบี่ยงเบนได้ใน CI แทนที่จะเป็นในเวอร์ชันที่ใช้งานจริง
นี่คือขั้นตอนการทำงาน:
- ส่งคำขอ สร้างการเรียก Chat Completions ใน Apidog ด้วยบล็อก
response_formatของคุณ บันทึกไว้ในคอลเล็กชันเพื่อให้สามารถทำซ้ำได้ - ยืนยันรูปแบบ เพิ่มการยืนยันผลตอบกลับใน Apidog ตรวจสอบว่า
categoryเป็นหนึ่งในค่า enum ของคุณ, ว่าseverityเป็นจำนวนเต็ม, ว่าaccount_idเป็นสตริงหรือ null Apidog สามารถ ตรวจสอบความถูกต้องของผลตอบกลับเทียบกับ JSON Schema ได้ เพื่อให้คุณแนบ schema ที่แน่นอนและทำให้การทำงานล้มเหลวเมื่อ payload เบี่ยงเบน - รันใน CI ใส่คอลเล็กชันใน pipeline ของคุณ เพื่อให้ทุกการเปลี่ยนแปลงโมเดลหรือ prompt จะตรวจสอบความสอดคล้องอีกครั้ง การเปลี่ยนแปลง schema ที่เงียบหายไปจะกลายเป็นการสร้างที่ล้มเหลว
- จำลองสัญญา ก่อนที่การเรียกจริงจะถูกสร้างขึ้น หรือเพื่อทดสอบผู้บริโภคปลายทางโดยไม่ต้องใช้โทเค็น ให้ตั้งค่า mock API ที่คืนค่าผลตอบกลับตัวอย่างที่ถูกต้องตาม schema ส่วนหน้าและชุดทดสอบของคุณจะทำงานกับรูปแบบที่เสถียรในขณะที่การผสานรวมกำลังถูกทำให้แข็งแกร่งขึ้น
ประเด็นสุดท้ายคือสิ่งที่ถูกประเมินค่าต่ำไป คุณสามารถพัฒนาและทดสอบทุกสิ่งที่ ใช้ structured output กับ mock ที่เคารพ schema เดียวกัน จากนั้นจึงสลับใช้การเรียก OpenAI สดเมื่อคุณพร้อม ดาวน์โหลด Apidog แล้วคุณจะสามารถสร้างคำขอ, การยืนยัน และ mock ได้ในที่เดียว
คำถามที่พบบ่อย
- ตอนนี้โหมด JSON ถูกเลิกใช้แล้วหรือไม่เมื่อมี structured outputs? โหมด JSON ยังคงใช้งานได้และยังคงรับประกัน JSON ที่ถูกต้อง เพียงแต่ไม่บังคับใช้ schema สำหรับโค้ดใหม่ structured outputs ที่มี
strict: trueเป็นทางเลือกที่แข็งแกร่งกว่า ใช้โหมด JSON ธรรมดาเฉพาะกับโมเดลที่ไม่รองรับ strict schemas หรือเมื่อคุณไม่มีรูปแบบที่กำหนดไว้จริง ๆ - รูทของ schema ของฉันสามารถเป็นอาร์เรย์ได้หรือไม่? ไม่ได้ ระดับบนสุดต้องเป็นออบเจกต์ ห่อหุ้มรายการของคุณใน property เช่น
{ "items": [...] }และใส่itemsในrequiredนี่เป็นสิ่งที่ผู้คนจำนวนมากสับสนในวันแรก - ฉันจะทำให้ฟิลด์เป็นทางเลือกได้อย่างไร? Structured outputs กำหนดให้ทุก property ต้องอยู่ใน
requiredดังนั้นจึงไม่มีฟิลด์ทางเลือกแบบคลาสสิก สร้างแบบจำลอง "การหายไป" ให้เป็น nullable: ใช้anyOfกับstring(หรือประเภทใดก็ตาม) และnullคีย์จะปรากฏอยู่เสมอ; ค่าของมันสามารถเป็นnullได้ - โหมดเข้มงวดหมายความว่าฉันสามารถข้ามการตรวจสอบความถูกต้องทั้งหมดได้หรือไม่? โครงสร้างได้รับการรับประกัน ดังนั้นคุณสามารถข้ามการตรวจสอบรูปร่างได้ แต่คีย์เวิร์ดเช่น
pattern,formatและช่วงตัวเลขไม่ได้รับการบังคับใช้โดยโมเดล และการปฏิเสธหรือการตัดทอนยังคงสามารถสร้างผลตอบกลับที่ผิดปกติได้ การทดสอบความสอดคล้องยังคงมีความจำเป็น หากคุณยังใหม่กับรูปแบบนี้ บทนำ JSON Schema นี้จะครอบคลุมส่วนประกอบพื้นฐาน และคุณสามารถเรียกใช้การตรวจสอบได้ในการปรับใช้ทุกครั้ง - ฉันควรใช้โมเดลใด? Structured outputs ใช้งานได้กับ GPT-4o และรุ่นที่ใหม่กว่า รวมถึงซีรีส์ GPT-5 เอกสารของ OpenAI ชี้ให้โปรเจกต์ใหม่ ๆ ใช้โมเดลเรือธงปัจจุบันของพวกเขา ยืนยันว่า ID โมเดลที่แน่นอนรองรับโหมดเข้มงวดก่อนที่จะพึ่งพามัน เนื่องจากคุณสมบัตินี้ติดตามเวอร์ชันของโมเดล
สรุป
ตอนนี้คุณมีวงจรที่สมบูรณ์แล้ว: เลือกโมเดลที่รองรับโหมดเข้มงวด, ส่งคำขอ Chat Completions ด้วย json_schema และ strict: true, เก็บ schema ของคุณให้อยู่ในกลุ่มย่อยที่รองรับ, แยกการทำงานเมื่อเกิด refusal, และจำไว้ว่ากฎระดับค่า (value-level rules) ยังคงต้องได้รับการตรวจสอบ จากนั้นพิสูจน์ด้วยการทดสอบ: สร้างคำขอใน Apidog, ยืนยันผลตอบกลับเทียบกับ schema ของคุณ, และจำลอง (mock) เพื่อให้ส่วนที่เหลือของระบบของคุณสามารถดำเนินการต่อได้ในขณะที่การผสานรวมกำลังเข้าที่ โมเดลให้คำมั่นเรื่องรูปร่าง การทดสอบของคุณพิสูจน์ว่ามันคงอยู่เช่นนั้น
