[LLM 8/10] Guardrails: รั้วนิรภัยที่แท้จริงไม่ใช่โมเดล แต่คือ threshold
แชตบอตภาษาไทยที่ผมและทีม deploy ให้ลูกค้าใช้งานจริง ไม่ได้เจอแต่คำถามสุภาพ ๆ — มีคนขอสูตรทำของผิดกฎหมาย มีคนพยายามหลอกให้มันด่าคนอื่น และมีวันที่โมเดลพ่นเบอร์โทรลูกค้าออกมาเอง บทนี้เราจะสร้างระบบป้องกันทั้งสองทิศ: classifier ตรวจ prompt อันตรายขาเข้า และ ตัวกรอง PII ขาออก แต่ประเด็นแกนกลางของบทไม่ใช่ตัวโมเดล — มันคือความจริงที่ว่า guardrail เป็นการตัดสินใจเรื่อง threshold ภายใต้ต้นทุนที่ไม่สมมาตร และตัวเลข "accuracy 94%" ที่คนชอบโชว์กันนั้น แทบไม่มีความหมายเลย
Open in Colab08_guardrails.ipynb
1. ปัญหา (Problem statement)
บทที่ผ่าน ๆ มาเราเทรนโมเดลให้ "เก่งขึ้น" มาตลอด แต่โมเดลที่เก่งแค่ไหนก็ตาม พอเจอผู้ใช้จริงจะเจอความเสียหายได้สองทิศทางเสมอ:
| ทิศทาง | ตัวอย่างความเสียหาย | เครื่องมือของบทนี้ |
|---|---|---|
| ขาเข้า (input) | ผู้ใช้ขอวิธีทำร้ายคนอื่น สูตรของผิดกฎหมาย วิธีโกง — แล้วโมเดลตอบให้ | classifier ตรวจ prompt อันตราย |
| ขาออก (output) | โมเดลพ่นเลขบัตรประชาชน เบอร์โทร เลขบัญชี ที่หลุดมาจาก context หรือข้อมูลเทรน | ตัวกรอง PII แบบ deterministic |
อย่าลืมว่า SFT ในบทที่ 2 มีผลข้างเคียงที่เงียบมาก: การ fine-tune ด้วยข้อมูลแคบ ๆ กัดกร่อนพฤติกรรมปฏิเสธ (refusal) ที่โมเดลเคยมี โมเดลที่คุณปรับแต่งเองจึงมักปลอดภัยน้อยกว่าต้นฉบับ นี่คือเหตุผลที่ระบบจริงต้องมีรั้วอีกชั้นที่อยู่นอกตัวโมเดล
แล้วทำไมถึงซื้อ guardrail สำเร็จรูปที่โฆษณาว่า "แม่น 94%" ไม่ได้เลย? เพราะประโยคนั้นยังไม่ได้ตอบคำถามที่สำคัญที่สุดสามข้อ:
- แม่น 94% ที่ threshold ไหน — ตัวเลขเดียวกันนี้เลื่อนได้ทั้งเส้นโค้ง
- วัดบนชุดทดสอบที่มี unsafe กี่เปอร์เซ็นต์ — ใน production ทราฟฟิกอันตรายจริงมักไม่ถึง 1%
- และมันบล็อกผู้ใช้บริสุทธิ์กี่เปอร์เซ็นต์ — ตัวเลขที่แทบไม่มีใครยอมรายงาน
Guardrail ที่บล็อกลูกค้าที่ถามเรื่องปกติ ไม่ใช่ระบบที่ปลอดภัย มันคือผลิตภัณฑ์ที่พัง
2. เราจะทำอะไร (Solution)
เราจะสร้าง guardrail จริงสองตัวบน Colab ฟรี แล้ววัดมันอย่างตรงไปตรงมา:
| ชั้น | ตำแหน่ง | เทคนิค | เวลาแฝงโดยประมาณ |
|---|---|---|---|
| Input guardrail | ก่อน prompt ไปถึง LLM | Qwen3-0.6B + sequence-classification head + LoRA r=8 | ~15–30 ms |
| Output guardrail | หลัง LLM ตอบ ก่อนถึงผู้ใช้ | regex + mod-11 checksum (ไม่มี ML เลย) | ~0.1 ms |
Guardrail ไม่ใช่โมเดล — มันคือการตัดสินใจเรื่อง threshold ภายใต้ต้นทุนที่ไม่สมมาตร โมเดลให้แค่คะแนน ส่วนการเลือกจุดตัด คือการตอบคำถามเชิงธุรกิจว่า "การปล่อยของอันตรายหลุดหนึ่งครั้ง แพงกว่าการบล็อกลูกค้าบริสุทธิ์หนึ่งคนกี่เท่า"
รายงานผลที่ซื่อสัตย์จึงต้องมีสองตัวเลขเสมอ: unsafe ที่จับได้ และ benign ที่ถูกบล็อก ตัวเลขเดียวโดด ๆ คือการตลาด ไม่ใช่วิศวกรรม
และเราจะได้เห็นด้วยว่า guardrail ที่ดีที่สุดบางตัวไม่ใช่ ML เลย — ตัวกรอง PII ด้วย regex + checksum นั้น deterministic, ทดสอบได้แบบ unit test, เร็วระดับไมโครวินาที และไม่มีวันโดน jailbreak
3. สมการ (Equation)
3.1 Loss ของ classifier — ของคุ้นเคย
binary cross-entropy ธรรมดา ( คือ unsafe) ไม่มีอะไรใหม่ — และนั่นแหละคือประเด็น: ส่วนที่เป็น ML ของ guardrail คือส่วนที่ง่ายที่สุดของทั้งระบบ ของจริงอยู่ข้างล่างนี้
3.2 กฎการตัดสินใจ และต้นทุนคาดหวัง — เนื้อหาจริงของบทนี้
โมเดลจบหน้าที่ที่การให้คะแนน การบล็อกหรือปล่อยคือการเทียบกับ ซึ่งเราเลือกโดย minimize ต้นทุนคาดหวัง:
- = สัดส่วน unsafe ที่หลุดรอด (false negative rate)
- = สัดส่วน benign ที่ถูกบล็อก (false positive rate)
- = ราคาของความผิดพลาดแต่ละแบบ
สังเกตว่าสมการนี้บังคับให้คุณตอบคำถามที่ ML ตอบแทนไม่ได้: ของผลิตภัณฑ์คุณคือเท่าไหร่ นี่คือการตัดสินใจเชิงผลิตภัณฑ์ล้วน ๆ และแต่ละผลิตภัณฑ์ตอบไม่เหมือนกัน:
| ผลิตภัณฑ์ | ราคาของ FN (ปล่อย unsafe หลุด) | ราคาของ FP (บล็อกคนบริสุทธิ์) | ที่สมเหตุสมผล |
|---|---|---|---|
| แชตบอตให้คำปรึกษาสุขภาพ | อันตรายถึงชีวิต + ความรับผิดทางกฎหมาย | ผู้ใช้หงุดหงิดเล็กน้อย | 50:1 ขึ้นไป |
| ผู้ช่วยลูกค้าองค์กร | เป็นข่าวเสียหาย | ลูกค้าติดต่อ support เพิ่ม | ~10:1 |
| เครื่องมือภายในสำหรับพนักงาน | จำกัด (ผู้ใช้คือพนักงานที่ระบุตัวได้) | งานสะดุดทุกวัน | ~2:1 |
ถ้าคุณไม่เคยเขียนอัตราส่วนนี้ลงเอกสารอย่างชัดเจน แปลว่าที่ผ่านมามีคนเลือก ให้คุณโดยบังเอิญ
3.3 บทเรียนที่แพงที่สุดของบท: base rate ทำ precision พังได้
สมมติ classifier ของเราจับ unsafe ได้ TPR = 95% และบล็อกผิดแค่ FPR = 5% — ฟังดูเยี่ยม คำถาม: ในบรรดาข้อความที่ถูกบล็อก มีกี่เปอร์เซ็นต์ที่ unsafe จริง? ใช้ Bayes ตรง ๆ ให้ คือสัดส่วน unsafe ในทราฟฟิกจริง:
แทนตัวเลขสองสถานการณ์:
- ชุดทดสอบสมดุล (): precision
- ทราฟฟิกจริง (): precision
classifier ตัวเดียวกันเป๊ะ ๆ — แต่ใน production ทุก ๆ 6 ข้อความที่ถูกบล็อก มี 5 ข้อความเป็นผู้ใช้บริสุทธิ์ เพราะเมื่อ unsafe หายาก ( เล็ก) พจน์ ในตัวหารจะกลืนทุกอย่าง นี่คือเหตุผลที่การประเมินบนชุดสมดุลแล้วเอาไปคุยว่า "แม่น 95%" คือการหลอกตัวเอง
3.4 การป้องกันหลายชั้น (layered defence)
ถ้าวาง guardrail อิสระกัน ชั้น (blocklist → classifier → system prompt → มนุษย์สุ่มตรวจ) โดย unsafe จะหลุดได้ต้องหลอกทุกชั้น แต่ benign โดนบล็อกถ้าชั้นใดชั้นหนึ่งจับผิด:
FNR ลดแบบเรขาคณิต (ดีมาก) แต่ FPR ทบต้นขึ้นเรื่อย ๆ (บิลที่ต้องจ่าย)
สมการ ใช้ได้ต่อเมื่อแต่ละชั้นพลาดแบบอิสระต่อกัน ซึ่งในความเป็นจริงแทบไม่เคยจริง — เทคนิคหลบเลี่ยงหนึ่งท่า (เช่น แทรก zero-width space กลางคำ) มักหลอกทุกชั้นที่อิงข้อความดิบพร้อมกัน ความผิดพลาดของแต่ละชั้นจึงสหสัมพันธ์กัน และ จริงจะแย่กว่าสูตรนี้เสมอ มองสูตรนี้เป็น best case ไม่ใช่คำสัญญา
3.5 Constrained decoding — guardrail ที่ไม่ใช่ ML และคนมองข้ามที่สุด
ถ้า use case ของคุณตอบได้แค่ชุดจำกัด (เมนู, หมวดหมู่, JSON ตาม schema) อย่าไปตรวจข้อความทีหลัง — บังคับตั้งแต่ตอน generate ด้วยการ renormalize บนเซตโทเคนที่อนุญาต :
โทเคนนอก มีความน่าจะเป็นเป็นศูนย์เป๊ะ ไม่ใช่ "น้อยมาก" ผลคือ guardrail ที่ deterministic, เวลาแฝงเพิ่มเป็นศูนย์, และไม่มี prompt ใดในจักรวาล bypass ได้ เพราะมันไม่ได้ห้ามโมเดล "อยากพูด" — มันทำให้คำนอกเซตไม่มีอยู่ในสารบบตั้งแต่แรก ที่ไหนใช้ constrained decoding ได้ ให้ใช้ก่อนเสมอ แล้วค่อยเอา classifier ไปเฝ้าส่วนที่เป็น free text จริง ๆ
บทความนี้คือประมาณ 30% แรกของบทเรียน — ส่วนที่เหลือ (การเตรียมสภาพแวดล้อม, การเตรียมข้อมูล, โค้ดหลัก, ผลลัพธ์จริง และบทสรุป) อยู่ในคอร์ส LLM Finetuning ซึ่งเรียนฟรี เพียงเข้าสู่ระบบด้วย Google
อ่านเนื้อหาเต็มในคอร์ส →