บทที่ 32

บทที่ 32 — การมาสก์ข้อมูลส่วนบุคคลภาษาไทย

เปลี่ยนข้อมูลส่วนบุคคลภาษาไทยให้เป็น placeholder ก่อนที่ข้อความจะออกจาก เครื่องคุณ แล้วใส่ค่าจริงกลับคืนก่อนที่คุณจะเห็นคำตอบ โมเดลทำงานกับ [PHONE_1] และ [ID_2] ส่วน log ของ provider ไม่เคยเห็นตัวเลขจริง

ปิดไว้เป็นค่าเริ่มต้น เปิดใน .thclaws/settings.json

{ "sensitive": { "enabled": true } }

ไม่มีปุ่มใน GUI และไม่มี slash command — นี่เป็นการตัดสินใจระดับไฟล์ตั้งค่า ทำครั้งเดียวต่อโปรเจกต์

หน้าตาเป็นอย่างไร

คุณพิมพ์ข้อความที่มีเบอร์โทรอยู่ในนั้น โมเดลได้รับ

ผู้ติดต่อคือ [PHONE_1] โปรดร่างอีเมลถึงเขา

โมเดลตอบโดยใช้ placeholder นั้น ก่อนคำตอบจะถึงมือคุณ ค่าจริงจะถูกใส่กลับ พร้อมเครื่องหมายให้คุณเห็นว่าเกิดอะไรขึ้น

ผมจะร่างอีเมลถึง 🔓« 081-234-5678 » ให้ครับ

เครื่องหมาย 🔓« » เป็นแค่การแสดงผล สิ่งที่เครื่องเอาไปใช้ต่อ — ไฟล์ที่เขียน tool ที่เรียก และประวัติ session — ได้ค่าจริงที่ไม่มีเครื่องหมายติดไปด้วย

กฎที่ทำให้มันปลอดภัย

ประวัติเก็บเป็น plaintext ส่วนการมาสก์อยู่ที่สายส่ง

นี่คือหลักการที่ควรเข้าใจ เพราะมันตรงข้ามกับที่หลายคนคาด ไฟล์ session บน ดิสก์ของคุณเก็บค่าจริง การมาสก์เกิดขึ้นตอนประกอบ request ทุก turn ใหม่ทุกครั้ง

การทำอีกแบบ — มาสก์ลงไปในประวัติเลย — ฟังดูเรียบร้อยกว่าแต่พัง เพราะ placeholder ที่ถูกเขียนลงประวัติใน turn ที่ 3 ต้องยังหมายถึงสิ่งเดิมใน turn ที่ 30 ข้าม compaction ข้าม /load และข้ามการสลับโมเดล พลาดการ re-map ครั้งเดียว โมเดลก็ไปให้เหตุผลเกี่ยวกับคนผิดคนแล้ว การมาสก์ที่สายส่งแปลว่า ทุก turn มาสก์ใหม่จากข้อความจริง และ coreference map ทำให้ [PHONE_1] ชี้ไป เบอร์เดิมตลอดอายุ session

อะไรถูกมาสก์บ้าง

มีตัวตรวจจับในตัวสี่แบบ แต่ละแบบมี validator ไม่ใช่แค่ pattern เปล่า ๆ

ประเภท Placeholder ตรวจจับอย่างไร
เลขบัตรประชาชน [ID_1] หาเลข 13 หลักก่อน แล้วให้ checksum ตามมาตรฐาน เป็นตัวตัดสิน เลข 13 หลักที่ไม่ใช่บัตรจริงจะถูกปล่อยผ่าน
เบอร์โทร [PHONE_1] รูปแบบเบอร์ไทย และถูกปฏิเสธเมื่อมีตัวเลขติดอยู่ข้าง ๆ จึงไม่ไปแคะเบอร์โทรออกจากเลขบัญชีธนาคาร
ทะเบียนรถ [PLATE_1] ต้องมีบริบท คือมี ทะเบียน… นำหน้า หรือมีชื่อจังหวัดตามหลัง
ชื่อที่มีคำนำหน้า [NAME_1] นาย / นาง / นางสาว / น.ส. / ด.ช. / ด.ญ. ตามด้วยชื่อ

เลขไทยถูกแปลงก่อน ๐๘๑… คือเบอร์โทรจริง และเวอร์ชันแรกเคยปล่อยให้มัน หลุดไปโดยไม่ถูกมาสก์ นั่นคือ failure mode เดียวที่ฟีเจอร์นี้ต้องไม่มีเด็ดขาด คือรั่วเพราะ pattern ไม่รู้จักตัวเลข ระบบจึงแปลง ๐-๙ เป็น ASCII ก่อน match

