บังคับ JSON จาก AI: valid ยังไม่พอถ้าไม่ตรง schema

|ผู้เขียน: กองบรรณาธิการ QUASA|3 นาทีในการอ่าน
บังคับ JSON จาก AI: valid ยังไม่พอถ้าไม่ตรง schema

หากต้องการให้คำตอบ AI ตรง JSON Schema ให้ใช้ Structured Outputs กับคำตอบที่แอปจะรับ และใช้ strict tool use เมื่อโมเดลส่งพารามิเตอร์เพื่อเรียกเครื่องมือ ตามคู่มือ OpenAI JSON mode ช่วยให้ผลลัพธ์เป็น JSON ที่ parse ได้ แต่ไม่รับประกันว่าฟิลด์และชนิดข้อมูลจะตรง schema ที่กำหนด ความต่างนี้สำคัญทันทีเมื่อแอปนำค่าที่ได้ไปบันทึกหรือส่งต่อให้ฟังก์ชัน

ก่อนใช้ผลลัพธ์ ให้แยกคำถามออกเป็นสามชั้น: ข้อความ parse ได้หรือไม่ ออบเจ็กต์ตรง schema หรือไม่ และค่าที่อยู่ในออบเจ็กต์ถูกต้องตามข้อมูลต้นทางกับกฎของงานหรือไม่ คำตอบที่ผ่าน parser อาจขาดฟิลด์บังคับ ส่วนคำตอบที่ผ่าน schema ก็ยังอาจอ้างถึงคำสั่งซื้อที่ไม่มีอยู่จริง การบังคับรูปแบบจึงเป็นส่วนหนึ่งของเส้นทางรับข้อมูล ไม่ใช่คำอนุญาตให้ข้ามการตรวจของแอป

เลือกกลไกจากหน้าที่ของผลลัพธ์

จุดตัดสินใจคือโมเดลกำลังส่งคำตอบให้แอป หรือกำลังขอให้แอปเรียกฟังก์ชัน ถ้าแอปต้องการออบเจ็กต์สำหรับแสดงผล เก็บข้อมูล หรือประมวลผลต่อ ให้กำหนด schema ของคำตอบด้วย Structured Outputs ถ้าโมเดลต้องเลือกเครื่องมือและส่งอาร์กิวเมนต์ ให้กำหนด schema ในเครื่องมือนั้นแล้วเปิด strict การเห็นข้อความหน้าตาคล้าย JSON เหมือนกันไม่ได้หมายความว่าทั้งสองเส้นทางควบคุมข้อมูลที่จุดเดียวกัน

  • JSON mode: เลือกเมื่อโจทย์ต้องการ JSON ที่อ่านด้วย parser ได้ และแอปพร้อมตรวจ schema เองหลังรับคำตอบ เหมาะกับกรณีที่ยังใช้รูปแบบคำตอบแบบมี schema ไม่ได้ แต่ต้องมีเส้นทางจัดการค่าที่ตรวจไม่ผ่าน
  • Structured Outputs: เลือกเมื่อคำตอบของโมเดลต้องมีคีย์ ชนิดข้อมูล และค่าจำกัดตาม schema ที่บริการรองรับ ก่อนแอปนำออบเจ็กต์ไปใช้
  • Strict tool use: เลือกเมื่อข้อมูลนั้นเป็น input ของการเรียกเครื่องมือที่โมเดลสร้างขึ้น ให้ตรวจการเกิด tool call และเงื่อนไขของแอปก่อนลงมือทำงาน

สมมติว่าหน้ารับคำสั่งซื้อให้โมเดลสกัดข้อมูลจากข้อความ แล้วแอปเป็นฝ่ายตัดสินใจว่าจะบันทึกหรือไม่ ข้อมูลที่สกัดได้ยังเป็นคำตอบของโมเดล จึงอยู่ในเส้นทาง structured response แต่ถ้าโมเดลได้รับสิทธิ์เลือกฟังก์ชันสำหรับส่งคำสั่งซื้อเอง ออบเจ็กต์เดียวกันจะกลายเป็นพารามิเตอร์ของเครื่องมือ ความต่างนี้กำหนดว่าควรวาง schema ตรงไหน และควรดักผลลัพธ์ก่อนเกิดผลข้างเคียงตรงจุดใด

