AI แต่งตัวเลขได้เนียนกว่าที่คิด: 3 ด่านที่ผมใช้กันตัวเลขปลอมหลุดขึ้นเว็บ (2026)
AI ไม่ได้แต่งตัวเลขจากอากาศ มันแต่งรอบตัวเลขจริง — วิธีวางสัญญาแหล่งอ้างอิง สคริปต์ตรวจอัตโนมัติ และการดึงแหล่งใหม่สดก่อนเผยแพร่ พร้อมโค้ดที่ก็อปไปใช้ได้เลย
AI แต่งตัวเลขได้เนียนกว่าที่คิด: 3 ด่านที่ผมใช้กันตัวเลขปลอมหลุดขึ้นเว็บ (2026)
AI ไม่ได้แต่งตัวเลขจากอากาศ มันแต่งรอบตัวเลขจริง — วิธีวางสัญญาแหล่งอ้างอิง สคริปต์ตรวจอัตโนมัติ และการดึงแหล่งใหม่สดก่อนเผยแพร่ พร้อมโค้ดที่ก็อปไปใช้ได้เลย
วันหนึ่งระบบเขียนข่าวอัตโนมัติของผมส่งบทความมาให้ตรวจ ในนั้นมีตารางเปรียบเทียบอัตราการใช้ AI ของห้าประเทศ สวยงาม มีเชิงอรรถอ้างอิงครบ อ่านแล้วน่าเชื่อถือทุกบรรทัด ปัญหาคือมีตัวเลขจริงอยู่แค่ตัวเดียว ที่เหลือถูก "เติมให้ครบตาราง" และแหล่งที่มันอ้างก็ไม่เคยพูดถึงตัวเลขพวกนั้นเลย — ที่แย่กว่านั้นคือมันเขียนรายงานยืนยันการตรวจสอบแนบมาด้วย เป็นรายงานที่มันพิมพ์เองโดยไม่เคยเปิดลิงก์ต้นทางสักครั้ง ผมทำงานสาย model validation ในแบงก์มาหลายปี และเคสนี้สอนผมว่าปัญหาไม่ได้อยู่ที่โมเดล แต่อยู่ที่ผมออกแบบระบบตรวจให้ "ผู้ถูกตรวจเป็นคนให้เกรดตัวเอง"
1. AI ไม่ได้แต่งตัวเลขจากอากาศ — มันแต่งรอบตัวเลขจริง
รูปแบบการหลอนที่อันตรายที่สุดไม่ใช่การกุตัวเลขขึ้นมาลอย ๆ เพราะแบบนั้นคนอ่านจับได้ง่าย รูปแบบที่อันตรายคือโมเดลเจอตัวเลขจริงหนึ่งตัว แล้วสร้างบริบทรอบ ๆ ให้มันสมเหตุสมผล เติมประเทศที่ขาด เติมปีที่หายไป ปัดเศษให้กลม แล้ววางเชิงอรรถของแหล่งที่มีอยู่จริงประกบไว้ ผลลัพธ์คือย่อหน้าที่ทุกองค์ประกอบดู "ตรวจสอบได้" แต่ตรวจจริงแล้วมีแค่ชิ้นเดียวที่รอด
ทำไมมันถึงหลุดสายตา เพราะเราตรวจผิดชั้น เวลาอ่านงานที่ AI เขียน เราตรวจว่า มีการอ้างอิงไหม ไม่ใช่ ตัวเลขนี้อยู่ในแหล่งนั้นจริงไหม สองอย่างนี้ต่างกันคนละโลก และช่องว่างระหว่างมันคือที่ที่ตัวเลขปลอมอาศัยอยู่
กฎจากงานวัดความเสี่ยง: control ที่ผู้ถูกควบคุมเป็นคนรายงานผลเอง ไม่ใช่ control มันคือพิธีกรรม ในงาน model validation เราถึงไม่เคยให้ทีมที่สร้างโมเดลเป็นคนเซ็นรับรองโมเดลตัวเอง หลักการเดียวกันใช้กับ AI ที่เขียนงานให้เรา — คำยืนยันของมันว่า "ตรวจแล้ว" ไม่มีน้ำหนักใด ๆ ถ้าเราไม่ได้เห็นหลักฐานว่ามันเปิดแหล่งจริง
ตัวอย่างสด ๆ อยู่ในข่าวที่ผมเพิ่งเขียนวันนี้ สุนทรพจน์ของรองผู้ว่าการธนาคารกลางอังกฤษที่เวที ECB Sintra ถูกหลายสำนักพาดหัวโดยอ้างสัดส่วนบริษัทการเงินที่ใช้ agentic AI ราวกับเป็นตัวเลขจากปากผู้พูด ผมเปิดตัวบทฉบับเต็มแล้วไล่หาสถิติทุกตัว — ไม่มีตัวเลขร้อยละใดในสุนทรพจน์นั้นเลย รายละเอียดอยู่ในข่าว BoE ยอมรับกรอบกำกับเดิมไม่ได้ออกแบบมาเพื่อ AI agent ตัวเลขไม่ได้ถูกกุขึ้น มันแค่ถูกจับไปวางผิดปาก ซึ่งในสไลด์ที่เสนอคณะกรรมการ ผลลัพธ์ไม่ต่างกัน
2. ด่านที่ 1 — สัญญาแหล่งอ้างอิง ที่เขียนก่อนลงมือเขียนงาน
ด่านแรกไม่ใช่เครื่องมือ แต่เป็นลำดับการทำงาน กฎมีข้อเดียว: ห้ามพิมพ์ตัวเลขลงในร่าง ก่อนที่ตัวเลขนั้นจะมีบรรทัด quote รองรับอยู่ในไฟล์แยกแล้ว ไฟล์นั้นผมเรียกว่าสัญญาแหล่งอ้างอิง (sources contract) หน้าตาเรียบง่ายมาก
ประโยคต้นฉบับ (ccaf-profitability): "Only 40% of respondents report increased
profitability from AI, while 43% report no change" (ที่มา: 1)
#### **Works cited**
1. Report finds uneven AI adoption in financial services — Cambridge Judge Business School
https://www.jbs.cam.ac.uk/2026/report-finds-uneven-ai-adoption-in-financial-services/
หัวใจอยู่ที่คำว่า verbatim — quote ต้องเป็นข้อความคำต่อคำที่ปรากฏในหน้านั้นจริง ไม่ใช่การสรุปความ เพราะถ้าเป็นการสรุป เครื่องจักรจะตรวจอะไรไม่ได้เลย และเมื่อ quote เป็นคำต่อคำ เราจึงเช็คได้ตรง ๆ ว่าตัวเลขในร่างโผล่อยู่ใน quote หรือไม่
เวลาสั่ง Claude ให้หาข้อมูล ผมสั่งเป็นสองจังหวะแยกกันเสมอ จังหวะแรกให้มันไปดึง quote คำต่อคำมาใส่สัญญา ห้ามเขียนบทความ จังหวะที่สองค่อยให้เขียนโดยห้ามใช้ตัวเลขนอกสัญญา การแยกสองจังหวะทำให้โมเดลไม่มีโอกาส "เขียนไปคิดตัวเลขไป" ซึ่งเป็นจังหวะที่การหลอนเกิดขึ้นมากที่สุด
มุมคนทำ model validation: นี่คือ input control ธรรมดา ๆ — จำกัดสิ่งที่ป้อนเข้าโมเดล แทนที่จะไปไล่จับความผิดที่ปลายทาง ต้นทุนของด่านนี้คือความช้าตอนหาแหล่ง ซึ่งถูกกว่าต้นทุนของการแก้ข่าวหลังเผยแพร่มาก
3. ด่านที่ 2 — สคริปต์ที่ผู้เขียนโกงตัวเองไม่ได้
ด่านที่สองคือเครื่องจักร มันทำงานง่ายมาก: ดึงตัวเลขสถิติทุกตัวออกจากร่าง แล้วถามทีละตัวว่าตัวเลขนี้ปรากฏใน quote ไหนของสัญญาหรือเปล่า ถ้าไม่ มันไม่ถามความเห็นใคร มันตกทันที ก็อปไปวางเป็น check_numbers.py แล้วใช้ได้เลย ไม่ต้องลงไลบรารีอะไรเพิ่ม
#!/usr/bin/env python3
"""check_numbers.py — ทุกตัวเลขในร่าง ต้องอยู่ใน quote ของแหล่งอ้างอิงจริง
ใช้: python3 check_numbers.py draft.md sources.md
exit 0 = ผ่าน · exit 1 = มีตัวเลขที่ไม่มีแหล่ง (อย่าเพิ่งเผยแพร่)
"""
import re
import sys
# ตัวเลขที่ "ปั้นง่าย" — สถิติ/เงิน/จำนวนใหญ่ (ปีไม่นับ เพราะเป็นวันที่ ไม่ใช่สถิติ)
CLAIM = [
re.compile(r"(\d[\d,]*\.?\d*)\s*%"),
re.compile(r"ร้อยละ\s*(\d[\d,]*\.?\d*)"),
re.compile(r"(\d[\d,]*\.?\d*)\s*(?:ล้าน|พันล้าน|หมื่นล้าน)"),
re.compile(r"(\d[\d,]*\.?\d*)\s*(?:billion|million|trillion)", re.I),
]
def tok(raw):
return raw.replace(",", "").rstrip(".")
def strip_noise(md):
md = re.sub(r"^---\n.*?\n---\n", "", md, flags=re.S) # frontmatter
md = re.sub(r"```.*?```", "", md, flags=re.S) # code fences
return md
def numbers_in(md):
seen, out = set(), []
for pat in CLAIM:
for m in pat.finditer(md):
t = tok(m.group(1))
if not t or t in seen or re.fullmatch(r"(?:19|20)\d{2}", t):
continue
seen.add(t)
out.append((m.group(0).strip(), t))
return out
def quotes_in(src):
return re.findall(r'"([^"]+)"', src)
def main():
if len(sys.argv) != 3:
sys.exit(__doc__)
draft = strip_noise(open(sys.argv[1], encoding="utf-8").read())
quoted = " ".join(quotes_in(open(sys.argv[2], encoding="utf-8").read()))
quoted_tokens = " ".join(tok(q) for q in re.findall(r"\d[\d,]*\.?\d*", quoted))
bad = 0
for raw, t in numbers_in(draft):
ok = re.search(rf"(?<!\d){re.escape(t)}(?!\d)", quoted_tokens)
print(f"{'✅' if ok else '❌'} {raw:<12} {'พบใน quote' if ok else 'ไม่มี quote รองรับ'}")
bad += 0 if ok else 1
print(f"\n{'ผ่าน' if not bad else f'ตก {bad} ตัว — ห้ามเผยแพร่'}")
return 1 if bad else 0
if __name__ == "__main__":
sys.exit(main())
อ่านทีละส่วนว่าแต่ละอย่างกันอะไร
CLAIMเก็บเฉพาะตัวเลขที่ปั้นง่าย — เปอร์เซ็นต์ เงิน จำนวนหลักล้าน ส่วนตัวเลขโครงสร้างอย่าง "3 ด่าน" หรือ "5 ขั้นตอน" ไม่ถูกจับ เพราะมันมาจากเนื้อหาไม่ใช่จากแหล่ง ถ้าจับหมดคนเขียนจะรำคาญจนเลิกใช้ และ control ที่ไม่มีใครใช้คือ control ที่ไม่มีอยู่- บรรทัด
re.fullmatch(r"(?:19|20)\d{2}", t)ตัดปีทิ้ง — ปีคือวันที่ ไม่ใช่สถิติ ถ้าไม่ตัด ทุกบทความจะตกเพราะคำว่าปีปัจจุบัน strip_noiseลบ frontmatter กับ code fence — โค้ดตัวอย่างในบทความไม่ใช่ข้ออ้างเชิงข้อเท็จจริง จึงไม่ต้องมีแหล่งquoted_tokensเก็บเฉพาะตัวเลขที่อยู่ในเครื่องหมายคำพูดของไฟล์สัญญา — จุดนี้คือหัวใจ ตัวเลขที่ผู้เขียนพิมพ์ไว้นอก quote ไม่นับ แปลว่า ผู้เขียนโกงตัวเองไม่ได้ด้วยการพิมพ์ตัวเลขลงไปเฉย ๆ ต้องยกข้อความจากแหล่งมาจริง(?<!\d)กับ(?!\d)กันการจับผิดตัว — เลข 43 ต้องไม่ไปแมตช์กับ 143 ที่บังเอิญอยู่ในแหล่ง
ลองของจริง สมมติร่างเขียนว่า มีเพียง 40% ที่บอกว่ากำไรเพิ่มขึ้นจริงจาก AI ขณะที่ 43% บอกว่าไม่เปลี่ยนแปลง แต่ไฟล์สัญญายังว่างเปล่า ไม่มี quote ใดเลย
$ python3 check_numbers.py draft.md sources_empty.md
❌ 40% ไม่มี quote รองรับ
❌ 43% ไม่มี quote รองรับ
ตก 2 ตัว — ห้ามเผยแพร่
$ echo $?
1
ทีนี้ใส่ quote คำต่อคำจากรายงาน CCAF ลงในสัญญา แล้วรันใหม่ด้วยไฟล์เดิม
$ python3 check_numbers.py draft.md sources.md
✅ 40% พบใน quote
✅ 43% พบใน quote
ผ่าน
$ echo $?
0
ร่างไม่ได้เปลี่ยนสักตัวอักษร สิ่งที่เปลี่ยนคือหลักฐาน และนี่คือพฤติกรรมที่เราต้องการจาก gate — มันไม่สนใจว่าใครเขียน มันสนใจว่ามีหลักฐานหรือไม่ เพราะ exit code เป็น 0 หรือ 1 คุณจึงเสียบมันเข้า pre-commit hook หรือ CI ได้ทันที ตัวเลขที่ไม่มีแหล่งจะ commit ไม่ผ่านตั้งแต่เครื่องตัวเอง
กับดักที่ผมเจอมาแล้ว: gate เวอร์ชันแรกของผมตรวจแค่ว่าไฟล์รายงานผลตรวจ มีคำว่า verified อยู่ไหม ผลคือ AI เขียนคำว่า verified ลงไปเอง แล้วผ่านฉลุย บทเรียนคือ อย่าตรวจคำประกาศ ให้ตรวจของ — เช็คว่าตัวเลขอยู่ใน quote จริง ไม่ใช่เช็คว่ามีใครบอกว่าตรวจแล้ว
4. ด่านที่ 3 — ดึงแหล่งใหม่สดตอนจะเผยแพร่
สองด่านแรกยังมีรูอยู่หนึ่งรู: ถ้าผู้เขียนเป็นคนพิมพ์ quote เอง มันก็แต่ง quote ได้เหมือนที่แต่งตัวเลข ด่านที่สามจึงเป็นด่านเดียวที่ผู้เขียนแตะไม่ได้ — ตอนจะเผยแพร่ ระบบจะไปโหลดทุก URL ในสัญญาใหม่สด ๆ แล้วเช็คว่า quote นั้นมีอยู่ในหน้านั้นจริง ไม่ใช้รายงานที่ผู้เขียนแนบมาเด็ดขาด
ผลลัพธ์แบ่งเป็นสี่สถานะ และแต่ละสถานะมีวิธีจัดการชัดเจน
- พบตรงเป๊ะ — ใช้ได้
- พบบางส่วน เกินเกณฑ์คำที่ตั้งไว้ — ใช้ได้ แต่ต้องอ่านด้วยตา เพราะมักเกิดจากเว็บใส่เครื่องหมายคำพูดหรือขีดคนละแบบ
- ไม่พบ quote ในหน้านั้น — ตัดตัวเลขทิ้ง หรือหาแหล่งใหม่ ห้ามเดา
- โหลดหน้านั้นไม่ได้ — ยังไม่นับว่าตรวจแล้ว บางเว็บบล็อกการเรียกอัตโนมัติ ให้ใช้แหล่งกระจกหรือประกาศต้นทางแทน
จุดที่คนมักพลาดคือเหมารวมสถานะ "โหลดไม่ได้" เป็น "ผ่าน" เพราะรู้สึกว่าแหล่งดูน่าเชื่อถือ ทั้งที่มันแปลว่า ยังไม่มีใครตรวจ ต่างหาก ในภาษาของงานกำกับความเสี่ยง นี่คือการเอา evidence gap ไปนับเป็น evidence
กฎจากงานวัดความเสี่ยง: หลักฐานที่ฝ่ายผลิตงานเป็นคนหยิบยื่นให้ ต้องถูกสุ่มตรวจซ้ำโดยฝ่ายที่ไม่มีส่วนได้เสีย ในระบบเนื้อหา ฝ่ายที่ไม่มีส่วนได้เสียคือสคริปต์ที่รันตอน deploy ไม่ใช่ตัวโมเดลที่เขียนบทความ
5. เอาไปใช้กับงานที่ไม่ใช่บทความ
หลักสามด่านนี้ไม่ได้ผูกกับงานเขียนข่าวเลย มันคือรูปแบบเดียวกับที่ใช้ได้กับทุกงานที่ AI ผลิตตัวเลขให้เรา
- สไลด์เสนอผู้บริหาร — บังคับให้ทุกตัวเลขบนสไลด์มี cell อ้างอิงในชีตแนบ ที่เก็บ quote คำต่อคำจากเอกสารต้นทาง ไม่ใช่แค่ชื่อรายงาน
- สรุปงบการเงินหรือ 56-1 — ให้โมเดลคัด quote จากเอกสารต้นฉบับก่อน แล้วค่อยให้สรุป ตัวเลขที่ไม่ได้มาจาก quote ถือว่าไม่มีอยู่
- รายงานที่ต้องส่งผู้ตรวจ — เก็บสัญญาแหล่งอ้างอิงไว้เป็นหลักฐานการทำงาน เพราะสิ่งที่ผู้ตรวจถามเสมอไม่ใช่ "ตัวเลขถูกไหม" แต่คือ "คุณรู้ได้อย่างไรว่ามันถูก"
ผมเขียนกฎข้อนี้ลงในไฟล์ CLAUDE.md ของ workspace เพื่อให้ทุก session เริ่มต้นด้วยกติกาเดียวกัน โดยไม่ต้องสั่งซ้ำ
## ตัวเลข
- ห้ามพิมพ์ตัวเลขสถิติ/เงิน ลงในร่าง ก่อนมี quote คำต่อคำใน `sources.md`
- quote ต้องเป็นข้อความจากหน้าเว็บจริง ห้ามสรุปความ
- ก่อน commit: `python3 check_numbers.py draft.md sources.md` ต้อง exit 0
- ตัวเลขที่โหลดแหล่งไม่ได้ = ยังไม่ตรวจ (ไม่ใช่ผ่าน) → ตัดทิ้งหรือหาแหล่งใหม่
ภาพรวม
ตัวเลขปลอมไม่ได้เล็ดลอดออกไปเพราะโมเดลแย่ แต่เพราะระบบตรวจถามคำถามผิด เราชอบถามว่า มีอ้างอิงไหม ทั้งที่คำถามที่มีความหมายคือ ตัวเลขนี้อยู่ในแหล่งนั้นจริงหรือเปล่า สามด่านที่เล่ามาตอบคำถามหลังทั้งหมด — ด่านแรกบังคับให้หลักฐานมาก่อนข้อความ ด่านที่สองให้เครื่องจักรเป็นคนตัดสินแทนความรู้สึก และด่านที่สามตัดโอกาสที่ผู้เขียนจะให้เกรดตัวเอง ทั้งสามด่านรวมกันเขียนได้ในไม่กี่สิบบรรทัด และมันจับของจริงมาแล้ว
ที่ผมให้ไปในบทความนี้คือด่านที่สอง ซึ่งเป็นชิ้นที่เอาไปใช้ได้เลยวันนี้ ส่วนการต่อทั้งสามด่านเข้าเป็นสายพานเดียว — สัญญาแหล่งอ้างอิงที่ผูกกับ git hook, การดึงแหล่งใหม่สดตอน deploy, การจัดการเว็บที่บล็อกบอต, และการวางลำดับ task ให้ AI ทำงานเองทั้งคืนโดยไม่หลุดกรอบ — ผมประกอบไว้เป็น workspace ที่ก็อปไปทั้งก้อนได้ในคอร์ส Claude Code ถ้าคุณกำลังปล่อยให้ AI เขียนอะไรที่มีตัวเลขแล้วมีชื่อคุณอยู่ท้ายบทความ ผมคิดว่าคุ้มที่จะวางด่านพวกนี้ก่อนที่จะต้องมานั่งแก้ทีหลัง
ที่มา
อ่านต่อ
QC Pipeline สำหรับ AI Output: วิธีที่ Data Scientist ในแบงก์ตรวจงาน AI ก่อนเข้า Production
อ่านต่อ financeอ่าน MD&A ข้ามปี 2564–2569: ทำไมบริษัทเดียวเล่า 'เรื่อง' คนละเรื่องทุกปี — เคสจริง PSL เดินเรือกับสงครามการค้า
อ่านต่อ financeMD&A Search 3 แพ็กราคา — ฿399 / ฿799 / ฿1,399: จ่ายต่างกันเห็นกี่ปีย้อนหลัง (คู่มือเลือกแพ็กแบบตรงไปตรงมา)
อ่านต่อ