ทุกส่วนของ request ที่มีข้อความถูกครอบคลุมหมด ทั้งข้อความของคุณ system prompt อาร์กิวเมนต์ของ tool และผลลัพธ์ของ tool

ความแม่นยำคือข้อจำกัด ไม่ใช่ความครอบคลุม

นี่คือการตัดสินใจเชิงออกแบบที่อธิบายทุกอย่างที่เหลือในบทนี้

ภาษาไทยเขียนติดกันไม่เว้นวรรค pattern ที่หลวมจึงไม่ได้แค่มาสก์เกินไปหนึ่งคำ แต่กลืนทั้งประโยครอบ ๆ ไปด้วย และโมเดลก็ได้รับ prompt ที่เละ ตัวตรวจจับจึง ถูกทำให้แคบโดยเจตนา และแต่ละตัวมีเงื่อนไขขอบเขตหรือบริบทกำกับ

กฎเวอร์ชันแรกให้ผล 119 จุดบนบทความภาษาไทยห้าบทที่ไม่มีข้อมูลส่วนบุคคลอยู่ เลย นั่นคือที่มาของการจูน

ตัวอย่างที่ชัดที่สุด: คุณ ไม่ใช่ตัวกระตุ้นชื่อ เพราะมันคือสรรพนามบุรุษ ที่สองในชีวิตประจำวัน และปรากฏ 80 ครั้งในคลังข้อความปลอด PII ชุดเดียวกันนั้น การนับ คุณสมชาย เป็นชื่อจะเท่ากับนับบทสนทนาไทยทั่วไปครึ่งหนึ่งเป็นข้อมูล ส่วนบุคคล ชื่อที่นำหน้าด้วย คุณ จึงถูกปล่อยไว้โดยตั้งใจ

ในทำนองเดียวกัน พยัญชนะสองสามตัวตามด้วยตัวเลขก็ดูเหมือนทะเบียนรถ แต่ก็เป็น ภาษาไทยธรรมดาด้วย (ครบ 3 ปี) ทะเบียนจึงต้องมีบริบทประกอบ

อะไรที่มันจับไม่ได้

ควรเข้าใจให้ชัดก่อนจะพึ่งพามัน

  • ชื่อที่ไม่มีคำนำหน้าทางการ เช่น คุณสมชาย หรือ สมชาย เฉย ๆ นี่คือ ช่องว่างที่ใหญ่ที่สุด และเป็นความตั้งใจตามเหตุผลข้างบน การตรวจจับชื่อและ ที่อยู่แบบอิสระต้องใช้โมเดลภาษา ไม่ใช่ regex ซึ่งชั้นนั้นอยู่ในแผน ยังไม่ ได้ ship
  • ที่อยู่ ด้วยเหตุผลเดียวกัน
  • อีเมลและเลขบัญชีธนาคาร ยังไม่มีตัวตรวจจับ
  • ใบหน้าและเอกสารในรูปภาพ รูปถ่ายบัตรประชาชนคือข้อมูลส่วนบุคคลจริงที่กฎ ระดับข้อความแตะไม่ได้ รูปภาพผ่านไปโดยไม่ถูกแตะต้อง
  • อะไรก็ตามที่อยู่นอกรูปแบบภาษาไทย นี่เป็นฟีเจอร์เฉพาะภาษาไทย

ให้ใช้กลไก placeholder นี้ในฐานะการลดการเปิดเผยอย่างมีนัยสำคัญ ไม่ใช่ในฐานะ การรับประกันการปฏิบัติตามกฎหมาย ถ้ามีเอกสารที่ต้องไม่ถึงมือ provider เด็ดขาด ก็อย่าวางมันลงในแชทที่วิ่งไปหา provider

ที่ไหนที่มันไม่ทำงาน

มีสองกรณีที่ปิดการมาสก์ทั้งหมด และเป็นความตั้งใจทั้งคู่

  • โมเดลในเครื่อง Ollama, LM Studio, vLLM และ llama.cpp รันบนเครื่องคุณ ไม่มีอะไรออกจากเครื่อง การมาสก์จึงมีแต่จะกิน context ที่โมเดลควรได้ใช้ ระบบข้ามให้เป็นราย request โดยดูจากโมเดลที่ใช้จริงใน turn นั้น
  • Multiuser pod การมาสก์ปฏิเสธที่จะติดอาวุธเมื่อ engine รันแบบหลาย tenant เพราะ worker ตัวเดียวให้บริการหลายคน และ coreference map เป็นของราย process failure mode ที่จะเกิดคือ [PHONE_1] ของ tenant หนึ่งไปแปลงกลับเป็นเบอร์ของ อีก tenant การปฏิเสธจึงเป็นคำตอบเดียวที่ปลอดภัย

