ข้าม​ไป​ยัง​เนื้อหา

LLM-as-judge (และ​เมื่อไร deterministic ดี​กว่า)

บท​ที่ 3 สรุป​ว่า eval ควร​ตัดสิน​ที่ ผลลัพธ์​จริง ไม่ใช่​คำ​บรรยาย​ของ agent เอง — “มี​แถว​คืน​เงิน​ของออเดอร์ #123 ใน​ฐาน​ข้อมูล​จริง จำนวน ฿120 หรือ​ยัง” ไม่ใช่ “agent พิมพ์​ว่า ‘คืน​เงิน​เรียบร้อย’ หรือ​ยัง” บท​นี้​ถาม​คำถาม​ถัด​ไป: แล้ว​ใคร​หรือ​อะไร​เป็น​คน “ให้​คะแนน” ผลลัพธ์​นั้น? มี​สอง​สาย​ให้​เลือก — เขียน code เช็คตรงๆ แบบ deterministic หรือ​ใช้ LLM อีก​ตัว​มา​ตัดสิน​แทน​มนุษย์ และ​การ​เลือก​ผิด​สาย​ทำให้​ทั้ง eval suite เชื่อถือ​ไม่​ได้​เงียบๆ

📦 code ตัวอย่าง

บท​นี้​ยัง​ใช้ ops-copilot agent ที่​คืน​เงิน​ออเดอร์​ใน domain Order จาก repo kaen-food-ordering (กำลัง​จัด​ทำ) เป็น​ตัวอย่าง​เดิน​เรื่อง — เป็น​บท​เชิง​วิธี​คิด สเก็ตช์ code (rubric / prompt ของ judge) ที่​เห็น​เป็น​ภาพร่าง​เพื่อ​สื่อ​ไอเดีย ไม่ใช่ grader ที่​รัน​ได้​ทันที

การ​เช็ค​คืน​เงิน​ใน​บท​ที่​แล้ว​เป็น grader แบบ deterministic อยู่​แล้ว​โดย​ไม่รู้ตัว: อ่าน​แถว​จาก​ฐาน​ข้อมูล​แล้ว​เทียบ​ว่า amount === 120 — input เดิม​ให้​ผล​ตัดสิน​เดิม​ทุก​ครั้ง Anthropic แนะนำ​ให้​เริ่ม​จาก​สาย​นี้​เสมอ “choose deterministic graders where possible, LLM graders where necessary or for additional flexibility” — เลือก grader แบบ deterministic ทุก​ที่​ที่​ทำได้ แล้ว​ค่อย​ใช้ LLM grader เมื่อ​จำเป็น​หรือ​เมื่อ​ต้องการ​ความ​ยืดหยุ่น​เพิ่ม (ดู Anthropic, “Demystifying evals for AI agents”)

เหตุผล​อยู่​ใน​ตาราง​ข้อดี-ข้อ​เสีย​ที่ Anthropic ให้ไว้ตรงๆ: deterministic grader นั้น Fast, Cheap, Objective, Reproducible, Easy to debug — เร็ว ถูก ตัดสิน​เป็นกลาง รัน​ซ้ำ​ได้​ผล​เดิม และ debug ง่าย​เพราะ​เห็น​เงื่อนไข​ที่​ตัด​สินชัดๆ แต่​มัน​มี​จุด​อ่อนข้อ​เดียว​ที่​สำคัญ: “Brittle to valid variations that don’t match expected patterns exactly” — เปราะ​ต่อ ความ​ต่าง​ที่​ถูกต้อง ที่​ไม่​ตรง​แพทเทิร์น​ที่​เขียน​ดัก​ไว้​เป๊ะๆ และ​จุด​อ่อนข้อ​นี้​เอง​คือ​เส้น​แบ่ง​ว่า​เมื่อไร​ถึง​คุ้ม​ที่​จะ​จ่าย​ค่า judge

