Quest 76 - Structured Output Parser
Quest 76: Structured Output Parser
medium 25-30 minutes🎯 Learning Objectives
- เข้าใจว่า LLMs มักใส่ JSON ใน markdown code blocks
- แยก JSON ออกจาก freeform text ได้อย่างน่าเชื่อถือ
- จัดการกับ malformed JSON และ type coercion
- สร้าง schema validation สำหรับ structured output
📖 Concept: Structured Output from LLMs
Structured Output คือเทคนิคการบังคับให้ LLM ตอบออกมาในรูปแบบที่ machine-readable — โดยปกติคือ JSON
ปัญหาคือ LLMs มักจะใส่ JSON ไว้ใน markdown code blocks:
```json{"name": "John", "age": "25"}```หรือบางทีก็ตอบ freeform text ปนกับ JSON ทำให้ code ที่จะ parse ต้องฉลาดพอที่จะแยกออก
ทำไมถึงสำคัญ: ถ้าคุณส่ง prompt ไปแล้วหวังว่าจะได้ JSON กลับมา คุณจะผิดหวัง — LLMs ไม่ได้ guarantee ว่าจะตอบ JSON เสมอไป Parser คือ safety net ของคุณ
⚙️ How It Works
กระบวนการ Parse Structured Output
LLM Response (freeform text) ↓1. ลอง JSON.parse() ตรงๆ ก่อน ↓ (ถ้าไม่ได้)2. ค้นหา JSON ใน markdown code blocks (```json ... ```) ↓ (ถ้าไม่เจอ)3. ค้นหา JSON objects ({...}) ใน text ↓ (ถ้าเจอ)4. JSON.parse() อีกครั้ง ↓5. Type coercion (string "42" → number 42) ↓6. Schema validation (required fields, types) ↓Return { parsed, errors, valid }Schema Definition
const schema = { name: { type: 'string', required: true }, age: { type: 'number', required: true }, is_active: { type: 'boolean', required: false }};💡 Example: Parser ใน Action
function parseStructuredOutput(text, schema) { let parsed = null; let jsonStr = text;
// Step 1: ลอง parse ตรงๆ try { parsed = JSON.parse(text); } catch (e) { // Step 2: หา JSON ใน markdown code block const codeBlockMatch = text.match(/```(?:json)?\s*([\s\S]*?)```/); if (codeBlockMatch) { jsonStr = codeBlockMatch[1].trim(); } else { // Step 3: หา JSON object ใน text const jsonMatch = text.match(/\{[\s\S]*\}/); if (jsonMatch) { jsonStr = jsonMatch[0]; } }
try { parsed = JSON.parse(jsonStr); } catch (e2) { return { parsed: null, errors: ['Invalid JSON: ' + e2.message], valid: false }; } }
// Step 4: Type coercion const errors = []; for (const [field, rules] of Object.entries(schema)) { if (rules.required && !(field in parsed)) { errors.push(`Missing required field: ${field}`); continue; } if (field in parsed && rules.type) { const val = parsed[field]; if (rules.type === 'number' && typeof val === 'string') { const num = Number(val); if (!isNaN(num)) parsed[field] = num; } if (rules.type === 'boolean' && typeof val === 'string') { if (val.toLowerCase() === 'true') parsed[field] = true; if (val.toLowerCase() === 'false') parsed[field] = false; } } }
return { parsed, errors, valid: errors.length === 0 };}
// ตัวอย่าง 1: JSON ใน code blockparseStructuredOutput( 'Here is the result:\n```json\n{"name": "John", "age": "25"}\n```\nHope this helps!', { name: { type: 'string', required: true }, age: { type: 'number', required: true } });// { parsed: { name: "John", age: 25 }, errors: [], valid: true }
// ตัวอย่าง 2: ไม่มี required fieldparseStructuredOutput( '{"name": "John"}', { name: { type: 'string', required: true }, age: { type: 'number', required: true } });// { parsed: { name: "John" }, errors: ["Missing required field: age"], valid: false }⚠️ Common Mistakes
Mistake 1: ไม่จัดการ JSON ใน code blocks
LLMs มักใส่ JSON ใน
json ...blocks → JSON.parse() จะ fail ถ้าไม่ extract ก่อน
Mistake 2: ไม่ทำ type coercion
LLM ตอบ
"age": "25"(string) แทน"age": 25(number) → code ที่ expect number จะ error
Mistake 3: ไม่ validate required fields
ได้ JSON กลับมาแล้วใช้เลยโดยไม่เช็ค fields → runtime error เมื่อเข้าถึง field ที่ไม่มี
Mistake 4: ไม่ handle malformed JSON
คิดว่า JSON.parse() จะสำเร็จเสมอ → LLMs บางครั้ง generate JSON ที่ syntax ผิด (missing comma, trailing comma)
📝 Knowledge Check
📝 Knowledge Check
Q1:ทำไม LLMs มักใส่ JSON ใน markdown code blocks?
Q2:Type coercion ใน structured output parser คืออะไร?
Q3:ขั้นตอนไหนควรทำก่อนในการ parse structured output?
🏋️ Quest: Structured Output Parser
ถึงเวลาฝึกฝน! สร้าง JSON parser ที่ฉลาดพอจะแยก JSON จาก LLM response
-
Download ไฟล์เริ่มต้นของ quest:
Terminal window npx bluebeltdojo download quest-76-structured-outputcd quest-76-structured-output -
เปิด
problem.jsใน editor ของคุณพร้อม AI assistant -
Implement
parseStructuredOutput(text, schema)ที่:- ลอง parse JSON ตรงๆ ก่อน
- หา JSON ใน markdown code blocks (
json ...) - หา JSON objects (
{...}) ใน text - ทำ type coercion (string → number, string → boolean)
- Validate required fields ตาม schema
-
ตรวจสอบ solution ของคุณ:
Terminal window node test.js -
เมื่อ tests ผ่านทั้งหมด ส่งคำตอบ:
Terminal window npx bluebeltdojo submit
💡 Tip: เริ่มจาก case ง่ายๆ (plain JSON) แล้วค่อยเพิ่ม code blocks — อย่าพยายามแก้ทุก edge case พร้อมกัน
คำใบ้
- Regex สำหรับ code block:
/```(?:json)?\s*([\s\S]*?)```/ - Regex สำหรับ JSON object:
/\{[\s\S]*\}/ - Type coercion: ใช้
Number(val)สำหรับ string → number,val.toLowerCase() === 'true'สำหรับ string → boolean - Validate หลัง coerce — ถ้า coerce ไม่ได้ให้ใส่ error message
- ทดสอบด้วย input หลายแบบ: plain JSON, JSON ใน code block, JSON ใน freeform text, missing fields