ใช้ schema เดียวกันแยก JSON ที่อ่านได้ออกจากข้อมูลที่ใช้ได้

ตัวอย่างสมมติต่อไปนี้กำหนดข้อมูลคำสั่งซื้อด้วยฟิลด์ order_id ซึ่งเป็นสตริง quantity ซึ่งเป็นจำนวนเต็ม และ currency ซึ่งรับค่า THB เท่านั้น: {"type":"object","properties":{"order_id":{"type":"string"},"quantity":{"type":"integer"},"currency":{"type":"string","enum":["THB"]}},"required":["order_id","quantity","currency"],"additionalProperties":false} นี่เป็นสัญญาเรื่องรูปข้อมูลของตัวอย่าง ไม่ใช่หลักฐานว่ามีคำสั่งซื้อนั้นอยู่ในระบบ

ค่า {"order_id":"A123","quantity":"2","currency":"THB"} เป็น JSON ที่ parse ได้ แต่ quantity เป็นสตริง จึงผิดข้อกำหนดจำนวนเต็ม หากเปลี่ยนเป็น 2 โดยไม่ใส่เครื่องหมายคำพูด ข้อผิดพลาดเรื่องชนิดข้อมูลจะหายไป แต่ยังต้องตรวจฟิลด์อื่นต่อ การแปลงสตริงเป็นตัวเลขโดยอัตโนมัติในแอปอาจทำให้ข้อมูลที่โมเดลส่งผิดสัญญาผ่านเข้าระบบโดยไม่มีใครเห็น ควรกำหนดให้ชัดว่าจะปฏิเสธหรือแปลงค่า และใช้กฎเดียวกันทุกทางเข้า

ตามคำอธิบายออบเจ็กต์ของ JSON Schema การใส่ชื่อฟิลด์ใน properties ยังไม่ทำให้ฟิลด์นั้นจำเป็นต้องมี; required เป็นตัวกำหนดฟิลด์บังคับ และ additionalProperties ใช้ควบคุมฟิลด์ที่ไม่ได้ประกาศ ดังนั้นออบเจ็กต์ที่ขาด currency หรือมีฟิลด์อื่นเพิ่มจะยัง parse ได้ แต่จะไม่ผ่าน schema ตัวอย่าง ตรวจสองรายการนี้แยกกัน โดยเฉพาะเมื่อออบเจ็กต์มีข้อมูลซ้อนหลายชั้น เพราะกฎที่รากไม่ได้ระบุรายละเอียดของฟิลด์ภายในออบเจ็กต์ลูกให้เอง

ใน Structured Outputs ฟิลด์ทั้งหมดต้องอยู่ใน required และออบเจ็กต์ต้องกำหนด additionalProperties เป็น false หากข้อมูลบางรายการไม่มีค่า ให้ใช้ชนิดข้อมูลที่ยอมรับ null ตามรูปแบบที่รองรับ แทนการปล่อยให้ฟิลด์หายไป วิธีนี้ทำให้ผู้รับแยกได้ระหว่าง “ไม่มีค่า” กับ “ผลลัพธ์ไม่ครบ” ก่อนแก้ schema ที่ใช้อยู่จริง ควรตรวจข้อกำหนดของบริการและรุ่นโมเดล เพราะการเป็น JSON Schema ที่ถูกต้องตามมาตรฐานไม่ได้แปลว่า API ทุกแห่งรับ keyword ชุดเดียวกัน

วาง schema ในตำแหน่งที่ API ใช้บังคับจริง

สำหรับคำตอบแบบมีโครงสร้างใน Responses API ให้ใส่ schema ใน text.format ชนิด json_schema พร้อม strict ตามรูปแบบของ API ส่วน Chat Completions ใช้ response_format ชนิด json_schema การเขียนคำสั่งในพรอมป์ว่า “ตอบตาม schema” ช่วยบอกความต้องการของงาน แต่ไม่ใช่ตัวแทนการกำหนดรูปแบบผ่าน API เมื่อรับผลลัพธ์แล้ว แอปควรอ่านช่องข้อมูลที่ใช้สำหรับคำตอบของ API นั้นหลังตรวจสถานะการจบ ไม่หยิบข้อความทุกส่วนมาต่อกันแล้วสมมติว่าเป็นออบเจ็กต์สำเร็จ