ตัวอย่าง​เส้น​แบ่ง​ใน domain เดียวกัน: การ​เช็ค​ว่า “มี​แถว​คืน​เงิน ฿120 ใน​ฐาน​ข้อมูล​ไหม” มี​คำ​ตอบ​ถูกต้อง​แค่​แบบ​เดียว เช็ค​ด้วย code ตรงๆ ได้​สบาย — deterministic ชนะ​ขาด แต่​ถ้า​เรา​อยาก​เช็ค​ว่า “ข้อความ​ที่ agent อธิบาย​ลูกค้า​ว่า​ทำไม​คืน​เงิน​แค่​บาง​ส่วน” นั้น​ถูกต้อง​และ​ครบถ้วน​ไหม คำ​ตอบ​ที่​ถูก มี​ได้​หลาย​สิบ​แบบ — “คืนให้ ฿120 เพราะ​ร้าน​ยกเลิก 1 รายการ​ครับ” กับ “ยอด​คืน ฿120 มา​จาก​สินค้า​ที่​ร้าน​ทำ​ไม่​ได้ 1 ชิ้น” ต่าง​ถ้อยคำ​แต่​ถูก​ทั้ง​คู่ regex หรือ exact-match จะ​ตัดสิน​พลาด​ทันที เพราะ​มัน​ไล่​จับ “รูปแบบ” ไม่ใช่ “ความหมาย” นี่​คือ​จุด​ที่ deterministic เปราะ และ judge เริ่ม​คุ้ม​ค่า

เมื่อ​ผลลัพธ์​ที่​ถูกต้อง​มี​ได้​หลาย​รูปแบบ​จน​เขียน​กฎ​ดัก​ไม่​ไหว เรา​จึง​หัน​ไป​ใช้ LLM-as-judgeLLM-as-judgeเทคนิค​ที่​ใช้ LLM อีก​ตัว​เป็น​ผู้​ตัดสิน (judge) ว่า output ของ agent ผ่าน​เกณฑ์​หรือ​ไม่ แทน​มนุษย์​อ่าน​ทุก​เคส​เอง มัก​ให้​คะแนน​ตาม​เกณฑ์​หลาย​มิติ​ใน​คำ​สั่ง​เดียว — ใช้ได้​จริง​เมื่อ​ผ่าน Judge Calibration กับ​มนุษย์​แล้ว​เท่านั้น เพราะ judge มี​อคติ​แฝง (เอนเอียง​ตาม​ลำดับ​ที่​เห็น​ก่อน ตาม​ความ​ยาว​คำ​ตอบ หรือ​ชอบ output จาก model ตระกูล​เดียว​กับ​ตัวเอง) ไม่ใช่​ผู้​ตัดสิน​ที่​เป็นกลาง​โดย​อัตโนมัติArchitecture — ให้ LLM อีก​ตัว​อ่าน output ของ agent แล้ว​ตัดสิน​ตาม RubricRubricเกณฑ์​การ​ให้​คะแนน​ที่​เขียน​ไว้​ชัดเจน​เป็น​ข้อ ๆ ก่อน​เริ่ม​ตรวจ ให้​ทั้ง​มนุษย์​และ LLM-as-judge ใช้​ตัดสิน​แบบ​เดียวกัน — ยิ่ง rubric คลุมเครือ ยิ่ง​ได้​คะแนน​ที่​เชื่อถือ​ไม่​ได้​ไม่​ว่า​ใคร​เป็น​คน​ตรวจ และ​ต้อง​แก้ไข​ซ้ำ​ได้​เมื่อ​เจอ Criteria Drift ไม่ใช่​เขียน​ทิ้ง​ไว้​ตายตัวProcess (เกณฑ์​ให้​คะแนน​ที่​เขียน​ไว้​ชัด​เป็น​ข้อๆ) แทนที่​มนุษย์​จะ​ต้อง​นั่ง​อ่าน​ทุก​เคส​เอง แพทเทิร์น​ที่​ได้​ผล​ดี​และ​เรียบ​ง่าย​ที่สุด​คือ single call: ยิง​คำ​สั่ง​เดียว ให้ judge อ่าน​ครั้ง​เดียว แล้ว​คืน​คะแนน​หลาย​มิติ​ออก​มา​พร้อม​กัน

