เราลบตัวแยกวิเคราะห์รายจ่ายภาษาธรรมชาติ
ตัวแยกวิเคราะห์แบบกฎอยู่ได้หนึ่งสัปดาห์ ประโยคธรรมดาสี่ประโยคลงเงินให้ผิดคน และกฎการปฏิเสธข้อเดียวก็มาแทนกองตัวกันทั้งหมด
เราลบตัวแยกวิเคราะห์ที่เพิ่งเขียนเสร็จทิ้งไป ความพยายามครั้งแรกของ Dimesum ในการแยกวิเคราะห์รายจ่ายจากภาษาธรรมชาติคือเอนจินกฎเกณฑ์ และประโยคธรรมดาสี่ประโยคก็ทำให้มันต้องเลิกใช้ dinner 12-08 400 ถูกอ่านเป็น ฿12 ravioli 600 ดึงสมาชิกชื่อ Ravindra เข้ามาในการหาร kirana 500 เรียกเก็บกับสมาชิกชื่อ Kiran และ refund -483.50 กลายเป็นการเรียกเก็บ ฿483.50
การเข้าใจประโยคเป็นหน้าที่ของโมเดลเท่านั้น ไม่ใช่ของสิ่งอื่นใด สิ่งที่มาแทนเอนจินกฎเกณฑ์คือขั้นเดียวชื่อ amount_only ตัวเลขตัวเดียว ที่คืนค่าก็ต่อเมื่อข้อความมีตัวเลือกจำนวนเงินที่ชัดเจนเพียงตัวเดียว และไม่เคยกล่าวอ้างเรื่องบุคคล สองตัวเลือกหมายถึงไม่มีจำนวนเงิน กฎข้อเดียวมาแทนกองตัวกันที่พอกพูนขึ้นเรื่อย ๆ
ประโยคสี่ประโยคทำให้ตัวแยกวิเคราะห์แบบกฎจบลง
ตัวแยกวิเคราะห์ที่ถูกลบครอบคลุมชุดเอนทิตีทั้งหมดที่เอกสารออกแบบ AI ของเราระบุไว้ การจับคู่สมาชิกและชื่อเล่น พจนานุกรมคำยกเว้น การอนุมานผู้จ่าย พจนานุกรมหมวดหมู่ และค่าความเชื่อมั่นรายฟิลด์ที่ปรับจูนแล้ว ความล้มเหลวทั้งสี่ด้านล่างต่างมีวิธีแก้ที่ชัดเจน แต่ทุกวิธีแก้ก็คือตัวกันตัวใหม่ที่มีจุดบอดของตัวเอง
| สิ่งที่ผู้ใช้พิมพ์ | สิ่งที่ตัวแยกวิเคราะห์ทำ | ทำไมจึงเกิดขึ้น |
|---|---|---|
dinner 12-08 400 | อ่านจำนวนเงินเป็น ฿12 | ผู้อ่านเห็นวันที่และยอดรวม รีเจ็กซ์เห็นตัวเลขสามตัวและหยิบตัวแรก |
ravioli 600 | ดึงสมาชิกชื่อ Ravindra เข้ามาในการหาร | การจับคู่ชื่อเล่นแบบคลุมเครือให้คะแนนอาหารจานหนึ่งกับบุคคล |
kirana 500 | เรียกเก็บกับสมาชิกชื่อ Kiran | ตัวจับคู่ตัวเดียวกัน คราวนี้กับชื่อร้านค้า |
refund -483.50 | บันทึกการเรียกเก็บ ฿483.50 | ตัวเลขรอด แต่เครื่องหมายไม่รอด เงินจึงชี้ไปในทางตรงข้าม |
สองในสี่กรณีคือบั๊กเดียวกันที่สวมเสื้อผ้าต่างกัน การจับคู่แบบคลุมเครือไม่อาจแยกอาหารจานหนึ่งออกจากบุคคล หรือแยกร้านค้าออกจากบุคคลได้ เพราะในระดับตัวอักษร ravioli กับ Ravindra ดูคล้ายกันจริง ๆ หากบังคับให้จับคู่คำนำหน้ายาวขึ้น คุณก็จะทำให้ ravi พังไป ซึ่งเป็นกรณีที่ตัวจับคู่นี้มีไว้เพื่อจัดการ
ทุกตัวกันที่คุณเพิ่มทำให้เกิดรูปประโยคใหม่อีกสองแบบ
ตัวแยกวิเคราะห์แบบกฎล้มเหลวในรูปแบบเฉพาะหนึ่งเดียว มันตอบอย่างมั่นใจและผิด ช่องว่างเปล่ามีต้นทุนเพียงการแตะหนึ่งครั้งของผู้ใช้ แต่การหารที่ผิดทำให้เสียความเชื่อมั่นในบัญชี และในแอปติดตามการแชร์เงิน บัญชีคือตัวผลิตภัณฑ์ สี่แถวด้านบนไม่ใช่การพลาดหวุดหวิด แต่เป็นบั๊กเรื่องเงิน
วงจรที่ไม่จบสิ้นคือข้อโต้แย้งที่แท้จริง ไม่ใช่ข้อบกพร่องเดี่ยว ๆ เพิ่มตัวกันเรื่องวันที่ แล้วกรณีเลขคำสั่งซื้อก็มา เพิ่มตัวกันเลขคำสั่งซื้อ แล้วตัวเลขเปล่าก็มา ตามด้วยจำนวน แล้วก็เลขโต๊ะ รายการตัวกันงอกขึ้นและไม่เคยลู่เข้า เพราะภาษาธรรมชาติไม่มีชุดรูปประโยคจำกัดให้ไล่แจกแจง
การป้อนด้วยภาษาธรรมชาติเป็นฟีเจอร์ AI และไม่มีอะไรในเรโป Dimesum ที่เข้ารูปแบบเดียวกันกับมัน การตัดสินใจลงตัวเมื่อ 2026-08-20 บันทึกไว้พร้อมความล้มเหลวทั้งสี่ เพื่อไม่ให้ใครสร้างตัวกันขึ้นใหม่โดยบังเอิญ
สิ่งที่ส่งออกไปคือตัวเลขหนึ่งตัวและการปฏิเสธ
amount_only คือขั้นลดระดับของเอกสารออกแบบ AI ของเราที่ถูกนำไปทำตามตัวอักษร ขั้นนั้นเขียนไว้ว่า "ฟอร์มธรรมดาพร้อมการเติมล่วงหน้าด้วยรีเจ็กซ์จำนวนเงินฝั่งไคลเอนต์" ดังนั้นขั้นนี้จึงคืนค่าจำนวนเงินและไม่มีอะไรอื่น ไม่มีคำอธิบาย ไม่มีหมวดหมู่ ไม่มีผู้จ่าย ไม่มีผู้ร่วม ไม่มีการยกเว้น มันไม่มีต้นทุนและไม่เรียกใครเลย จึงเป็นเหตุผลที่การทดสอบและ CI รันกับมัน
ความกำกวมคือการปฏิเสธ ไม่ใช่การตัดสินเสมอ
กฎทั้งหมดอยู่ในฟังก์ชันเดียวชื่อ extract_amount_minor ตัวเลขจะกลับมาก็ต่อเมื่อข้อความมีตัวเลือกเพียงตัวเดียวเท่านั้น ดังนั้น order 90210 dinner 400 และ flat 402 rent 15000 จึงคืนค่าว่างเปล่าแทนที่จะเลือกผู้ชนะ ตัวเลขที่ระบุสกุลเงินถือว่าชัดเจนแม้จะอยู่ข้างตัวเลขเปล่า จึงเป็นเหตุผลที่ split 3 ways ฿1,200 ยังอ่านได้เป็น ฿1,200
ตัวเลขที่ติดลบถือว่าไม่มีจำนวนเงินเลย ไม่ใช่ค่าสัมบูรณ์ของมัน -500 minus 200 และ (500) แบบนักบัญชี ล้วนกลับมาว่างเปล่า เพราะฟิลด์นี้คือการเรียกเก็บ และการเก็บตัวเลขไว้แต่ทิ้งเครื่องหมายทำให้เงินชี้ไปในทางตรงข้ามกับข้อความ วงเล็บนับก็ต่อเมื่อปิดล้อมที่ตัวเลขนั้นเอง ดังนั้น (500 each) จึงยังเป็นข้อความในวงเล็บ
สกุลเงินเป็นตัวกำหนดการคำนวณ
หน่วยย่อยคือรูปแบบเดียวที่เงินใช้ใน Dimesum ดังนั้นขั้นนี้จึงแปลงด้วยตารางเลขชี้กำลัง ISO 4217 แทนการคูณด้วย 100 แบบตายตัว เงินเยนของญี่ปุ่นไม่มีหน่วยย่อยเลย และการคูณ 100 ทำให้ใบเสร็จ ¥1,200 พองขึ้นร้อยเท่า ตัวเลขที่ละเอียดกว่าหน่วยเล็กที่สุดของสกุลเงินจะถูกปฏิเสธแทนที่จะปัดเศษ เพราะการปัดเศษจำนวนเงินที่คนพิมพ์เข้ามาคือการสร้างตัวเลขขึ้นเอง
คำบอกจำนวนแบบอินเดียเป็นส่วนหนึ่งของการเขียนตัวเลข ไม่ใช่ส่วนหนึ่งของการเข้าใจประโยค 1.2k 2 lakh และ 500/- ล้วนถอดค่าได้ เช่นเดียวกับ 1,200 อะไรก็ตามที่เกินจำนวนสูงสุดของบัญชีจะกลับมาว่างเปล่า ดังนั้นตัวเลขที่พิมพ์ผิดจึงทำให้ฟิลด์หนึ่งว่างแทนที่จะทำให้จำนวนเต็มล้นในขั้นถัดไป
| ฟิลด์ | ตัวแยกวิเคราะห์แบบกฎ (ลบแล้ว) | amount_only (ใช้งานจริง) | ขั้นของโมเดล (ต่อไว้ ไม่มีคีย์) |
|---|---|---|---|
| จำนวนเงิน | เดาจากตัวเลขหลายตัว | ตัวเลขที่ชัดเจนหนึ่งตัว มิฉะนั้นว่างเปล่า | อ่านตามบริบท |
| คำอธิบาย หมวดหมู่ | จับคู่พจนานุกรม | เป็น null เสมอ | ดึงจากประโยค |
| ผู้ร่วม การยกเว้น | จับคู่ชื่อแบบคลุมเครือ | ว่างเปล่าเสมอ | ถอดค่าเป็นรหัสสมาชิกจริง |
| ผู้จ่าย | อนุมานจากถ้อยคำ | ว่างเปล่าเสมอ | ระบุชื่อ พร้อมจำนวนเงินที่เป็น null ได้ |
| ความเชื่อมั่นรวม | ปรับจูนรายฟิลด์ | ตรึงไว้ที่ 0.3 | ต่อการแยกวิเคราะห์ |
| พรอมป์ที่รายงาน | ไม่มีอยู่ | null ไม่มีการอ่านพรอมป์ | รหัสและเวอร์ชันพรอมป์ |
ขั้นที่ใช้งานจริงไม่เคยผ่านเกณฑ์ใช้งานที่ 0.6
สัญญาการแยกวิเคราะห์ของเราจะทิ้งการแยกวิเคราะห์ที่ความเชื่อมั่นรวมต่ำกว่า 0.6 และพาผู้ใช้ไปยังฟอร์มธรรมดา amount_only รายงาน 0.3 ในทุกคำตอบ และค่าคงที่นี้เป็นเชิงโครงสร้างไม่ใช่การปรับจูน จำนวนเงินตัวเดียวไม่ถือเป็นการแยกวิเคราะห์ ขั้นนี้จึงอยู่ที่ครึ่งหนึ่งของเกณฑ์ไม่ว่าจะพบอะไร ค่าคงที่ค่าเดียวสำหรับทุกคำตอบคือสิ่งที่ตรึงมันไว้ตรงนั้น คะแนนรายกรณีคือคะแนนที่สุดท้ายแล้วจะมีคนดันให้สูงขึ้น
ขั้นนี้ยังรายงานว่าไม่มีพรอมป์เลย ทั้ง prompt_id และ prompt_version กลับมาเป็น null เพราะขั้นนี้ไม่ได้อ่านพรอมป์ใด การตั้งชื่อพรอมป์จะทำให้ผลการประเมินทุกอย่างถูกยกให้เวอร์ชันพรอมป์ที่ขั้นนี้ไม่เคยเห็น และชุดเครื่องมือประเมินคือเครื่องมือเดียวที่ได้รับอนุญาตให้เลื่อนขั้นขึ้นเป็นข้อเสนอแนะแบบแตะครั้งเดียว ที่ความแม่นยำ 95% สำหรับจำนวนเงินและผู้ร่วมพร้อมกัน
มีอีกสองขั้นที่ถูกประกาศไว้และไม่มีขั้นใดใช้งานได้ ขั้น cheap-fast มีอะแดปเตอร์ Groq สำหรับ openai/gpt-oss-120b แต่ไม่มีคีย์ ส่วนขั้นกลางไม่มีอะแดปเตอร์ การเลือกอย่างใดอย่างหนึ่งล้มเหลวตั้งแต่เริ่มระบบ ไม่ใช่ตอนที่ผู้ใช้ร้องขอครั้งแรก เพราะ LLM คิดเงินต่อการเรียกหนึ่งครั้ง และการพึ่งพาที่มีค่าใช้จ่ายต้องล้มเหลวแบบปิดไว้ก่อน
ไม่มีอะไรบันทึกอัตโนมัติ ช่องว่างจึงมีต้นทุนเพียงแตะครั้งเดียว
ช่องว่างเปล่ามีต้นทุนน้อยมากก็เพราะไม่มีการบันทึกใดใน Dimesum ที่เขียนเงินได้ การบันทึกสร้างข้อเสนอแนะ คนยืนยันมัน และการยืนยันคือสิ่งที่สร้างรายจ่าย การตัดสินใจ D5 ในบรีฟระบุกฎนี้ และ .go-arch-lint.yml บังคับใช้มัน บริบทการรับข้อมูลถูกปฏิเสธไม่ให้พึ่งพา expense หรือ ledger ใด ๆ ดังนั้นการบันทึกจึงไม่อาจบันทึกสมุดรายวันได้แม้โดยบังเอิญ CI ทำให้การ import ล้มเหลว ซึ่งเราตรวจสอบด้วยการเพิ่มเข้าไปหนึ่งครั้ง
การบันทึกเก็บข้อความดิบไว้ไม่ว่าตัวแยกวิเคราะห์จะทำอะไร และระบุว่าฟิลด์ใดยังไม่ถูกถอดค่า ไคลเอนต์เน้นช่องว่างเหล่านั้นแทนที่จะแสดงร่างที่กุขึ้น ซึ่งเป็นความต่างระหว่างตัวแยกวิเคราะห์ที่ไม่พูดอะไรกับตัวที่เดา การยืนยันดึงรหัสรายจ่ายจากรหัสข้อเสนอแนะ ดังนั้นการแตะซ้ำจึงเล่นซ้ำแทนที่จะเรียกเก็บสองครั้ง
กฎที่ควรค่าแก่การหยิบไปใช้
นับตัวกันของคุณ ไม่ใช่บั๊กของคุณ รายการตัวกันที่งอกขึ้นทุกสัปดาห์กำลังบอกคุณว่างานนี้คือการทำความเข้าใจ และการทำความเข้าใจเป็นของโมเดล ขั้นต่อไปของเราคือรันชุดโกลเดนใน contracts/parse_expense/eval/ กับขั้นของโมเดลจริง เพราะไม่มีอะไรในนี้กลายเป็นข้อเสนอแนะแบบแตะครั้งเดียวได้หากปราศจากคำตัดสินนั้น
คำถามที่พบบ่อย
ทำไม Dimesum ถึงลบตัวแยกวิเคราะห์รายจ่ายแบบกฎ?
Dimesum ลบมันเพราะประโยคธรรมดาสี่ประโยคทำให้เกิดบั๊กเรื่องเงิน และตัวกันทุกตัวที่เพิ่มเข้าไปก็ทำให้เกิดรูปประโยคใหม่อีกสองแบบ dinner 12-08 400 ถูกอ่านเป็น ฿12 ravioli 600 เพิ่มสมาชิกชื่อ Ravindra kirana 500 เรียกเก็บกับสมาชิกชื่อ Kiran และ refund -483.50 กลายเป็นการเรียกเก็บ ฿483.50 การเข้าใจประโยคเป็นหน้าที่ของโมเดล
ขั้น amount_only คืนค่าอะไรจริง ๆ?
ขั้น amount_only คืนค่าตัวเลขเพียงตัวเดียวและไม่มีอะไรอื่น มันตอบด้วยจำนวนเงินก็ต่อเมื่อข้อความมีตัวเลือกจำนวนเงินที่ชัดเจนเพียงตัวเดียวเท่านั้น และไม่เคยระบุผู้ร่วม ผู้จ่าย คำอธิบาย หรือหมวดหมู่ หากมีสองตัวเลือกก็จะไม่มีจำนวนเงินเลย ส่วนที่เหลือทั้งหมดในสัญญาการแยกวิเคราะห์รอขั้นของโมเดล
ทำไม amount_only ถึงรายงานความเชื่อมั่น 0.3 แทนคะแนนจริง?
ค่า 0.3 เป็นเชิงโครงสร้าง ไม่ได้ปรับจูน สัญญาการแยกวิเคราะห์ของเราจะทิ้งการแยกวิเคราะห์ที่ต่ำกว่า 0.6 และพาผู้ใช้ไปยังฟอร์มธรรมดา และจำนวนเงินตัวเดียวไม่ถือเป็นการแยกวิเคราะห์ ขั้นนี้จึงอยู่ที่ครึ่งหนึ่งของเกณฑ์นั้นไม่ว่าจะพบอะไร ค่าคงที่ค่าเดียวสำหรับทุกคำตอบช่วยกันไม่ให้คะแนนรายกรณีถูกดันขึ้นภายหลัง
การป้อนด้วยภาษาธรรมชาติเขียนลงบัญชีได้เองโดยไม่มีคนยืนยันไหม?
ไม่ได้ การบันทึกสร้างเพียงข้อเสนอแนะ และต้องมีคนยืนยัน ตามการตัดสินใจ D5 ในบรีฟ กฎนี้บังคับใช้ใน .go-arch-lint.yml ซึ่งไม่อนุญาตให้บริบทการรับข้อมูลพึ่งพา expense หรือ ledger ดังนั้น CI จะทำให้การ import ล้มเหลวหากการบันทึกเอื้อมไปถึงสมุดรายวัน การยืนยันคือสิ่งที่สร้างรายจ่าย
ถ้าไม่มีขั้นของโมเดล การแยกวิเคราะห์รายจ่ายจากภาษาธรรมชาติจะเป็นอย่างไร?
Dimesum จะลดระดับลงมาที่ amount_only และแสดงช่องว่าง ขั้น cheap-fast ต่อกับ openai/gpt-oss-120b ของ Groq และส่งมอบมาโดยไม่มีคีย์ ส่วนขั้นกลางไม่มีอะแดปเตอร์ การเลือกอย่างใดอย่างหนึ่งจึงล้มเหลวตั้งแต่ตอนเริ่มระบบ ไม่ใช่ตอนที่ผู้ใช้ร้องขอครั้งแรก การบันทึกยังคงเก็บข้อความดิบไว้ไม่ว่าทางใด
บทความยอดนิยม
- บัญชีเพิ่มอย่างเดียวที่ทำให้ยอดหารบิลแม่นยำอ่าน 6 นาที
- ทำไมการแก้ไขค่าใช้จ่ายร่วมต้องระบุการแบ่งใหม่อ่าน 5 นาที
- บั๊กเรื่องเงินหกจุดในการแยกบิลหลายสกุลเงินอ่าน 6 นาที
- เคลียร์ค่าใช้จ่ายกลุ่มให้จบในไม่กี่การโอนอ่าน 6 นาที
- วิธีแบ่งบิลเมื่อมีจานที่ไม่ได้แชร์กันอ่าน 6 นาที