productize.life
TH EN
AI · Reliability

เครื่องมือที่เอาไว้จับผิด
ดันผิดเสียเอง

บางครั้งตัวที่เราใช้ตรวจจับความผิด ก็พังเงียบๆ แล้วรายงานว่า "ไม่มีบั๊ก" ทั้งที่ไม่ได้ตรวจอะไรเลย วิธีจับให้ได้คือทำให้มันพังให้ดูสักครั้ง

Yim· เขียนด้วยกันกับ Dobby (AI Oracle)/30 มิ.ย. 2026/~7 นาที

เวลาปล่อยให้ AI เขียนโค้ด เราจะมี AI อีกตัวคอยรีวิวก่อนเอาขึ้นจริงเสมอ (ใช้ codex เป็นตัวรีวิว เหมือนให้คนที่สองตรวจงานคนแรก) ทางปกติก็คือ รีวิวเสร็จ ขึ้นรายการที่ต้องแก้ เราแก้ แล้วค่อยปล่อย

ช่วงที่ 1"ไม่มีบั๊ก" อาจแปลว่าตัวตรวจสอบตายไปแล้ว

มีรอบหนึ่ง ตัวรีวิวกลับมาแบบไม่เจออะไรเลย รายการว่างเปล่า "ไม่มีบั๊ก" เราเกือบบันทึกว่าโค้ดสะอาด ผ่าน

แต่พอเห็นเลขศูนย์ก็เริ่มเอะใจ diff ขนาดนี้จะไม่มีอะไรให้ติเลยได้ยังไง เลยเลื่อนไปดูท้ายๆ ของผลรีวิว ตรงนั้นแหละที่เจอว่าตัวรีวิว timeout ไปตั้งแต่ต้น โหลด model ไม่ขึ้นด้วยซ้ำ แปลว่าไม่เคยได้อ่านโค้ดเราสักบรรทัด "ไม่มีบั๊ก" ที่เห็นเลยไม่ได้แปลว่าโค้ดสะอาด แต่แปลว่าตัวตรวจสอบตายไปก่อนจะได้ตรวจ

พอ re-run ให้ทำงานจริง คราวนี้เจอของจริง 4 จุดที่ต้องแก้

ปัญหาคือ "0 บั๊ก จากตัวตรวจสอบที่ตายแล้ว" กับ "0 บั๊ก เพราะโค้ดสะอาดจริงๆ" หน้าตาเหมือนกันเป๊ะ ถ้าไม่แกะดูข้างใน ก็แยกไม่ออก

แล้วนี่ไม่ใช่ครั้งเดียว อีกรอบ คำสั่งที่เราเขียนไว้เช็คว่า token (กุญแจยืนยันตัวกับเซิร์ฟเวอร์) ยังใช้ได้ไหม ดันไปตัดตัวอักษรบางตัวออกจาก token เองเงียบๆ ก่อนเช็ค เลยรายงานว่า token เสีย ทั้งที่ของดีอยู่แท้ๆ ตัวเช็คทำของพังเอง แล้วก็โทษของที่ตัวเองทำพัง

ช่วงที่ 2ผลที่ขึ้นเขียว ยังไม่ใช่หลักฐานที่เชื่อได้

ลองมองสองเคสเมื่อกี้ใหม่ ทั้งคู่มีจุดร่วมเดียวกัน เราเอา "ผลที่ผ่าน" มาเป็นหลักฐานว่าทุกอย่างเรียบร้อย ทั้งที่ไม่เคยพิสูจน์เลยว่าตัวตรวจสอบจับของพังได้จริงไหม

ตัวรีวิวที่ timeout กับคำสั่งเช็ค token ที่ตัดตัวอักษรทิ้ง ไม่ได้ขึ้นว่าผ่านเพราะของมันดี แต่ขึ้นว่าผ่านเพราะไม่ได้ตรวจอะไรเลยต่างหาก ผลที่ออกมาเลยว่างเปล่าพอๆ กับตอนที่ทุกอย่างดีจริง แล้วเราก็ดันอ่านความว่างเปล่านั้นว่า "ดี"

ตรงนี้แหละคือกับดัก ในไปป์ไลน์ที่มี AI ช่วยทำงาน เราพึ่งตัวตรวจสอบเต็มไปหมด ทั้ง linter, health check, เทสต์อัตโนมัติ ไปจนถึง AI ที่เอามาตรวจงาน AI ด้วยกันเอง ทุกตัวรายงานออกมาเป็นเขียวหรือแดง ผ่านหรือไม่ผ่าน แต่ไม่มีตัวไหนบอกเราเลยว่า ตอนขึ้นเขียว มันตรวจจริง หรือแค่ตายเงียบๆ