หากใช้ JSON mode ใน Responses API รูปแบบที่ส่งคือ text.format ชนิด json_object และควรสั่งให้โมเดลสร้าง JSON อย่างชัดเจนในบทสนทนา จากนั้นแอปต้อง parse ผล ตรวจ schema และกำหนดว่าจะทำอย่างไรเมื่อข้อมูลผิดรูปแบบ การขอออบเจ็กต์ที่มี order_id, quantity และ currency ในพรอมป์เพียงอย่างเดียวไม่ได้ป้องกัน quantity กลายเป็นสตริง หรือ currency กลายเป็นค่าที่ระบบไม่รับ

เมื่อโมเดลต้องเรียกเครื่องมือด้วย Claude ให้วาง schema ของตัวอย่างใน input_schema และตั้ง strict: true ไว้ที่ระดับนิยามเครื่องมือ คู่มือ strict tool use ของ Claude อธิบายว่าเมื่อมี tool_use ชื่อเครื่องมือจะเป็นชื่อที่ใช้ได้ และ input จะตรงกับส่วนของ JSON Schema ที่รองรับ โดยจำกัดการสร้างผลลัพธ์ตามไวยากรณ์ ขอบเขตการรับประกันนี้อยู่ที่พารามิเตอร์ของการเรียกเครื่องมือ ไม่ได้แปลงข้อความตอบทั่วไปให้เป็น structured response

การมีพารามิเตอร์ที่ตรง schema ยังไม่ใช่คำสั่งให้ฟังก์ชันทำงานทันที ตัวจัดการ tool call ต้องตรวจว่าเครื่องมือที่ถูกเลือกเหมาะกับคำขอนั้น ผู้ใช้มีสิทธิ์ทำรายการ และตัวระบุที่ได้รับอยู่ในขอบเขตที่อนุญาต ตัวอย่างเช่น order_id อาจเป็นสตริงถูกชนิดและ quantity เป็นจำนวนเต็ม แต่ผู้ใช้ไม่มีสิทธิ์แก้คำสั่งซื้อนั้น การตรวจสิทธิ์และการค้นข้อมูลจริงจึงต้องอยู่ก่อนคำสั่งเขียนฐานข้อมูลหรือเรียกบริการภายนอก

จัดการข้อจำกัดของ schema และผลลัพธ์ที่ไม่สมบูรณ์

ก่อนนำ schema จากไลบรารีทั่วไปไปใส่ API ให้ดูว่า keyword ที่ใช้อยู่รองรับหรือไม่ Structured Outputs รองรับ JSON Schema เพียงบางส่วน และ schema ที่มีรูปแบบไม่รองรับอาจถูกปฏิเสธตั้งแต่ส่งคำขอ ตัวอย่างการใช้เงื่อนไขประกอบหลายชั้นอาจต้องย้ายไปตรวจในแอป ส่วน strict tool use ก็มีขอบเขตของ schema ที่รองรับเช่นกัน หากระบบต้องอาศัยกฎเฉพาะจำนวนมาก ให้แยกกฎที่ API บังคับได้ออกจากกฎที่ตัวตรวจของแอปต้องรับผิดชอบ

ข้อจำกัดนี้มีผลกับความหมายของค่าในตัวอย่างด้วย enum ที่รับ THB ทำให้ currency เป็นค่าอื่นไม่ได้ตาม schema แต่ไม่ได้พิสูจน์ว่าต้นทางระบุสกุลเงินจริงเป็นบาท และชนิด integer ก็ไม่ได้บอกว่า quantity มากกว่าศูนย์ เพราะ schema ตัวอย่างไม่ได้กำหนดเงื่อนไขนั้น แม้เพิ่มข้อจำกัดเชิงตัวเลขในรูปแบบที่บริการรองรับ ระบบก็ยังต้องดูว่าจำนวนสินค้าที่ผู้ใช้ขอสอดคล้องกับข้อมูลต้นทางและกฎการขายหรือไม่

