หลักการสำคัญ

  • เมื่อต้องสร้าง Natural Language API สำหรับโปรดักชัน จำเป็นต้องแยก semantic parsing ออกจาก execution
  • ใช้ LLM เฉพาะสำหรับแปลงภาษาธรรมชาติ → คำขอแบบมีโครงสร้าง (canonical structured requests) เท่านั้น
  • ควรมองภาษาธรรมชาติเป็นเพียงอินพุต ไม่ควรใช้เป็นสัญญา API โดยตรง (ภาษาเปราะบาง)

ปัญหาของการใช้ภาษาธรรมชาติโดยตรง

  • พฤติกรรมที่ไม่กำหนดแน่นอน (nondeterministic behavior)
  • บิซิเนสลอจิกที่อิงพรอมป์ต์ → ดีบักและทำซ้ำเพื่อทดสอบได้ยาก
  • สัญญา API โดยนัย → การเปลี่ยนแปลงเพียงเล็กน้อยอาจทำให้พฤติกรรมเปลี่ยน
  • เกิดความล้มเหลวแบบเงียบ (silent failures) ทำให้ระบบเปราะบาง

สถาปัตยกรรม: แยกเป็น 2 เลเยอร์

1. Semantic Parse API (ภาษาธรรมชาติ → แปลงเป็นโครงสร้าง)

  • รับข้อความอินพุตจากผู้ใช้
  • ใช้ LLM เพื่อดึง intent และ entities
  • เติม schema ที่กำหนดไว้ล่วงหน้าให้ครบ
  • หากข้อมูลไม่พอ ให้ถามคำถามเพื่อ clarification (ห้ามรันบิซิเนสลอจิก)
  • ทำหน้าที่เหมือนคอมไพเลอร์ (เช่น “blue backpack but cheaper” → {intent: “recommend_similar”, reference_product_id: “blue_backpack_123”, price_bias: -0.8})

2. Structured Execution API (โครงสร้าง → การทำงาน)

  • รับเฉพาะอินพุตที่มีโครงสร้างเท่านั้น
  • เป็นแบบกำหนดแน่นอน มีการจัดการเวอร์ชัน และทดสอบได้
  • ไม่มีการประมวลผลภาษาธรรมชาติ ทำหน้าที่เป็นแบ็กเอนด์ที่เสถียร

องค์ประกอบสำคัญ: Canonical Schemas

  • สัญญาแยกตาม intent ที่นิยามไว้ในโค้ด (ฟิลด์บังคับ/ไม่บังคับ ช่วงค่าที่รับได้ กฎการตรวจสอบความถูกต้อง)
  • ดูดซับความหลากหลายของภาษาธรรมชาติ → รับประกันเอาต์พุตที่สม่ำเสมอ
  • ทำหน้าที่เป็น backbone ของสัญญา API

Schema Completion (Clarification)

  • หากข้อมูลไม่ครบ ให้ตอบกลับเป็น “needs_clarification” (missing fields, targeted question, current state)
  • จัดการหน่วยความจำด้วย state object (ตัว API เป็น stateless)
  • ไคลเอนต์ส่งต่อ state เพื่อคงบทสนทนาไว้ → เมื่อครบแล้วจึงรัน canonical_request

การออร์เคสเตรต: ใช้ LangGraph

  • โมเดลเวิร์กโฟลว์แบบมีโครงสร้าง (จัดประเภท intent → ดึง entities → รวม schema → ตรวจสอบความถูกต้อง → route ไปยัง complete/clarification)
  • การตัดสินใจอยู่บนโค้ด ส่วน LLM ทำได้แค่เสนอ
  • มีการเปลี่ยนสถานะที่ชัดเจน สังเกตการณ์ได้ และรีทรายอย่างปลอดภัย

กลไกความปลอดภัย: Confidence Gates

  • บังคับให้ LLM ส่งค่า confidence score มาด้วย
  • หากต่ำกว่า threshold ให้บล็อกการทำงานและขอ clarification (เช่น “the bag” ที่กำกวม → ความเชื่อมั่นต่ำ → ถามเพิ่ม)
  • ป้องกันการตีความผิดแบบเงียบ ๆ

การทำให้เป็นมาตรฐาน: Lightweight Ontologies

  • อิงโค้ดเป็นหลัก (intent ที่อนุญาต, synonym mappings, cross-field validation)
  • ค่าที่ LLM เสนอ → ทำ normalization ด้วยโค้ด (เช่น “cheaper” → price_bias: -0.7)
  • หากตรรกะไม่สอดคล้องกัน ให้ clarification (เช่น cheap + high quality ให้ถามลำดับความสำคัญ)

ข้อพิจารณาด้านประสิทธิภาพ

  • เวลาแฝง: การจัดประเภท intent ~40ms, การดึง entities ~200ms, การตรวจสอบ 1ms → รวม 250300ms
  • ยอมรับได้สำหรับ UX แบบแชต และต้นทุนยังต่ำกว่าค่าใช้จ่ายจากความผิดพลาด

บทเรียนสำคัญ (Key Takeaways)

  • ภาษาไม่ใช่สัญญา API ต้องแปลงให้เป็นโครงสร้าง
  • ฝั่งเซิร์ฟเวอร์ต้องเป็นเจ้าของการทำ schema completion
  • ใช้ LLM เฉพาะกับ discovery และ extraction ไม่ใช่ execution
  • ให้ความสำคัญสูงสุดกับความปลอดภัยและความเป็น deterministic
  • อิงจากประสบการณ์จริงในการสร้างระบบด้วย Azure OpenAI + LangGraph

https://aisparkup.com/posts/9012

ยังไม่มีความคิดเห็น

ยังไม่มีความคิดเห็น