คำถามที่ควรถามเลยไม่ใช่ "ผ่านไหม" แต่เป็น "ถ้ามีอะไรพังจริง ตัวนี้จับได้ไหม" และวิธีเดียวที่จะตอบคำถามนี้ได้ คือทำให้มันพังให้ดูสักครั้ง

ช่วงที่ 3mutation testing จงใจทำให้พัง แล้วดูว่าตัวตรวจสอบจับได้ไหม

วิธีนี้มีชื่อเรียกอยู่แล้วในการเขียนเทสต์ เรียกว่า mutation testing แนวคิดมีมาตั้งแต่ปลายยุค 70 แต่หลักการเรียบง่ายมาก แทนที่จะถามว่า "เทสต์ผ่านไหม" ก็กลับด้านมาถามว่า "ถ้าจงใจใส่บั๊กลงไป เทสต์จับได้ไหม"

วิธีทำคือ เอาโค้ดมาแก้ให้ผิดทีละนิดแบบตั้งใจ เปลี่ยน + เป็น - เปลี่ยน >= เป็น > สลับ true เป็น false โค้ดที่แก้ให้พังแบบนี้เรียกว่า mutant (ตัวกลายพันธุ์) แล้วรันเทสต์ชุดเดิมทับลงไป ถ้าเทสต์ดีจริง ต้องจับ mutant ตัวนี้ได้ คือต้องมีเทสต์สักตัวเปลี่ยนจากเขียวเป็นแดง อันนี้เราเรียกว่า "ฆ่า mutant ตาย" แต่ถ้าใส่บั๊กเข้าไปแล้วเทสต์ยังเขียวหมดเหมือนเดิม แปลว่า mutant ตัวนั้น "รอด" และนั่นคือหลักฐานชัดๆ ว่าเทสต์ของเราไม่ได้ตรวจตรงนั้นเลย

ยกตัวอย่างง่ายๆ สมมติมีฟังก์ชันเช็คว่าอายุถึงเกณฑ์ไหม เขียนว่า age >= 18 แล้วมีเทสต์ยิงด้วยอายุ 25 ผ่านฉลุย ดูเผินๆ เหมือนมีเทสต์คุมอยู่แล้ว แต่ลองเปลี่ยน >= เป็น > ดู ถ้าเทสต์ยังผ่านอยู่ แปลว่าไม่เคยมีเทสต์ไหนยิงด้วยอายุ 18 พอดีเลย เคสตรงขอบที่คนพลาดกันบ่อยที่สุด เทสต์เราไม่เคยแตะ

ทีนี้ลองขยายความคิดนี้ออกไปนอกเรื่องเทสต์ ตัวตรวจสอบทุกตัวเล่นท่าเดียวกันได้หมด อยากรู้ว่า linter จับ pattern ที่ห้ามใช้ได้จริงไหม ก็แอบใส่ pattern นั้นเข้าไปสักบรรทัด อยากรู้ว่า AI reviewer จับบั๊กเป็นไหม ก็ป้อนโค้ดที่มีบั๊กชัดๆ ให้ดูสักตัว ถ้าเงียบ แปลว่าเราเพิ่งจับได้ว่าตัวตรวจสอบนี้เชื่อไม่ได้ ก่อนที่มันจะปล่อยของพังจริงหลุดผ่าน

ช่วงที่ 4positive control เวอร์ชันเบา ทำมือได้ทุกครั้ง

mutation testing แบบเต็มสูบใช้แรงพอควร ต้องใส่ mutant เป็นร้อยๆ ตัว แล้ววัดว่าฆ่าได้กี่เปอร์เซ็นต์ เหมาะกับเอาไปวางใน CI ให้รันยาวๆ แต่หลายครั้งเราไม่ได้ต้องการขนาดนั้น เราแค่อยากรู้เดี๋ยวนั้นว่าตัวตรวจสอบที่อยู่ตรงหน้า ยังทำงานอยู่ไหม ก่อนจะเชื่อผลของมัน

ตรงนี้มีวิธีที่ถูกกว่าและเร็วกว่ามาก ยืมมาจากแล็บวิทยาศาสตร์ เรียกว่า positive control เวลานักวิทยาศาสตร์รันการทดลอง เขาจะใส่ตัวอย่างที่รู้อยู่แล้วว่าต้องให้ผลบวกลงไปด้วยเสมอ ถ้าตัวที่รู้คำตอบล่วงหน้ายังไม่ขึ้นผลบวก แปลว่าการทดลองนั้นพัง ผลที่เหลือทั้งหมดก็เชื่อไม่ได้ทันที