เส้นทางรับคำตอบต้องแยกการปฏิเสธออกจากข้อมูลสำเร็จ การปฏิเสธอาจไม่อยู่ในรูป schema ที่ร้องขอ จึงควรตรวจสัญญาณ refusal ก่อนนำข้อความไป parse อีกกรณีคือการสร้างคำตอบถูกตัดเพราะถึงขีดจำกัดผลลัพธ์หรือหยุดด้วยเหตุผลอื่น ส่วนที่ได้รับอาจดูคล้าย JSON ที่เกือบครบ แต่ไม่ควรถูกบันทึกเป็นรายการสำเร็จ เพียงเพราะตัวแปลงบางชั้นอ่านข้อความบางส่วนได้

  1. ตรวจว่าคำขอ API สำเร็จและการสร้างคำตอบจบสมบูรณ์ตามสถานะหรือเหตุผลที่ API ส่งกลับ
  2. แยก refusal และกรณีผลลัพธ์ถูกตัดออกจากเส้นทางข้อมูลปกติ โดยกำหนดผลที่ผู้ใช้และระบบจะได้รับ
  3. สำหรับคำตอบทั่วไป ให้ parse และตรวจ schema; สำหรับ tool use ให้ตรวจว่ามีการเรียกเครื่องมือที่คาดหวัง แล้วอ่าน input ของการเรียกนั้น
  4. ตรวจค่ากับข้อมูลต้นทาง สิทธิ์ และกฎธุรกิจ ก่อนเขียนฐานข้อมูลหรือทำงานที่ย้อนกลับยาก

หากจะลองสร้างคำตอบใหม่หลังถูกตัด ให้แยกขั้นสร้างข้อมูลออกจากขั้นลงมือทำงาน โดยเฉพาะเมื่อฟังก์ชันเกี่ยวข้องกับการชำระเงิน การแก้รายการ หรือการส่งข้อความ การผูกคำขอกับตัวระบุสำหรับป้องกันการทำซ้ำเป็นทางเลือกของการออกแบบระบบที่ช่วยไม่ให้การลองใหม่ทำงานซ้ำโดยไม่ตั้งใจ ส่วนการปฏิเสธควรเดินเส้นทางของการปฏิเสธ ไม่ใช่ส่งเข้าตัวตรวจ schema แล้วรายงานว่าโมเดลตอบผิดชนิดข้อมูล

ตรวจความจริงของข้อมูลก่อนรับเข้าระบบ

สำหรับตัวอย่างคำสั่งซื้อ แอปยังต้องตรวจว่า order_id มีอยู่จริงและเป็นของผู้ใช้ที่ทำรายการ quantity อยู่ในช่วงที่ระบบยอมรับ และ currency ตรงกับคำสั่งซื้อหรือแหล่งข้อมูลที่ใช้สกัด หากข้อความต้นทางไม่ได้ระบุข้อมูลบางอย่าง การบังคับให้โมเดลเติมฟิลด์ครบอาจได้ค่าในชนิดที่ถูกต้องแต่เป็นค่าที่เดาขึ้น ควรกำหนดวิธีแทนข้อมูลที่ไม่ทราบไว้ในสัญญาของข้อมูล และไม่ปล่อยให้ค่าที่เดาได้ผ่านเป็นข้อเท็จจริง

ชุดทดสอบสำหรับทางรับข้อมูลควรครอบคลุมกรณีที่ต่างกันจริง ได้แก่ JSON ที่ parse ได้แต่ผิดชนิด ฟิลด์บังคับหาย ฟิลด์ส่วนเกิน ค่า enum ผิด การปฏิเสธ และคำตอบที่ถูกตัด ผลที่คาดหวังของแต่ละกรณีควรชัดว่าระบบปฏิเสธข้อมูล ขอคำตอบใหม่ หรือส่งให้ตรวจด้วยวิธีอื่น การแยกสาเหตุเช่นนี้ทำให้แก้ข้อผิดพลาดได้ตรงชั้น: parser จัดการไวยากรณ์ schema จัดการโครงสร้าง และแอปจัดการความถูกต้องของรายการก่อนเกิดผลในระบบจริง

อ่านเพิ่มเติม:

แชร์:

สมัครรับจดหมายข่าวของเรา

รับข่าวสารล่าสุดเกี่ยวกับ Web3, AI และคริปโตส่งตรงถึงกล่องจดหมายของคุณ

0