เป้าหมาย
สร้างชุดทดสอบจากเคสจริง ให้คะแนนอัตโนมัติ รู้ความแม่นยำและต้นทุนต่องาน แล้วปรับ prompt อย่างมีหลักฐาน
ทำไมต้อง eval
"ลองสามข้อแล้วดูดี" ไม่พอ → แก้ prompt ให้เคสใหม่ผ่าน เคสเก่าอาจพังเงียบๆ (regression) eval ให้ตัวเลขที่เทียบกันได้ทุกครั้งที่แก้
6 ขั้นทำ eval
- เก็บเคสจริง 20–100 เคส จากตั๋ว/อีเมล/log จริง (ลบข้อมูลส่วนบุคคลก่อน) ใส่เคสยากและกำกวมด้วย
- เขียนคำตอบที่คาดหวัง ให้คนที่รู้งานเป็นคนกำหนด ไม่ใช่ให้ AI เดา
- เลือกวิธีให้คะแนน
grader ใช้กับ ข้อดี / ข้อเสีย exact match หมวดหมู่ ตัวเลข ใช่/ไม่ใช่ แม่น ถูก / ใช้กับข้อความอิสระไม่ได้ code check JSON ถูก schema, มีเลขออเดอร์, ยาวไม่เกิน N เร็ว / ตรวจได้แค่รูปแบบ LLM-as-judge + rubric คุณภาพคำตอบ น้ำเสียง ความครบ ยืดหยุ่น / ต้องเขียน rubric ชัด และสุ่มตรวจตัว judge - แบ่ง dev / test — ปรับ prompt ดูแค่ dev, test เก็บไว้วัดตอนท้าย กันการ "จูนจนจำข้อสอบ"
- วัด baseline ก่อน แล้ว เปลี่ยนทีละอย่าง (prompt หรือโมเดล หรือ effort) จดผลทุกครั้ง
- ดูต้นทุนต่องาน คู่กับความแม่นยำ — แม่นขึ้น 2% แต่แพงขึ้น 3 เท่า อาจไม่คุ้ม
ลองเลย 🧪
ทดลอง A — สคริปต์ eval จัดหมวดตั๋วลูกค้า (pip install anthropic pydantic และตั้ง ANTHROPIC_API_KEY ใน env)
บันทึกเป็น eval_tickets.py ไว้ในโฟลเดอร์ระดับนี้ (ข้าง samples/)
import csv
import sys
from typing import Literal
import anthropic
from pydantic import BaseModel
TASK_MODEL = "claude-sonnet-5-5"
JUDGE_MODEL = "claude-opus-5-5"
PRICE = {"claude-sonnet-5-5": (2, 10), "claude-opus-5-5": (4, 20)} # USD ต่อ 1M token (input, output)
SYSTEM_PROMPT = """จัดหมวดข้อความลูกค้าร้านกาแฟออนไลน์ และร่างคำตอบสั้นภาษาไทย ไม่เกิน 3 บรรทัด
หมวด: billing (การเงิน ใบแจ้งหนี้ ส่วนลด), shipping (การจัดส่ง), refund (ขอคืนเงิน/คืนสินค้า),
technical (แอป เว็บ ล็อกอิน), other (อื่นๆ)"""
RUBRIC = """ให้คะแนนคำตอบถึงลูกค้า 1-5: สุภาพ ตรงประเด็น ไม่สัญญาสิ่งที่ร้านอาจทำไม่ได้ (เช่น คืนเงินทันที)
ไม่ขอข้อมูลบัตรเต็มเลข passed=true เมื่อ score >= 4"""
class Ticket(BaseModel):
category: Literal["billing", "shipping", "refund", "technical", "other"]
reply: str
class Grade(BaseModel):
score: int
passed: bool
reason: str
client = anthropic.Anthropic()
total_cost = 0.0
def ask(model, system, text, schema):
global total_cost
r = client.messages.parse(model=model, max_tokens=16000, system=system,
messages=[{"role": "user", "content": text}], output_format=schema)
p_in, p_out = PRICE[model]
total_cost += (r.usage.input_tokens * p_in + r.usage.output_tokens * p_out) / 1_000_000
return r.parsed_output
split = sys.argv[2] if len(sys.argv) > 2 else "dev" # dev = T01-T14, test = T15-T20
rows = [r for r in csv.DictReader(open(sys.argv[1], encoding="utf-8"))
if split == "all" or (int(r["id"][1:]) <= 14) == (split == "dev")]
correct = good_reply = 0
for row in rows:
out = ask(TASK_MODEL, SYSTEM_PROMPT, row["input"], Ticket)
if out is None:
print(row["id"], "ไม่ได้ผลลัพธ์ (อาจถูกปฏิเสธ)")
continue
ok = out.category == row["expected_category"]
grade = ask(JUDGE_MODEL, RUBRIC, f"ข้อความลูกค้า: {row['input']}\nคำตอบ: {out.reply}", Grade)
correct += ok
good_reply += bool(grade and grade.passed)
if not ok or not (grade and grade.passed):
print(f"{row['id']} คาด={row['expected_category']} ได้={out.category} judge={grade.score if grade else '-'} {grade.reason if grade else ''}")
n = len(rows)
print(f"\n[{split}] หมวดถูก {correct}/{n} = {correct / n:.0%} | คำตอบผ่าน rubric {good_reply}/{n}")
print(f"ต้นทุนรวม ${total_cost:.4f} | ต่อเคส ${total_cost / n:.4f} (รวมค่า judge)")python eval_tickets.py samples/eval-cases.csv dev→ จดตัวเลข baseline: % หมวดถูก, % คำตอบผ่าน, ต้นทุนต่อเคส แล้วอ่านเคสที่พิมพ์ออกมา (ผิดเพราะ prompt หรือเพราะเฉลยกำกวม?)
ทดลอง B — ปรับทีละอย่าง แล้ววัดซ้ำ
แก้ SYSTEM_PROMPT อย่างเดียว เช่นเพิ่มกติกา "ถ้าลูกค้าขอเงินคืน ให้เป็น refund แม้สาเหตุคือสินค้าเสีย" → รัน dev ใหม่ → ดีขึ้นค่อยรัน test ครั้งเดียว
→ ลองอีกรอบโดยเปลี่ยนแค่ TASK_MODEL เป็นรุ่นเล็กกว่า เทียบความแม่น vs ต้นทุน
ทดลอง C — ให้ Claude ช่วยหาจุดอ่อนของ rubric
นี่คือ rubric ที่ใช้ให้ AI ให้คะแนนคำตอบลูกค้า: [วาง RUBRIC]
ยกตัวอย่างคำตอบ 3 แบบที่ได้คะแนนสูงตาม rubric แต่จริงๆ แย่ แล้วเสนอ rubric ที่รัดกุมขึ้นeval ใน CI (กัน regression)
รันสคริปต์ใน GitHub Actions ทุกครั้งที่ไฟล์ prompt เปลี่ยน แล้วให้ fail ถ้าความแม่นต่ำกว่าเกณฑ์ (เช่น 90%) — เก็บ API key เป็น secret ของ repo เท่านั้น
⚠️ ต้องตรวจสอบ: ชื่อรุ่นและราคาต่อ 1M token ใน
PRICEที่ platform.claude.com ก่อนใช้ตัวเลขต้นทุนจริง
สรุปจำง่าย
เคสจริง + เฉลยจากคน + grader อัตโนมัติ + เปลี่ยนทีละอย่าง + ดูต้นทุนต่องาน