เอามาใช้กับตัวตรวจสอบก็ตรงตัว ก่อนจะเชื่อว่า ตรวจแล้วไม่เจออะไร แปลว่าไม่มีปัญหา ให้ลองป้อนเคสที่รู้อยู่แล้วว่าต้องโดนจับเข้าไปสักตัวก่อน ถ้าจับได้ ค่อยเชื่อผลที่เหลือ แต่ถ้าปล่อยเคสที่ควรโดนจับให้ผ่านไปได้ ก็จบ ไม่ต้องเสียเวลาอ่านผลที่เหลือเลย เพราะตัวตรวจสอบตายไปแล้ว

ย้อนกลับไปสองเคสแรก ทั้งคู่ แค่คั่น positive control ไว้นิดเดียวก็รอดแล้ว ก่อนเชื่อ "0 บั๊ก" ถ้าลองโยนโค้ดที่มีบั๊กชัดๆ ให้ codex ดูสักตัว มันคงเงียบใส่ตั้งแต่ตอนนั้น เราก็รู้เลยว่าตัวรีวิวตาย ส่วนคำสั่งเช็ค token ถ้าลองรันกับ token ที่รู้ว่าดีก่อน แล้วเห็นว่ายังขึ้นว่า "เสีย" เราก็จับได้ทันทีว่าปัญหาอยู่ที่ตัวเช็ค ไม่ใช่ token

ช่วงที่ 5ยิ่งปล่อยให้ AI ทำงานเยอะ ยิ่งต้องระวังตรงนี้

ตอนเราทำงานคนเดียวกับ AI ทั้งกอง จำนวนตัวตรวจสอบเพิ่มขึ้นเร็วมาก ตัว agent รายงานเองว่า "ทำเสร็จแล้ว" เทสต์รันอัตโนมัติ health check คอยดูว่าระบบยังอยู่ AI อีกตัวคอยรีวิวโค้ด ทุกตัวส่งสัญญาณเขียวแดงกลับมาให้เราเชื่อ

ปัญหาคือตัวตรวจสอบพวกนี้พังแบบไม่ส่งเสียงบอกได้ง่ายมาก พอ timeout มันไม่ได้ฟ้องว่าตัวเองพัง แค่คืนค่าว่างๆ กลับมาเฉยๆ เหมือนตอนที่ทุกอย่างปกติ agent ที่ควรทำงานต่อ พอเจอ error ก็อาจจบด้วยสถานะ "สำเร็จ" หน้าตาเฉย (เคส agent บอกว่าเสร็จทั้งที่ยังไม่เสร็จ เราเล่าไว้แล้วในโพสต์ why your AI agent lies to you) ยิ่งเอางานไปฝากตัวตรวจสอบพวกนี้มากเท่าไหร่ โอกาสที่ผลผ่านปลอมๆ จะหลุดไปถึงตอนใช้งานจริงก็ยิ่งมากขึ้น

ทางที่เราเลือกเดินคือ ฝัง positive control ไว้ในไปป์ไลน์ตั้งแต่แรก ให้ทุกตัวตรวจสอบต้องพิสูจน์ก่อนว่าจับเคสที่รู้ว่าพังได้จริง ถึงจะมีสิทธิ์บอกว่า "ผ่าน" รายละเอียดวิธีวางเก็บไว้เล่าวันหลัง แต่หลักคิดเปิดได้หมด เพราะนี่ไม่ใช่ความลับ เป็นวินัยต่างหาก

ถ้าจะหยิบอะไรกลับไปใช้แค่อย่างเดียว เอาอันนี้ ผลที่ขึ้นเขียวจะเป็นหลักฐานได้ ก็ต่อเมื่อคุณเคยเห็นมัน red flag มาก่อน คราวหน้าที่ตัวตรวจสอบบอกว่า "ไม่เจออะไร" อย่าเพิ่งเชื่อ ลองโยนเคสที่รู้ว่าต้องโดนจับเข้าไปสักตัว ถ้ามันเงียบ คุณเพิ่งเจอบั๊กตัวจริง และมันอยู่ที่ตัวตรวจสอบเอง

เขียนจากงานจริง ไม่ใช่ทฤษฎี จากรอบที่ตัวรีวิวตายเงียบๆ แล้วรายงานว่าโค้ดสะอาด และคำสั่งเช็ค token ที่ตัดตัวอักษรของ token ทิ้งเอง

ที่มาและอ้างอิงReferences

ซีรีส์ ความน่าเชื่อถือของ AI
ติดตาม

รับบทความใหม่และของฟรีก่อนใคร

ทิ้งอีเมลไว้ บทความใหม่และของฟรีเป็นครั้งคราวจะส่งไปให้ ไม่สแปม

ใช้อีเมลเพื่อส่งอัปเดตเท่านั้น

ความคิดเห็น

ร่วมพูดคุย

แบ่งปันความคิดเห็นได้เลย

ชื่อจะแสดงต่อสาธารณะ อีเมลเก็บเป็นความลับ ไม่แสดงที่ไหน

กำลังโหลดความคิดเห็น…