Eval-driven development (ข้อถกเถียงจริง)
เจ็ดบทที่ผ่านมาสอน “วิธี” ทำ eval ให้ถูก บทสุดท้ายนี้ถามคำถามที่เถียงกันไม่จบ: เมื่อไร ควรเขียน eval — ก่อนสร้าง agent หรือหลัง หัวใจของบทนี้คือ EvalEvalการวัดผลอย่างเป็นระบบว่า output ของ AI agent (เช่น ops-copilot) ถูกต้องและมีประโยชน์จริงหรือไม่ ด้วยชุดเกณฑ์และกรณีทดสอบที่ชัดเจน แทนการดูจากความรู้สึกว่า 'ตอบดูดี' — จำเป็นเพราะ agent เป็นระบบหลายขั้นตอนที่ความผิดพลาดสะสมทบกันได้ และแต่ละรอบก็ไม่ได้เดินทางเดิมเป๊ะทุกครั้งProcess — การวัดความสำเร็จของ agent อย่างเป็นระบบด้วยเกณฑ์และเคสที่ชัดเจน — ควรถูกเขียน “ณ จุดไหน” ของวงจรพัฒนา และคำตอบของแหล่งอ้างอิงชั้นต้นสองแหล่งที่น่าเชื่อถือทั้งคู่ ขัดกันตรงๆ
บทนี้จึงไม่ได้สอนวิธีเดียวแล้วปิดจบ มันวางข้อถกเถียงจริงลงบนโต๊ะ ให้เห็นทั้งสองฝ่ายโดยระบุชื่อ แล้วค่อยชี้ว่าอะไรทำให้ทั้งคู่ถูกในบริบทของตัวเอง เพราะสิ่งที่ ADVANCED ต้องได้จากบทนี้ไม่ใช่ “เชื่อใคร” แต่เป็นวิจารณญาณว่าจะเลือกวิธีไหนเมื่อยืนอยู่ในสถานการณ์แบบไหน
บทนี้ใช้ ops-copilot agent ที่คืนเงินออเดอร์ใน domain Order จาก repo kaen-food-ordering (กำลังจัดทำ) เป็นตัวอย่างเดินเรื่อง เป็นบทเชิงวิธีคิด (design/methodology) สเก็ตช์ที่เห็น — eval spec, ลำดับการทำงาน — เป็น ภาพร่างเพื่อสื่อไอเดีย ไม่ใช่ eval harness ที่รันได้ทันที
ฝ่ายสนับสนุน: Anthropic กับ eval-driven development
หัวข้อที่มีชื่อว่า “ฝ่ายสนับสนุน: Anthropic กับ eval-driven development”Anthropic สนับสนุน ให้เขียน eval ก่อน เขาเขียนไว้ตรงๆ ว่าให้ “build evals to define planned capabilities before agents can fulfill them, then iterate until the agent performs well” — สร้าง eval เพื่อ นิยาม capability ที่วางแผนไว้ก่อนที่ agent จะทำมันได้ แล้วค่อย iterate จนกว่าจะผ่าน (ดู Anthropic, “Demystifying evals for AI agents”)
วงจรที่เขาเสนอเดินตามลำดับนี้: นิยามความสำเร็จ → ออกแบบ task → สร้าง grader → รัน trial → วิเคราะห์ transcript → iterate แล้ววนกลับ พูดอีกแบบคือ eval มาก่อน ความสามารถตามทีหลัง เหมือนเขียน test ที่ยังแดงไว้รอ แล้วค่อยเขียน code ให้มันเขียว
ในโลก ops-copilot สิ่งนี้หมายความว่า: ก่อนจะมี tool refund ด้วยซ้ำ เราเขียน eval ที่นิยามว่า “คืนเงินสำเร็จ” แปลว่าอะไรไว้ก่อน — และนิยามนั้นต้องวัดที่ outcome จริง ไม่ใช่คำพูดของ agent:
# สเก็ตช์ eval spec (ไม่ใช่ file ที่รันได้จริง)# เขียน 'ก่อน' มี tool refund ตามแนว eval-driven ของ Anthropiccase: "คืนเงินออเดอร์ #123 จำนวน ฿120"input: "ลูกค้าขอคืนเงินออเดอร์ #123 เพราะร้านยกเลิก"success: # นิยาม 'ความสำเร็จ' ล่วงหน้า — วัดที่สถานะจริงของฐานข้อมูล db.refunds: orderId: 123 amount: 120 # ✅ ต้องมีแถวคืนเงินของออเดอร์นี้จริง จำนวนถูกต้อง ห้ามเชื่อ: "ข้อความ agent ว่า 'คืนเงินเรียบร้อย'" # version ดิบ — ผ่านลวงตาได้เหตุผลที่แนวนี้ใช้ได้: ในงาน greenfield เรา รู้เป้าหมายล่วงหน้า อยู่แล้ว โจทย์ “คืนเงินให้ถูกออเดอร์ ถูกจำนวน” ไม่ต้องรอเห็น production trace ก็เขียนเกณฑ์ความสำเร็จได้ครบ eval ที่เขียนไว้ก่อนจึงทำหน้าที่เป็นทั้ง spec และเป้าเล็งให้การ iterate
post multi-agent ของ Anthropic รายงานว่าระบบใหม่ดีขึ้น “90.2%” เหนือ single-agent — แต่ตัวเลขนี้วัดกับ eval set ภายในของ Anthropic เอง ไม่ใช่ benchmark อิสระ ให้หยิบ post นี้มาอ้างเพื่อ วิธีการ (loop นิยาม→สร้าง grader→iterate) ไม่ใช่เพื่อยกตัวเลขไปเคลมว่า agent เก่งระดับนั้นแบบพกพาได้ (ดู Anthropic, “multi-agent research system”)
ฝ่ายค้าน: Hamel กับ “Generally no”
หัวข้อที่มีชื่อว่า “ฝ่ายค้าน: Hamel กับ “Generally no””Hamel Husain ถูกถามตรงๆ ว่าควรทำ eval-driven development ไหม คำตอบสั้น: “Generally no.” — ส่วนใหญ่ไม่ควร เหตุผลของเขาคือ “LLMs have infinite surface area for potential failures. You can’t anticipate what will break.” LLM มีพื้นที่ผิวของความล้มเหลวที่กว้างไม่สิ้นสุด คุณคาดเดาไม่ได้หรอกว่าอะไรจะพัง (ดู Hamel, “Should I practice eval-driven development?”)
หัวใจคำค้านของเขาอยู่ที่การกลับลำดับ: “Write evaluators for errors you discover, not errors you imagine.” — เขียน evaluator สำหรับ error ที่คุณ เจอจริง ไม่ใช่ error ที่คุณ จินตนาการ ขึ้นเอง เพราะถ้าเขียน eval จากจินตนาการ คุณจะเสียแรงไล่ดักปัญหาที่อาจไม่เคยเกิด ขณะที่ปัญหาจริงซึ่งคาดไม่ถึงกลับหลุดรอด
นี่คือ Error AnalysisError Analysisการนั่งอ่าน trace ที่ agent ทำงานจริงทีละเคสเพื่อหาว่าอะไรพังจากอะไร เน้นจับ 'ความผิดพลาดแรกสุด' ในแต่ละ trace ก่อนเสมอ เพราะความผิดพลาดต้นทางมักลากให้พังต่อเป็นทอด ๆ — เป็นจุดเริ่มต้นของ eval ที่ดี ไม่ใช่การมองแค่ dashboard ตัวเลขรวม และควรทำซ้ำทุก 2-4 สัปดาห์Process — การนั่งอ่าน trace ที่ agent ทำงานจริงทีละเคส หา “ความผิดพลาดแรกสุด” ในแต่ละ trace แล้วเขียน evaluator ให้จับ ปัญหานั้น โดยเฉพาะ ในมุมของ Hamel eval ไม่ใช่สิ่งที่คุณเขียนไว้ล่วงหน้าเพื่อบอกว่า agent ควรทำอะไร แต่เป็นสิ่งที่คุณสกัดออกมาจากสิ่งที่ agent ทำพลาดไปแล้วจริงๆ ลำดับจึงเป็น “รันก่อน แล้วค่อยขุด error มาเป็น eval” ตรงข้ามกับ “เขียน eval ก่อน แล้วค่อยสร้าง”
ทั้งสองฝ่ายไม่ได้ขัดกันจริง — มันขึ้นกับ context
หัวข้อที่มีชื่อว่า “ทั้งสองฝ่ายไม่ได้ขัดกันจริง — มันขึ้นกับ context”จุดที่คลี่คลายข้อถกเถียงนี้ไม่ใช่ “ใครถูก” แต่คือ context ต่างกัน ทั้งคู่พูดถูกในสถานการณ์ของตัวเอง:
- แนว Anthropic เข้าทาง greenfield — ระบบที่ยังไม่มีอะไรรันจริง เรา รู้เป้าหมายล่วงหน้า (คืนเงินให้ถูกออเดอร์ ถูกจำนวน) จึงเขียน eval “refund สำเร็จ” ไว้ก่อนมี tool refund ได้เต็มปาก ไม่มี production trace ให้ขุดก็ยังมีเกณฑ์ความสำเร็จที่ชัดพอจะเล็ง
- แนว Hamel เข้าทางระบบที่รันจริงแล้ว — เมื่อมี production trace เป็นกอง การเดา error ล่วงหน้ากลายเป็นการเสียแรง เพราะปัญหาจริงจำนวนมากคาดไม่ถึง ให้ทำ error analysis ขุดจาก trace จริงแล้วเขียน evaluator ตามสิ่งที่เจอ จะได้ eval ที่ตรงปัญหากว่ามาก
และ Hamel เองก็เปิดช่องให้แนว greenfield ในกรณีข้อจำกัดแคบๆ ที่ชัดเจน — เขาบอกว่าถ้าจะเพิ่มกฎอย่าง “never mention competitors” การเขียน evaluator สำหรับกฎนั้นไว้แต่เนิ่นๆ “may be acceptable” พูดง่ายๆ คือเมื่อเป้าหมายชัดและแคบพอจะเขียนเป็นเกณฑ์ตายตัวได้ตั้งแต่ต้น การเขียน eval ก่อนก็ไม่ผิด — ซึ่งกลับไปบรรจบกับตรรกะ greenfield ของ Anthropic พอดี
flowchart TB
START["คำถาม: เขียน eval 'ก่อน' หรือ 'หลัง' สร้าง agent?"]
START --> A["ฝ่าย Anthropic — สนับสนุน eval-driven<br/>เขียน eval นิยามความสำเร็จ ก่อน agent ทำได้<br/>แล้ว iterate จนผ่าน"]
START --> H["ฝ่าย Hamel — 'Generally no'<br/>เขียน evaluator จาก error ที่ 'เจอจริง'<br/>ไม่ใช่ error ที่ 'จินตนาการ'"]
A --> Q{"อยู่ในบริบทไหน?"}
H --> Q
Q -->|"ยังไม่มี — greenfield<br/>รู้เป้าหมายล่วงหน้า"| USEA["ใช้แนว Anthropic:<br/>เขียน eval 'refund สำเร็จ' ก่อนมี tool refund"]
Q -->|"มีแล้ว — ระบบรันจริง"| USEH["ใช้แนว Hamel:<br/>error analysis หา error จริงก่อน แล้วค่อยเขียน evaluator"]
Q -->|"เป้าหมายแคบ+ชัดตายตัว เช่น 'ห้ามพูดถึงคู่แข่ง'"| BOTH["เขียน evaluator ไว้แต่เนิ่น ๆ ได้<br/>(จุดที่ทั้งสองฝ่ายบรรจบกัน)"]
classDef pos fill:#1e3a8a,stroke:#1e293b,color:#f8fafc;
class USEA,USEH,BOTH pos;
คำบรรยายภาพ: สองจุดยืนออกจากคำถามเดียวกัน — เขียน eval ก่อนหรือหลัง ฝ่าย Anthropic สนับสนุน eval-driven (เขียนก่อน) ฝ่าย Hamel ค้านลำดับนั้น (ขุดจาก error จริงก่อน) ตัวชี้ขาดว่าใช้อันไหนไม่ใช่ “ใครน่าเชื่อกว่า” แต่คือ context: greenfield ที่รู้เป้าล่วงหน้าเข้าทาง Anthropic ระบบที่มี production trace ให้ขุดเข้าทาง Hamel และเมื่อเป้าหมายแคบและชัดตายตัว ทั้งสองฝ่ายก็บรรจบกันที่ “เขียน evaluator ไว้ก่อนได้”
แต่ evaluator ที่คุณเขียนไม่ใช่ oracle
หัวข้อที่มีชื่อว่า “แต่ evaluator ที่คุณเขียนไม่ใช่ oracle”ไม่ว่าจะเข้าทางไหน มีกับดักหนึ่งที่ทั้งสองฝ่ายเห็นตรงกัน: evaluator ที่คุณเขียนขึ้นไม่ใช่ผู้ตัดสินที่เชื่อได้เองโดยอัตโนมัติ โดยเฉพาะถ้ามันเป็น LLM-as-judge ตัว judge มีอคติที่ วัดได้จริง — เอนเอียงตามลำดับที่เห็นก่อน (position bias) ตามความยาวคำตอบ (verbosity bias) และชอบ output จาก model ตระกูลเดียวกับตัวเอง (self-enhancement bias) ตามที่งาน MT-Bench รายงานไว้ ดังนั้น evaluator ที่เขียนไว้ล่วงหน้าแบบ greenfield ก็ยังต้อง calibrate ก่อนไว้ใจ
วิธี calibrate ที่ถูกคือดู TPR/TNR (จับ “ผ่านจริง” และ “พังจริง” ได้แม่นแค่ไหน แยกกัน) เทียบกับป้ายที่มนุษย์ผู้เชี่ยวชาญให้ไว้ ไม่ใช่ดู % ที่ตรงกับมนุษย์รวมๆ เพราะถ้าเคสพังมีน้อย judge ที่ตอบ “ผ่าน” ไปเรื่อยก็ได้คะแนนตรงกันสูงลวงตาทั้งที่จับอะไรไม่ได้เลย และไม่ว่าจะ calibrate ดีแค่ไหน มนุษย์ที่นั่งอ่าน trace ก็ยังจับความล้มเหลวคนละชนิดที่ automation มองข้ามได้เสมอ — judge คือ เครื่องมือที่ต้องคอยสอบเทียบ ไม่ใช่ oracle ประเด็นนี้คือเหตุผลที่บท 4 (LLM-as-judge) กับบท 6 (error analysis) ต้องอ้างถึงกันไปมา และเป็นสิ่งที่ช่วยรักษาคุณภาพ eval ไว้ไม่ให้พึ่ง judge เพียงลำพัง
ปิดวง: context → harness → loop → eval
หัวข้อที่มีชื่อว่า “ปิดวง: context → harness → loop → eval”ทั้งคอร์สนี้ต่อยอดจากลำดับที่ซีรีส์บทความวางไว้ — context → harness → loop เราให้ context กับ model ห่อมันด้วย harness ที่ต่อ tool และขอบเขต แล้วปล่อยให้มันวนใน loop จนบรรลุเป้าหมาย บทนี้เติมชั้นสุดท้าย: eval คือสิ่งที่บอกว่าทั้งสามชั้นข้างต้นทำงานได้จริงหรือเปล่า และข้อถกเถียง eval-driven ก็คือคำถามว่าชั้นนี้ควรมาเมื่อไรในไทม์ไลน์ — คำตอบที่โตแล้วคือ “แล้วแต่ context” ไม่ใช่สูตรตายตัว
จากจุดนี้ ก้าวต่อไปคือลงไปสร้าง harness จริงให้ agent — ต่อ tool ให้มันลงมือกับโลกภายนอกอย่างปลอดภัย ซึ่งเป็นเรื่องของคอร์ส ออกแบบ MCP Server ที่ดี ที่มอง tool ทุกตัวเป็น Anti-Corruption Layer เมื่อ harness แน่นแล้ว วินัย eval ทั้งแปดบทนี้คือสิ่งที่ทำให้คุณรู้ว่ามันเชื่อถือได้จริง ไม่ใช่แค่ดูเหมือนทำงาน
ข้อถกเถียงในบทนี้มาจากแหล่งชั้นต้นสองแหล่งที่ควรอ่านเองทั้งคู่:
- Anthropic, “Demystifying evals for AI agents” — ฝ่ายสนับสนุน: สร้าง eval นิยาม capability ก่อน agent ทำได้ แล้ว iterate
- Hamel, “Should I practice eval-driven development?” — ฝ่ายค้าน: “Generally no” เขียน evaluator สำหรับ error ที่เจอจริง ไม่ใช่ที่จินตนาการ
- Anthropic, “multi-agent research system” — อ้างเพื่อ วิธีการ (loop นิยาม→grader→iterate) ตัวเลข 90.2% เป็น internal-eval ไม่ใช่ benchmark อิสระ
ข้อถกเถียง “เขียน eval ก่อนหรือหลัง” คือญาติสายตรงของข้อถกเถียง test-first ในโลก code — อ่านการ์ด Test-Driven Development (TDD) ที่ DevIQ เทียบเคียงได้: eval-driven development คือ TDD version ของ agent ที่ผลลัพธ์ไม่ deterministic ทำให้ “เขียน test ก่อน” มีเงื่อนไขมากกว่าเดิม
เช็กความเข้าใจ — บทที่ 8
ข้อ 1 / 3จุดยืนของ Anthropic ต่อ eval-driven development คืออะไร?