thinking block ก็ถูกปล่อยไว้เช่นกัน เพราะการให้เหตุผลของโมเดลมีแต่ placeholder อยู่แล้วโดยธรรมชาติ (มันเห็นแต่ placeholder มาตลอด) และ Anthropic เซ็นบล็อกพวกนั้นไว้ การเขียนทับจึงจะทำให้ลายเซ็นเสีย

โมเดลถูกบอกอะไรบ้าง

ขณะที่การมาสก์ทำงานอยู่ system prompt จะมีหัวข้อ Redacted values เพิ่มเข้ามา มันมีอยู่เพราะความผิดพลาดที่เห็นได้ชัดเป็นเรื่องการสนทนา ไม่ใช่เรื่องเทคนิค โมเดลที่เห็น [PHONE_1] แล้วตีความว่า ข้อมูลหายไป จะถามคุณกลับมาอย่างสุภาพ ว่าขอเบอร์จริงหน่อย — แล้วตัว un-masker ก็จะเขียนประโยคนั้นใหม่ให้กลายเป็นการ อ้างว่าเบอร์จริงคือ placeholder

โมเดลจึงถูกบอกสั้น ๆ ว่า placeholder แทนข้อมูลจริงที่ผู้ใช้ให้มาแล้ว มันไม่ได้ หายไป ไม่ใช่ template และไม่ใช่ error ให้ใช้ซ้ำตรง ๆ แล้วค่าจริงจะถูกแทนกลับ ก่อน tool ทำงาน และอย่าพยายาม validate หรือจัดรูปแบบใหม่ เพราะมันมองไม่เห็น ตัวเลขที่อยู่ข้างใต้

คำเฉพาะของคุณเอง

ตัวตรวจจับรองรับ dictionary ที่กำหนดเองได้ คือคำเฉพาะของโปรเจกต์ที่จะถูกมาสก์ เป็น [CUST_1] แต่ยังไม่มี key ใน settings ให้ตั้ง วันนี้จึงเข้าถึงได้จาก โค้ดเท่านั้น ถ้าคุณต้องการมาสก์ข้อความเฉพาะบางอย่าง นั่นคือช่องว่าง ไม่ใช่การ ตั้งค่าที่คุณหาไม่เจอ

การเปิดใช้งาน

{
  "sensitive": { "enabled": true }
}

ตั้งรายโปรเจกต์ใน .thclaws/settings.json การเปลี่ยนค่ามีผลกับ request ใหม่ ส่วน session ที่ติดอาวุธอยู่แล้วจะรักษา coreference map ไว้ การเปลี่ยน settings เรื่องอื่นกลางบทสนทนาจึงไม่ทำให้เลข placeholder ของคุณเปลี่ยน

อย่าลืมว่า settings.json ที่รูปแบบผิดจะถูกอ่านผ่านไปเงียบ ๆ ทุก flag แบบ opt-in จะกลายเป็นปิดโดยไม่มีคำเตือน ถ้าตั้งค่านี้แล้วไม่เห็น placeholder เลย ให้ตรวจก่อนว่าไฟล์เป็น JSON ที่ถูกต้อง

การแก้ปัญหา

อาการ สาเหตุ วิธีแก้
ไม่มีอะไรถูกมาสก์เลย ยังไม่ได้เปิด หรือ settings.json parse ไม่ผ่าน ตรวจ JSON ให้ถูก และ sensitive.enabled ต้องเป็น true
ตั้งค่าถูกแล้วแต่ยังไม่มาสก์ คุณใช้โมเดลในเครื่อง หรืออยู่บน multiuser pod ปกติ — ดูข้างบน
มีชื่อหลุดไป ชื่อนั้นไม่มีคำนำหน้าทางการ หรือใช้ คุณ ปกติในตอนนี้ การตรวจชื่ออิสระยังไม่ได้ ship
เลข 13 หลักไม่ถูกมาสก์ มันไม่ผ่าน checksum บัตรประชาชน แปลว่าไม่ใช่เลขบัตร ทำงานตามที่ตั้งใจไว้
โมเดลขอ “เบอร์จริง” กลับมา มันอ่าน placeholder ว่าข้อมูลหายไป คำอธิบายใน system prompt มีไว้กันเรื่องนี้ ถ้ายังเกิดซ้ำให้แจ้ง
เห็น 🔓« » ในไฟล์ที่ agent เขียน เป็นบั๊ก — เครื่องหมายควรอยู่แค่ตอนแสดงผล แจ้งได้เลย

ดูเพิ่มเติม

  • บทที่ 5 — permissions และการที่ settings.json parse ไม่ผ่านแบบเงียบ ๆ
  • บทที่ 6 — provider ตัวไหนเป็นโมเดลใน เครื่อง (และจึงข้ามการมาสก์)
  • บทที่ 27 — cloud gateway เห็นอะไรและไม่เห็นอะไร