ตัดสินที่ผลลัพธ์ ไม่ใช่เส้นทาง
บทที่ 1 สรุปว่า agent ตัดสินกันที่ผลลัพธ์เพราะมันหลายขั้นตอนและไม่นิ่งข้ามรอบ บทที่ 2 แยกความล้มเหลวออกเป็นหมวดๆ เพื่อรู้ว่าจะแก้อะไรก่อน ทีนี้พอลงมือเขียน eval จริง สัญชาตญาณแรกที่เกือบทุกคนมีคือ “จดลำดับ step ที่ถูกต้องไว้ แล้วเช็กว่า agent เดินตามนั้นเป๊ะไหม” — เรียก lookup_order ก่อน แล้วค่อย check_refund_policy แล้วจึง issue_refund ถ้าเดินครบตามลำดับก็นับผ่าน ฟังดูเข้มงวดดี แต่บทนี้จะอธิบายว่าทำไมมันถึงเป็นกับดัก และทำไม Anthropic ถึงปฏิเสธวิธีนี้เป็นค่าเริ่มต้น
บทนี้ยังใช้ ops-copilot agent ที่คืนเงินออเดอร์ใน domain Order เดิมจาก repo kaen-food-ordering (กำลังจัดทำ) เป็นตัวอย่างเดินเรื่อง — คอร์สนี้เป็นคอร์สเชิงวิธีคิด สเก็ตช์ code ที่เห็นเป็นภาพร่างของ eval (rubric / การเทียบสถานะ / schema ของ tool) เพื่อสื่อไอเดีย ไม่ใช่ eval harness ที่รันได้ทันที
ทำไมการเช็กลำดับ step เป๊ะๆ ถึงเปราะ
หัวข้อที่มีชื่อว่า “ทำไมการเช็กลำดับ step เป๊ะๆ ถึงเปราะ”ก่อนอื่นตั้งชื่อสิ่งที่เรากำลังพูดถึงให้ชัด: TrajectoryTrajectoryลำดับขั้นตอนจริงที่ agent เดินผ่านระหว่างทำงาน (เรียก tool ไหน คิดอะไร ตัดสินใจอย่างไร) ก่อนถึงผลลัพธ์สุดท้าย — เช็คทีละก้าวยังมีประโยชน์เป็นตาข่ายเสริมด้านความปลอดภัย (เช่น เช็คว่าไม่เคยเรียก tool คืนเงินโดยไม่มีการอนุมัติ) แต่ไม่ควรใช้แทนการเช็ค outcome เป็นหลัก เพราะเข้มเกินไปกับ agent ที่มีหลายเส้นทางที่ถูกต้องพร้อมกันArchitecture คือลำดับขั้นตอนจริงที่ agent เดินผ่านระหว่างทำงาน — เรียก tool ตัวไหน ด้วย parameter อะไร คิดอะไร ตัดสินใจอย่างไร ก่อนจะถึงผลลัพธ์สุดท้าย การ “diff เส้นทาง” คือการเทียบ trajectory ที่ agent เดินจริงกับเส้นทางทองที่เราวางไว้ล่วงหน้า ถ้าไม่ตรงเป๊ะก็ตก
Anthropic พูดถึงสัญชาตญาณนี้ตรงๆ ว่า “There is a common instinct to check that agents followed very specific steps like a sequence of tool calls in the right order. We’ve found this approach too rigid and results in overly brittle tests.” — มันเข้มเกินไปและได้ test ที่เปราะ คำแนะนำของเขาคือ “grade what the agent produced, not the path it took.” คือตัดสินจากสิ่งที่ agent ทำให้เกิดขึ้น ไม่ใช่เส้นทางที่มันเดิน (ดู Anthropic, “Demystifying evals for AI agents”)
เหตุผลที่มันพังกับ agent โดยเฉพาะย้อนกลับไปที่คุณสมบัติจากบทที่ 1: agent ไม่ deterministic ให้ query เดิมเป๊ะ มันก็เดินไปถึงคำตอบที่ถูกต้องได้หลายเส้นทาง — เปลี่ยนลำดับ tool เปลี่ยน subagent ที่เรียก เปลี่ยนจำนวนก้าว แต่ปลายทางถูกเหมือนกัน Anthropic สรุปว่า “this variability requires evaluation methodologies that focus on outcomes rather than process compliance.” — ความแปรผันนี้บังคับให้ต้องวัดกันที่ผลลัพธ์ ไม่ใช่ความยอมตามกระบวนการ (ดู Anthropic, “How we built our multi-agent research system”)
ลองดูกับ ops-copilot: การคืนเงินออเดอร์หนึ่งจะเช็ก policy ก่อนแล้วค่อย lookup ออเดอร์ หรือ lookup ก่อนแล้วค่อยเช็ก policy ก็ได้ทั้งคู่ — ผลลัพธ์ที่ถูกต้องอันเดียวกัน แต่ถ้าเราเอา trajectory ไป diff กับเส้นทางทองเส้นเดียว รอบที่สลับลำดับอย่างถูกต้องจะตกทันที นี่คือ ❌ version ดิบ: golden-trajectory diffing — มันลงโทษความหลากหลายที่ไม่ได้ผิดอะไรเลย
flowchart TB START["คำสั่ง: คืนเงินออเดอร์ 123 เป็นเงิน 120 บาท"] START --> A1["รอบ A ขั้นที่ 1: lookup_order"] START --> B1["รอบ B ขั้นที่ 1: check_refund_policy"] A1 --> A2["ขั้นที่ 2: check_refund_policy"] B1 --> B2["ขั้นที่ 2: lookup_order"] A2 --> A3["ขั้นที่ 3: issue_refund"] B2 --> B3["ขั้นที่ 3: issue_refund"] A3 --> ENDST["สถานะปลายทางเดียวกัน<br/>มีแถวคืนเงินออเดอร์ 123 จำนวน 120 บาท ในฐานข้อมูล"] B3 --> ENDST ENDST --> JUDGE["Outcome-based Eval ตัดสินที่นี่<br/>ผ่านทั้งสองเส้นทาง"] classDef good fill:#16a34a,stroke:#065f46,color:#f8fafc; classDef path fill:#1e3a5f,stroke:#1e40af,color:#f8fafc; class ENDST,JUDGE good; class A1,A2,A3,B1,B2,B3 path;
คำบรรยายภาพ: คำสั่งเดียวกัน สองเส้นทางที่ถูกต้องต่างกัน — รอบ A เช็กออเดอร์ก่อนแล้วค่อยเช็ก policy รอบ B สลับกัน ทั้งคู่จบลงที่สถานะปลายทางเดียวกันคือมีแถวคืนเงินออเดอร์ 123 จำนวน 120 บาทในฐานข้อมูล ถ้าตัดสินด้วยการ diff เส้นทางกับเส้นทางทองเส้นเดียว เส้นใดเส้นหนึ่งจะตกทั้งที่คืนเงินสำเร็จ แต่ถ้าตัดสินที่ end-state (กล่องเขียว) ทั้งสองเส้นทางผ่าน เพราะสิ่งที่เราสนใจจริงๆ คือปลายทาง ไม่ใช่ทางที่เดินมา
outcome คือสถานะจริงของสภาพแวดล้อม ไม่ใช่คำพูดของ agent
หัวข้อที่มีชื่อว่า “outcome คือสถานะจริงของสภาพแวดล้อม ไม่ใช่คำพูดของ agent”ทีนี้มาถึงหัวใจ: Outcome-based EvalOutcome-based Evalการตัดสินจาก 'สถานะสุดท้ายของสภาพแวดล้อมจริง' หลัง agent ทำงานเสร็จ เช่น มีแถวคืนเงินของออเดอร์นั้นในฐานข้อมูลจริงหรือยัง ไม่ใช่จากคำบรรยายว่า agent 'บอกว่าทำเสร็จแล้ว' — เป็นค่าเริ่มต้นที่แนะนำ เพราะ agent หลายเส้นทางไปถึงผลลัพธ์ที่ถูกต้องเหมือนกันได้โดยไม่จำเป็นต้องเดินเหมือนกันProcess คือการตัดสินจากสถานะสุดท้ายที่เกิดขึ้นจริงต่อสภาพแวดล้อมหลัง agent ทำงานเสร็จ ไม่ใช่จากคำที่ agent บรรยายว่าตัวเองทำสำเร็จ และไม่ใช่จากการ diff เส้นทางที่มันเดิน จุดที่ต้องแยกให้ขาดมีสองด้าน — outcome ไม่ใช่ “คำพูด” และ outcome ไม่ใช่ “เส้นทาง”
τ-bench ทำสิ่งนี้ให้เห็นเป็นรูปธรรม: มันไม่ได้อ่านว่า agent พิมพ์อะไรออกมา แต่ตัดสินด้วยการเทียบ “the database state at the end of a conversation with the annotated goal state” — เทียบสถานะฐานข้อมูลตอนจบบทสนทนากับสถานะเป้าหมายที่มนุษย์ระบุไว้ (ดู τ-bench (arXiv 2406.12045)) สถานะเป้าหมายที่มนุษย์ระบุไว้ก้อนนั้นคือ Ground TruthGround Truthคำตอบหรือพฤติกรรมที่ 'ถูกต้องจริง' ตามการตรวจสอบของมนุษย์ผู้เชี่ยวชาญ ใช้เป็นหลักอ้างอิงเทียบกับ output ของ agent ใน Golden Dataset — ถ้า ground truth เองยังคลุมเครือ eval ที่เทียบกับมันก็เชื่อถือไม่ได้ตั้งแต่ต้นProcess ของเคส — คำตอบที่ “ถูกต้องจริง” ที่เราเอาไว้เทียบ ถ้า ground truth เองยังคลุมเครือ eval ที่วัดเทียบกับมันก็เชื่อถือไม่ได้ตั้งแต่ต้น
กลับมาที่ ops-copilot คำถามที่ eval ควรถามไม่ใช่ “agent บอกว่าคืนเงินแล้วหรือยัง” แต่เป็น “ตอนนี้มีแถวคืนเงินของออเดอร์ #123 ในฐานข้อมูลจริง จำนวน ฿120 หรือยัง” เทียบสองสเก็ตช์นี้:
// สเก็ตช์เพื่อสื่อไอเดีย ไม่ใช่ code ที่รันได้จริง — เทียบสองวิธีตัดสินผลเดียวกัน
// version ดิบ: golden-trajectory diffing — บังคับให้ลำดับ tool ตรงกับเส้นทางทองที่วางไว้const goldenPath = ["lookup_order", "check_refund_policy", "issue_refund"];markPass(deepEqual(agentTrace.toolCalls, goldenPath));// ❌ รอบที่เช็ก policy ก่อน lookup (เส้นทางถูกต้องอีกเส้น) จะตกทั้งที่คืนเงินสำเร็จ — เปราะ
// version ที่วัด outcome: ดูสถานะจริงของฐานข้อมูลหลัง agent ทำงานเสร็จconst row = db.refunds.findOne({ orderId: 123 });markPass(row != null && row.amount === 120);// ✅ สนใจแค่ว่าปลายทางถูกไหมเทียบกับ ground truth ไม่สนว่าเดินมาทางไหนversion ดิบตกทุกรอบที่ agent เดินเส้นทางถูกต้องแต่ไม่ตรงลำดับทอง — มันเปราะเพราะเข้าใจผิดว่า “เส้นทางเดียว” เท่ากับ “ถูกต้อง” ส่วน version ที่วัด outcome ถามคำถามที่ตรวจสอบได้กับสถานะจริง จึงยอมรับทุกเส้นทางที่พาไปถึงปลายทางที่ถูก นี่คือเหตุผลที่การตัดสินจากผลลัพธ์เป็นค่าเริ่มต้นของคอร์สนี้
เป็นค่าเริ่มต้น ไม่ใช่กฎตายตัว — per-step check ยังมีที่ยืน
หัวข้อที่มีชื่อว่า “เป็นค่าเริ่มต้น ไม่ใช่กฎตายตัว — per-step check ยังมีที่ยืน”แต่ต้องระวังอย่าเหวี่ยงสุดทาง “ตัดสินที่ผลลัพธ์” ไม่ได้แปลว่า “ห้ามดูเส้นทางเลย” มันเป็น ค่าเริ่มต้น ไม่ใช่กฎสัมบูรณ์ แนวทางของ Anthropic เองก็ยังเก็บบทบาทให้การเช็ก trajectory และการเช็กนโยบายทีละก้าวไว้ — การไล่อ่าน transcript หรือเช็กว่าแต่ละก้าวไม่ละเมิดข้อบังคับด้านความปลอดภัยนั้น “มีประโยชน์บ่อยครั้ง” โดยเฉพาะกับ coding agent
เส้นแบ่งอยู่ตรงนี้: outcome เป็นแกนหลักที่ตัดสินว่างานสำเร็จไหม ส่วน per-step check เป็น ตาข่ายเสริมด้านความปลอดภัย ที่คอยรักษาไม่ให้ agent ทำสิ่งที่ยอมรับไม่ได้ระหว่างทาง — ต่อให้ปลายทางถูกก็ตาม ตัวอย่างกับ ops-copilot ที่ชัดที่สุด: “agent เคยเรียก tool คืนเงินโดยไม่ผ่านการอนุมัติของผู้จัดการไหม” ต่อให้จำนวนเงินสุดท้ายในฐานข้อมูลถูกเป๊ะ ถ้ามันข้ามขั้นอนุมัติไปคืนเงินก้อนใหญ่เองก็คือพฤติกรรมที่รับไม่ได้ การเช็กแบบนี้ต้องดูที่เส้นทาง ไม่ใช่แค่ปลายทาง
ความต่างจาก version ดิบข้างบนอยู่ที่เจตนา: golden-trajectory diff เอาเส้นทางมาเป็น เกณฑ์ตัดสินความสำเร็จ (ผิดลำดับ = งานไม่สำเร็จ) ซึ่งเปราะ ส่วน per-step safety check เอาเส้นทางมาเป็น เกณฑ์ด้านความปลอดภัยที่เป็นเกณฑ์รอง (ละเมิดข้อบังคับ = เตือนภัย ไม่ว่าผลจะถูกไหม) สองอย่างนี้ดูเส้นทางเหมือนกันแต่ถามคนละคำถาม จำไว้ว่า outcome คือเกณฑ์หลัก per-step check คือเกณฑ์รองที่รักษาความปลอดภัย ไม่ใช่ตัวแทนของ outcome
สรุป และทางไปบทหน้า
หัวข้อที่มีชื่อว่า “สรุป และทางไปบทหน้า”บทนี้ตอบว่า eval ควรวัด “อะไร”: วัดที่สถานะจริงของสภาพแวดล้อมปลายทางเทียบกับ ground truth ไม่ใช่คำที่ agent พูด และไม่ใช่การ diff เส้นทางทีละก้าว เพราะ agent เดินไปถึงผลลัพธ์ที่ถูกต้องได้หลายเส้นทาง — บังคับให้ตรงลำดับเดียวคือ test ที่เปราะ ส่วนการเช็กเส้นทางยังมีที่ยืนในฐานะตาข่ายความปลอดภัยที่เป็นเกณฑ์รอง ไม่ใช่เกณฑ์หลัก
คำถามถัดไปคือ “แล้วใครเป็นคนตัดสินว่า outcome ผ่านเกณฑ์” บางเคสเทียบสถานะฐานข้อมูลตรงๆ ด้วย code ก็จบ (เหมือนสเก็ตช์ข้างบน) แต่หลายเคสผลลัพธ์เป็นข้อความยาวๆ ที่ “ถูก” ได้หลายแบบจนเขียนเงื่อนไขตายตัวไม่ไหว บทที่ 4 จะว่าด้วย LLM-as-judge — เมื่อไรควรใช้ LLM อีกตัวมาเป็นผู้ตัดสิน เมื่อไรตัวเช็กแบบ deterministic ดีกว่า และทำไม judge ถึงไม่ใช่ผู้ตัดสินที่เชื่อได้เองโดยอัตโนมัติจนกว่าจะ calibrate กับมนุษย์ก่อน
บทนี้สังเคราะห์จากสามแหล่งหลัก อ่านต่อได้ที่ต้นทางโดยตรง:
- Anthropic, “Demystifying evals for AI agents” — คำแนะนำให้ “grade what the agent produced, not the path it took” และเหตุผลว่าการเช็กลำดับ step เป๊ะเป็น “too rigid… brittle”
- Anthropic, “How we built our multi-agent research system” — agent เดินได้หลายเส้นทางที่ถูกต้อง จึงต้องวัดที่ผลลัพธ์ ไม่ใช่ความยอมตามกระบวนการ (อ้างเพื่อ วิธีการ; ตัวเลข 90.2% ใน post นั้นเป็นผลจาก eval set ภายในของ Anthropic เอง ไม่ใช่ benchmark อิสระ จึงไม่หยิบมาอ้างเป็นตัวเลขสมรรถนะ)
- τ-bench (arXiv 2406.12045) — ตัดสินด้วยการเทียบสถานะฐานข้อมูลปลายทางกับสถานะเป้าหมาย (ground truth) อ้างเพื่อ วิธีการเทียบ end-state; ตัวเลขคะแนนของ GPT-4o ในเปเปอร์เป็นผลปี 2024 ถือเป็นข้อมูลเก่า
เช็กความเข้าใจ — บทที่ 3
ข้อ 1 / 3ทำไมการ diff เส้นทาง (เทียบลำดับ step กับเส้นทางทองเส้นเดียว) ถึงเปราะเมื่อใช้กับ agent?