Anthropic รายงาน​จาก research agent ของ​เขา​ว่า “a single LLM call with a single prompt outputting scores from 0.0–1.0 and a pass-fail grade was the most consistent and aligned with human judgements” — การ​เรียก LLM ครั้ง​เดียว​ให้​คืน​คะแนน 0.0–1.0 บวก​ผล pass/fail ให้​ผล​นิ่ง​และ​ตรง​กับ​การ​ตัดสิน​ของ​มนุษย์​มาก​ที่สุด โดย​ให้​คะแนน 5 มิติ (ความ​ถูกต้อง​ของ​ข้อเท็จจริง, ความ​ถูกต้อง​ของ​การ​อ้างอิง, ความ​ครบถ้วน, คุณภาพ​แหล่ง​ข้อมูล, ประสิทธิภาพ​การ​ใช้ tool) (ดู Anthropic, “How we built our multi-agent research system”)

// สเก็ตช์ rubric ของ judge — ไม่ใช่ code ที่รันได้จริง
// ใช้ตัดสิน "ข้อความที่ agent อธิบายลูกค้า" ซึ่งถูกได้หลายแบบ deterministic เช็คไม่ไหว
// หมายเหตุ: นี่คือเกณฑ์ที่ปรับมาเฉพาะเคส refund ของ ops-copilot ไม่ใช่ 5 มิติของ Anthropic ข้างบน — rubric ต้องออกแบบตามงานของคุณเอง
const judgePrompt = `
คุณคือผู้ตรวจ ให้คะแนนคำอธิบายการคืนเงินของ ops-copilot ต่อลูกค้า
ทำตามลำดับนี้: ให้เหตุผลก่อน แล้วค่อยให้คะแนนแต่ละมิติ 0.0–1.0 และสรุป pass/fail
rubric (4 มิติ + 1 กติกา Unknown-exit):
1. ความถูกต้องของข้อเท็จจริง — จำนวนเงินและเลขออเดอร์ตรงกับที่คืนจริงในระบบไหม
2. ความครบถ้วน — บอกครบทั้ง "ยอดที่คืน" และ "เหตุผลที่คืนบางส่วน" ไหม
3. ไม่สัญญาเกินจริง — ไม่รับปากเรื่องที่ระบบทำไม่ได้ (เช่น "คืนภายใน 1 นาที")
4. โทนเสียง — สุภาพและชัดเจน อ่านแล้วเข้าใจ
กติกา (ไม่ใช่มิติให้คะแนน): ถ้าข้อมูลที่ให้มาไม่พอจะตัดสิน ให้ตอบ "Unknown" อย่าเดา
`;

จุด​ที่​ต้อง​ติด​ป้าย​ให้​ชัด: ผล​ที่​ว่า “เรียก​ครั้ง​เดียว​ดี​กว่า ensemble หลาย​ตัว” เป็น​สิ่ง​ที่​วัด​ได้ เฉพาะ​ใน​ระบบ research ของ Anthropic ไม่ใช่​กฎ​สากล ให้​ถือ​เป็น “ค่า​เริ่มต้น​ที่​ควร​ลอง​ก่อน” ไม่ใช่ “ต้อง​เรียก​ครั้ง​เดียว​เสมอ” — domain อื่น​อาจ​ต้อง​วัด​เอง​ว่า​แบบ​ไหน​นิ่ง​กว่า

judge ไม่ใช่​ตัวแทน​มนุษย์​แบบ​เสียบ​ปลั๊ก​แล้ว​ใช้ได้​เลย

กับดัก​ใหญ่​ที่สุด​ของ​ทั้ง​คอร์ส​คือ​การ​เข้าใจ​ว่า LLM-as-judge เป็น “มนุษย์​สำเร็จรูป” ที่​เอา​มา​แทน​การ​อ่าน​ของ​คน​ได้​เลย​ด้วย rubric เดียว มัน​ไม่ใช่ judge เป็น เครื่องมือ​วัด​ที่​ต้อง calibrate และ​ต้อง​คอย​เช็ค​ซ้ำ ไม่ใช่ oracle ที่​เชื่อ​ได้​ทันที — เพราะ​มัน​มี​อคติ​แฝง​ที่​วัด​ได้ (หัวข้อ​ถัด​ไป) และ​มนุษย์​ยัง​จับ​สิ่ง​ที่ judge มอง​ข้าม​ได้​เสมอ

