ลองถามโมเดลภาษาว่าคำว่า “strawberry” มีตัวอักษรกี่ตัว มีโอกาสสูงที่มันจะตอบผิด มันอาจจะบอกว่าสิบตัว หรืออาจจะเดาว่าสิบเอ็ดตัว มันจะตอบด้วยความมั่นใจเต็มเปี่ยม แต่ก็ยังคงผิดอยู่ดี ลองให้โมเดลตัวเดิมคำนวณดอกเบี้ยทบต้นของเงินกู้ หรือบวกเลขจำนวนมาก หรือนับวันทำการระหว่างสองวันที่ แล้วคุณมักจะได้คำตอบที่ดูน่าเชื่อถือ แต่ตัวเลขกลับคลาดเคลื่อนไปเล็กน้อยอย่างน่าอันตราย
สิ่งนี้เกิดขึ้นเพราะโมเดลภาษาขนาดใหญ่ไม่ได้ใช้เหตุผลเกี่ยวกับตัวเลขเหมือนที่มนุษย์ทำ แต่พวกมันทำนาย token ซึ่ง token อาจเป็นคำทั้งคำ ส่วนหนึ่งของคำ หรือตัวเลขเพียงหลักเดียว เมื่อโมเดลเห็นคำว่า “strawberry” มันไม่ได้เห็นตัวอักษรแปดตัวเรียงกันอยู่ แต่มันเห็นเป็นกลุ่มก้อนของข้อความ (chunks) มันไม่เคยถูกสอนให้นับตัวอักษร แต่ถูกสอนให้ทำนายว่ากลุ่มข้อความถัดไปควรจะเป็นอะไร ข้อจำกัดแบบเดียวกันนี้ยังใช้กับการคำนวณทางคณิตศาสตร์ด้วย โมเดลไม่มีเครื่องคิดเลขภายในตัว มันไม่มีตรรกะการทดเลข และไม่มีความเข้าใจเรื่องค่าประจำหลักที่แท้จริง เมื่อมันคูณ 148 ด้วย 279 มันไม่ได้กำลังทำการคูณ แต่มันกำลังจับคู่รูปแบบ (pattern-matching) กับนิพจน์ที่คล้ายคลึงกันที่มันเคยเห็นระหว่างการฝึกฝน โดยการเดาว่าลำดับตัวเลขใดควรจะตามมา สำหรับผลรวมเล็กๆ น้อยๆ รูปแบบนั้นอาจแข็งแกร่งพอที่จะใช้งานได้ แต่สำหรับอะไรก็ตามที่ต้องการความแม่นยำสูง การเดานั้นจะผิดพลาดในที่สุด
สองหน้าที่ ในบอทตัวเดียว
วิธีการเขียน Prompt แบบมาตรฐานมักจะสั่งให้ระบบเดียวทำสองสิ่งที่แตกต่างกันอย่างสิ้นเชิงในเวลาเดียวกัน อย่างแรกคือ ทำความเข้าใจตรรกะของปัญหา และอย่างที่สองคือ ดำเนินการคำนวณทางคณิตศาสตร์ให้ถูกต้อง โมเดลทำหน้าที่แรกได้อย่างน่าประทับใจจริงๆ มันสามารถอ่านโจทย์ปัญหา สกัดตัวแปร สร้างความสัมพันธ์ และวางแผนแนวทางการแก้ปัญหาได้ แต่หลังจากนั้นมันต้องทำหน้าที่เป็นเครื่องคิดเลขของตัวเองด้วย และนั่นคือจุดที่ความต่อเนื่องเริ่มขาดสะบั้น ตัวเลขที่ผิดพลาดเพียงหลักเดียวในขั้นตอนที่สามจะส่งผลเสียต่อทุกขั้นตอนหลังจากนั้น ตรรกะอาจจะสมบูรณ์แบบ แต่คำตอบสุดท้ายกลับใช้ไม่ได้เพราะโมเดลบวกเลขผิด
Program-Aided Language Models หรือ PAL แก้ปัญหานี้ด้วยการแยกงานออกจากกัน แทนที่จะถามหาคำตอบจากโมเดล ให้คุณถามหาโปรแกรมแทน
นี่คือขั้นตอนการทำงานที่เกิดขึ้นจริง คุณนำเสนอโจทย์ โมเดลจะคิดหาตรรกะ กำหนดตัวแปร และวางโครงสร้างอัลกอริทึม จากนั้น แทนที่จะคำนวณผลลัพธ์ด้วยตัวเอง มันจะเขียนสคริปต์สั้นๆ ซึ่งมักจะเป็นภาษา Python สคริปต์นั้นจะถูกส่งต่อไปยัง code interpreter ของจริง ตัวแปลรหัสจะรันตรรกะนั้นและคืนผลลัพธ์ที่แม่นยำและแน่นอนกลับมา โมเดลทำหน้าที่อธิบายคณิตศาสตร์ ส่วน Python ทำหน้าที่คำนวณคณิตศาสตร์
การใช้เหตุผลผ่านการรันโค้ดในทางปฏิบัติ
ให้คิดว่า PAL คือการใช้เหตุผลที่รันได้ (executable reasoning) หากสคริปต์สามารถแก้ปัญหาได้ ก็ปล่อยให้โมเดลเขียนสคริปต์นั้น
ลองพิจารณาตัวอย่างที่เป็นรูปธรรม คุณต้องการคำนวณยอดเงินเมื่อครบกำหนดของเงินฝากประจำจำนวน ₹50,000 โดยมีอัตราดอกเบี้ยต่อปีที่ 8.5 เปอร์เซ็นต์ คิดดอกเบี้ยทบต้นทุกไตรมาส เป็นเวลาเจ็ดปี หากถามโมเดลภาษาโดยตรง มันอาจจะเขียนสูตร แทนค่า และคำนวณผลลัพธ์ผ่านกระบวนการคิด (chain of thought) แต่หากสังเกตดูดีๆ คุณอาจพบว่ามันจัดการเรื่องการทบต้นรายไตรมาสผิดพลาดโดยการหารอัตราดอกเบี้ยไม่ถูกต้อง หรือมันปัดเศษในขั้นตอนกลางทางและทำให้ข้อผิดพลาดนั้นส่งต่อไปยังขั้นตอนถัดไป คำตอบอาจจะดูสมเหตุสมผลแต่กลับคลาดเคลื่อนไปหลายร้อยรูปี
เมื่อใช้ PAL รูปแบบการโต้ตอบจะเปลี่ยนไป คุณสั่งให้โมเดลสร้างโค้ด Python ที่กำหนด principal = 50000, rate = 0.085, time = 7, และ n = 4 จากนั้นคำนวณ amount = principal * (1 + rate/n) ** (n * time) โมเดลจะส่งโค้ดออกมา จากนั้น Python runtime จะรันโค้ดนั้น คุณจะได้ตัวเลขที่แม่นยำจนถึงทศนิยมตำแหน่งสุดท้ายในทุกๆ ครั้ง ไม่มีการเดาในการคูณ ไม่มีการมโนเศษที่เหลือขึ้นมาเอง และไม่มีข้อผิดพลาดจากการปัดเศษที่ดูเหมือนจะมั่นใจ
รูปแบบเดียวกันนี้ยังใช้กับการคำนวณวันที่ได้ด้วย ลองถามโมเดลว่าวันที่ใดจะตรงกับอีก 120 วันทำการนับจากวันนี้ โดยไม่นับรวมวันเสาร์-อาทิตย์ โมเดลที่ใช้ข้อความเพียงอย่างเดียวอาจจะนับไปข้างหน้าแล้วพลาดตรงวันเสาร์ แต่แนวทางแบบ PAL จะให้โมเดลเขียนสคริปต์โดยใช้ตรรกะของ datetime และ calendar แล้วปล่อยให้ตัวแปลรหัสทำการวนลูปอย่างแม่นยำ การจัดการข้อมูลก็ทำงานในลักษณะเดียวกัน หากคุณต้องการแยกข้อมูลจาก CSV ที่ยุ่งเหยิง กรองข้อมูล JSON ที่ซ้อนกัน หรือรันการแปลงทางสถิติอย่างรวดเร็ว โมเดลควรทำหน้าที่ร่างตรรกะ ในขณะที่ตัวแปลรหัสจัดการเรื่องการวนลูปข้อมูล
ทำไมเรื่องนี้ถึงสำคัญจริงๆ
การเปลี่ยนจากการตอบด้วยข้อความมาเป็นการใช้โค้ดที่รันได้ มอบข้อได้เปรียบในทางปฏิบัติสามประการ
Determinism. โมเดลภาษาที่ถูกถามคำถามเดิมซ้ำสองครั้งอาจมีการเปลี่ยนการใช้คำหรือเปลี่ยนตัวเลขบางตัว ในขณะที่อินเทอร์พรีเตอร์ (interpreter) จะคืนค่าผลลัพธ์เดิมสำหรับอินพุตเดิมเสมอ ความเสถียรนั้นมีความสำคัญอย่างยิ่งในงานบัญชี โลจิสติกส์ การจัดตารางเวลา และการคำนวณทางวิศวกรรมใดๆ ที่ความสม่ำเสมอเป็นสิ่งจำเป็นที่ขาดไม่ได้
Verifiability. เมื่อโมเดลส่งเหตุผลมาให้คุณสามย่อหน้า คุณต้องอ่านทุกประโยคเพื่อตามหาตัวเลขที่ผิดเพียงตัวเดียว แต่เมื่อมันส่งสคริปต์สิบบรรทัดมาให้ คุณสามารถตรวจสอบโค้ดได้ คุณสามารถตรวจสอบได้ว่าสูตรดอกเบี้ยทบต้นนั้นถูกต้องก่อนที่อินเทอร์พรีเตอร์จะเริ่มทำงานด้วยซ้ำ คุณสามารถตรวจสอบชื่อตัวแปร มองหาข้อผิดพลาดแบบ off-by-one และแม้แต่ทำ version-control ให้กับโซลูชันนั้นได้ พื้นที่สำหรับความผิดพลาดที่ซ่อนอยู่จึงลดลงอย่างมหาศาล
Reliability. โมเดลทำหน้าที่ในขอบเขตของตนเอง มันทำในสิ่งที่ถูกสร้างมาให้ทำ นั่นคือการใช้เหตุผลเกี่ยวกับโครงสร้าง อรรถศาสตร์ (semantics) และการย่อยปัญหา (problem decomposition) ส่วนเครื่องจักรก็ทำในสิ่งที่ถูกสร้างมาให้ทำ นั่นคือการคำนวณอย่างแม่นยำ การแยกส่วนความรับผิดชอบ (separation of concerns) เช่นนี้คือวิธีที่ซอฟต์แวร์ที่น่าเชื่อถือถูกออกแบบสถาปัตยกรรมขึ้นมา การใช้ Composition ให้ผลลัพธ์ที่ดีกว่าการออกแบบแบบ monolithic
รันโค้ดเสมือนเป็นข้อมูลที่ไม่น่าไว้วางใจ
จำเป็นต้องมีคำเตือนไว้สักนิด โค้ดที่ถูกสร้างขึ้นควรถูกปฏิบัติเหมือนเป็นอินพุตที่ไม่น่าไว้วางใจ โมเดลอาจเขียนสคริปต์ที่มีลูปไม่สิ้นสุด (infinite loop) การร้องขอเครือข่ายที่ไม่จำเป็น หรือการดำเนินการกับระบบไฟล์ที่คุณไม่ได้สั่ง ควรเรียกใช้งานโปรแกรมเหล่านี้ภายใน sandbox ที่แยกส่วนออกมาเสมอ ใช้คอนเทนเนอร์ที่มีสิทธิ์จำกัด, ฟังก์ชันแบบ serverless ที่ไม่มีการเข้าถึงเครือข่าย หรือสภาพแวดล้อมที่ควบคุมอย่างเข้มงวดซึ่งมีการจำกัดเวลา CPU และไม่มีการจัดเก็บข้อมูลแบบถาวร (persistent storage) ความปลอดภัยไม่ใช่เพียงหมายเหตุประกอบในที่นี้ แต่มันคือส่วนหนึ่งของการออกแบบระบบ
จุดที่ PAL ทำงานได้ดี และจุดที่มันสิ้นสุดลง
PAL ทำงานได้อย่างยอดเยี่ยมสำหรับคณิตศาสตร์ วันที่ และการจัดการข้อมูลที่มีโครงสร้าง มันช่วยขจัดข้อผิดพลาดเชิงกลไกที่มักเกิดขึ้นกับการใช้เหตุผลผ่านข้อความเพียงอย่างเดียว
อย่างไรก็ตาม มันไม่ได้ช่วยแก้ไขตรรกะที่ผิดพลาด หากโมเดลเลือกสูตรที่ผิด,