งาน MT-Bench (Zheng et al., NeurIPS 2023) วัด​พฤติกรรม​ของ LLM ที่​ทำ​หน้าที่ judge แล้ว​พบ​อคติ​แฝง​สาม​แบบ​ที่​ต้อง​รู้​ก่อนไว้ใจผลใดๆ (ดู MT-Bench (arXiv 2306.05685)):

  • position bias — เอนเอียง​เข้าหา​คำ​ตอบ​ที่​ถูกวาง​ให้​เห็น ก่อน เวลา​ให้ judge เทียบ​สอง​คำ​ตอบ ลำดับ​ที่​วาง​มี​ผล​ต่อ​ผล​ตัดสิน ทั้ง​ที่​ไม่​ควร​มี
  • verbosity bias — เอน​เข้าหา​คำ​ตอบ​ที่ ยาว​กว่า แม้​เนื้อหา​ไม่​ได้​ดี​กว่า ยาว​และ​ดู​ละเอียด​ถูก​ตีความ​ว่า​ดี​โดย​อัตโนมัติ
  • self-enhancement bias — judge มี​แนวโน้ม​ให้​คะแนน output จาก model ตระกูล​เดียว​กับ​ตัวเอง สูง​กว่า​ความ​เป็น​จริง

ทั้ง​สาม​อย่าง​แก้​ได้​ด้วย​การ​ออกแบบ ไม่ใช่​ด้วย​การ​หวัง​ว่า model จะ​ดี​ขึ้น​เอง: กัน position bias ด้วย​การ สุ่ม​สลับ​ลำดับ​คำ​ตอบ (หรือ​รัน​ทั้ง​สอง​ลำดับ​แล้ว​เฉลี่ย), กัน verbosity bias ด้วย​การ คุม​ความ​ยาว ให้​เทียบ​กัน​ได้​หรือ​สั่ง rubric ไม่​ให้​นับ​ความ​ยาว​เป็น​ข้อดี, และ​กัน self-enhancement bias ด้วย​การ​เลือก model คนละ​ตระกูล​กับ​ตัว​ที่​ถูก​ตัดสิน มา​เป็น judge สำหรับ ops-copilot: ถ้า agent ที่​คืน​เงิน​ขับ​ด้วย model ตระกูล​หนึ่ง อย่า​ใช้ model ตระกูล​เดียวกัน​มา​เป็น​คน​ให้​คะแนน​งาน​ของ​มัน​เอง

flowchart TB
  O["outcome ที่ต้องให้คะแนน<br/>เช่น ผลการคืนเงินออเดอร์ 123"]
  O --> Q1{"มีรูปแบบคำตอบถูกต้องแบบเดียว<br/>เช็คด้วย code ตรงได้ไหม?"}
  Q1 -->|"ได้ เช่น มีแถวคืนเงิน ฿120 ในฐานข้อมูลไหม"| DET["deterministic grader<br/>เร็ว ถูก reproducible debug ง่าย"]
  Q1 -->|"ไม่ได้ เช่น ข้อความอธิบายถูกได้หลายแบบ"| JUDGE["LLM-as-judge<br/>ยืดหยุ่นแต่มีอคติแฝง"]
  DET --> DETW["ข้อควรระวัง: เปราะต่อความต่างที่ถูกต้อง<br/>ถ้าคำตอบมีได้หลายแบบจะตัดสินพลาด"]
  JUDGE --> BIAS["อคติ 3 อย่าง MT-Bench<br/>position / verbosity / self-enhancement"]
  BIAS --> FIX["กัน bias: สุ่มสลับลำดับคำตอบ<br/>คุมความยาว ใช้ model คนละตระกูลเป็น judge"]
  FIX --> CAL["calibrate เทียบป้ายมนุษย์<br/>ดู TPR และ TNR แยกกัน ไม่ใช่ % agreement รวม"]
  CAL --> USE["ค่อยปล่อยให้ judge ตัดสินเอง<br/>แล้วยังสุ่มอ่าน transcript ต่อ"]
  classDef det fill:#16a34a,stroke:#065f46,color:#f8fafc;
  classDef warn fill:#dc2626,stroke:#7f1d1d,color:#f8fafc;
  class DET det;
  class BIAS warn;

คำ​บรรยาย​ภาพ: เส้นทาง​ตัดสิน​ใจ​ของ grader หนึ่ง​ภาพ ถ้า​ผลลัพธ์​มี​รูปแบบ​ถูกต้อง​แบบ​เดียว​ให้​ไป​ทาง deterministic (เขียว: เร็ว/ถูก/รัน​ซ้ำ​ได้) โดย​จำ​ข้อ​ควร​ระวัง​ว่า​มัน​เปราะ​ต่อ​ความ​ต่าง​ที่​ถูกต้อง ถ้า​คำ​ตอบ​ถูก​ได้​หลาย​แบบ​ให้​ไป​ทาง LLM-as-judge ซึ่ง​พก อคติ 3 อย่าง​จาก MT-Bench (แดง) มา​ด้วย จึง​ต้อง​กัน bias ก่อน (สุ่ม​สลับ​ลำดับ คุม​ความ​ยาว ใช้ model คนละ​ตระกูล) แล้ว​จึง calibrate เทียบ​ป้าย​มนุษย์​โดย​ดู TPR/TNR แยก​กัน ก่อน​ปล่อย​ให้ judge ตัดสิน​เอง — และ​ยัง​ต้อง​สุ่ม​อ่าน transcript ต่อ ไม่​ปล่อย​ให้ judge ทำงาน​คน​เดียวลอยๆ

กัน​อคติ​แล้ว​ยัง​ไม่​พอ ก่อน​ปล่อย​ให้ judge ตัดสิน​เอง​เต็ม​รูปแบบ​ต้อง​ผ่าน Judge CalibrationJudge Calibrationกระบวนการ​เช็ค​ว่า LLM-as-judge ตัดสิน​ตรง​กับ​ป้าย​ที่​มนุษย์​ผู้เชี่ยวชาญ​ให้​ไว้​แค่​ไหน ก่อน​ปล่อย​ให้ judge ตัดสิน​เอง​เต็ม​รูปแบบ — ต้อง​ดู​อัตรา​ที่ judge จับ​ได้​ถูก​ทั้ง​ฝั่ง 'ผ่าน​จริง' และ 'พัง​จริง' แยก​กัน ไม่ใช่​แค่ % ที่​ตรง​กับ​มนุษย์​รวม ๆ เพราะ​ถ้า​เคส​พัง​มี​น้อย judge ที่​ตอบ 'ผ่าน' มั่ว ๆ ก็​ยัง​ได้​คะแนน​สูง​ลวงตา และ​ต้อง calibrate ซ้ำ​ทุก​ครั้ง​ที่​เปลี่ยน model judge หรือ rubricProcess ก่อน — เอา judge ไป​ตัดสิน​ชุด​เคส​ที่ มนุษย์​ผู้เชี่ยวชาญ​ให้​ป้าย​ไว้​แล้ว (held-out labeled set) แล้ว​วัด​ว่า​มัน​ตรง​กับ​มนุษย์​แค่​ไหน แต่​จุด​ตาย​อยู่​ที่ วัด​ด้วย​ตัวเลข​อะไร

อย่า​วัด​ด้วย raw agreement — เปอร์เซ็นต์​ที่ judge ตัดสิน​ตรง​กับ​มนุษย์​โดย​รวม​ทุก​เคส เพราะ​มัน​เป็น​ตัวเลข​ลวงตา​เมื่อ​เคส​พัง​มี​น้อย: ถ้าจริงๆ แล้ว​มี​เคส​พัง​แค่ 10% judge ที่​ตอบ “ผ่าน” มั่วๆ ทุก​เคส​จะ​ได้ agreement สูง​ถึง ~90% ทั้ง​ที่​มัน​จับ​ของ​พัง​ไม่​ได้​เลย​สัก​เคส ตัวเลข​สวย​แต่ judge ไร้​ประโยชน์ (กับดัก ~90% นี้​และ​การ​วัด​ด้วย TPR/TNR แยก​กัน สรุป​จาก Hamel/Shreya “LLM Evals FAQ”) ทาง​ที่​ถูก​คือ​ดู​สอง​อัตรา​แยก​กัน:

  • True Positive Rate (TPR) — ใน​บรรดา​เคส​ที่ พัง​จริง judge จับ​ได้​ถูก​กี่​เปอร์เซ็นต์
  • True Negative Rate (TNR) — ใน​บรรดา​เคส​ที่ ผ่าน​จริง judge บอกว่า​ผ่าน​ถูก​กี่​เปอร์เซ็นต์

judge ที่​ตอบ “ผ่าน” ทุก​เคส​จะ​ได้ TPR = 0 ทันที ปัญหา​โผล่​ให้​เห็น ต่าง​จาก raw agreement ที่​กลบ​มัน​ไว้ นอกจาก​นี้​ยัง​มี​เทคนิค​ออกแบบ​สอง​ข้อ​ที่​ช่วย​ลด​การ​ตัดสิน​มั่ว: ให้ judge มี​ทางออก “Unknown / ข้อมูล​ไม่​พอ” เพื่อ​ไม่​ให้​มัน​เดา​เมื่อ​หลักฐาน​ไม่​พอ (ลด​คำ​ตัดสิน​ที่ hallucinate ขึ้น​มา) และ​บังคับ​ให้​มัน ให้​เหตุผล​ก่อน​ตัดสิน เพราะ​การ​คิด​เป็น​ขั้น (chain-of-thought) ทำให้​คะแนน​แม่น​ขึ้น แม้​เรา​จะ​ทิ้ง​เหตุผล​นั้น​ไม่​เก็บ​ก็ตาม — สอง​ข้อ​นี้​อยู่​ใน​สเก็ตช์ rubric ด้าน​บน​แล้ว (ทั้งหมด​ตาม Anthropic, “Demystifying evals for AI agents”)

และ​ต้อง calibrate ซ้ำ​ทุก​ครั้ง ที่​เปลี่ยน model judge หรือ​แก้ rubric — ค่าที่​เคย​ผ่าน​ไม่​การันตี​ว่า​ยัง​ผ่าน​หลัง​เปลี่ยน สุดท้าย judge ที่ calibrate ดีแล้ว​ก็​ยัง ไม่​ปลด​มนุษย์​ออก​จาก loop: มนุษย์​ยัง​จับ​ความ​ผิดพลาด​ที่ judge มอง​ข้าม​ได้​เสมอ (บท​ที่ 6 จะ​เล่า​เคส​จริง​ที่​มนุษย์​จับ​ได้​แต่ automation ไม่​เห็น) วิธี​คิด​ที่​ถูก​คือ — judge เป็น​เครื่องมือ​วัด​ที่​เรา calibrate แล้ว​คอย​เช็ค​ซ้ำ ไม่ใช่ oracle ที่​ตั้ง​แล้ว​ลืม​ได้ การ​รักษา​คุณภาพ eval จึง​มา​จาก loop error analysis → ป้าย​จาก​มนุษย์ → judge ที่ calibrate → กลับ​ไป​อ่าน transcript ต่อ ที่​บท​ที่ 6 จะ​ประกอบ​ให้​เต็ม

บท​นี้​ให้​เกณฑ์​เลือก grader: deterministic ก่อน​เสมอ​ถ้า​ผลลัพธ์​มี​รูปแบบ​ถูกต้อง​แบบ​เดียว (เร็ว/ถูก/รัน​ซ้ำ​ได้ แต่​เปราะ​ต่อ​ความ​ต่าง​ที่​ถูกต้อง) แล้ว​ค่อย​ขยับ​ไป LLM-as-judge เมื่อ​คำ​ตอบ​ถูก​ได้​หลาย​แบบ โดย​ไม่​ลืม​ว่า judge มี​อคติ​แฝง (position/verbosity/self-enhancement) ที่​ต้อง​กัน และ​ต้อง calibrate ด้วย TPR/TNR ไม่ใช่ raw agreement ก่อน​ไว้ใจ บท​ที่ 5 จะ​ย้อน​ไป​ที่​ต้นทาง​ของ​ทั้งหมด — eval set ควร​เริ่ม​จาก​กี่​เคส และ​เคส​พวก​นั้น​ควร​มา​จาก​ไหน


🔗 อ้างอิง​ต้นทาง​ของ​บท​นี้

บท​นี้​สังเคราะห์​จาก​สี่​แหล่ง​หลัก อ่าน​ต่อ​ได้ที่​ต้นทาง​โดยตรง:

เช็กความเข้าใจ — บทที่ 4

ข้อ 1 / 3

ในกรณีใดที่ควรใช้ deterministic grader แทน LLM-as-judge?