一張單據進來之後,系統做了什麼
抽取一張發票在 2026 年已經是商品化服務,一份大約幾美仙。 所以真正的產品不在「讀得懂」,在於讀完之後的四件事: 怎樣編碼、什麼時候該停手、入到一本怎樣的帳,以及怎樣證明給核數師看。
五個階段
-
收件
每間公司有一個專屬電郵地址;供應商直接寄,同事直接轉寄。手機拍照走一個網頁(不是要下載的 App)。平台(Stripe、PayPal、WooCommerce)用 webhook 自動進來,銀行月結單支援 PDF 與 CSV 匯入。每一個檔案先做 SHA-256 內容雜湊——同一份檔案不會被處理兩次。
-
抽取
多模態模型按嚴格的 JSON schema 輸出,並且每一個欄位各自附上置信度。這一點很重要:發票號碼看不清而總額很清楚,是兩件不同的事,覆核的人需要知道分別。高金額或低置信的單據會再用第二個模型跑一次——兩家答案不一致,本身就是最強的訊號。
-
解析
供應商用名稱、稅號和銀行帳號做模糊比對。重複偵測是一條加權規則,不是單一欄位比較:同一供應商、金額相差 0.5% 以內、日期相差七天以內、發票號碼相似度高——四項一起看。新供應商一律轉人手,不猜。
-
編碼
不是用所有客戶的數據訓練一個通用模型。是把「供應商+明細描述」向量化,在這一間公司自己的已編碼交易裡找最相近的紀錄,提議它過去用過的科目、稅項和成本中心。同一個供應商大約十五張單據之後就穩定,而且可以解釋——這比任何置信度數字都有說服力。
-
入帳或轉人手
通過閘門就寫入總賬:一張平衡的複式分錄,帶原始單據、帶佐證紀錄。不通過就進例外佇列,並且說明為什麼在那裡。
總賬是自己的,所以四條規矩寫死在資料庫裡
應用程式層面的檢查,總有第二條程式路徑繞得過去; 資料庫約束繞不過。這四條不是設定,不是選項, 是資料庫本身會拒絕的動作。
借貸必須平衡
每一張分錄、每一種貨幣,借方總額等於貸方總額。用延遲約束在交易提交那一刻檢查——寫到一半不平衡沒關係,提交時不平衡就整張拒絕。
只增不改
分錄表上的更新與刪除權限直接撤銷了,連程式自己都做不到。錯了就沖銷加重入,兩筆都留在帳上。
鎖了的期間拒絕寫入
由寫入前觸發器擋,不是靠服務層一個 if。結了帳的月份,沒有任何路徑補得到分錄進去。
佐證鏈不可以斷
每一筆佐證的雜湊值包含上一筆的雜湊值。回頭改動歷史,程式報得出斷在哪一筆。
還有一條關於錢的
金額一律用整數的最小單位(仙、分),不用浮點數。每一條分錄行同時存三個值:原幣金額、當時用的匯率、換算後的港元。不存兩個計第三個——事後重算會靜靜地改寫歷史。匯率的來源與時間戳寫進佐證。
閘門為什麼要有兩個獨立條件
模型自報的置信度不是校準過的概率。單靠它去決定「要不要無人入帳」, 等於把一個會計後果押在一個沒有校準的數字上。 所以閘門的另一半必須是確定性的、可審計的、和模型完全無關的。
| 模型那一半 | 確定性那一半 |
|---|---|
| 每一個抽取欄位都高過它自己那個門檻(不是一個總分) | 金額低於該公司的自動入帳上限 |
| 若觸發交叉核對,兩個模型的答案一致 | 該供應商已有足夠而且一致的歷史樣本 |
| — | 不是新供應商、不疑似重複 |
| — | 會計期間未鎖、政策檢查(預算、成本中心、審批人)通過 |
| 欄位 | 開局值 |
|---|---|
| 幣別 | 0.97 |
| 金額 | 0.95 |
| 日期 | 0.93 |
| 供應商 | 0.90 |
| 逐行明細 | 0.80 |
| 供應商最少歷史 | 15 筆,而且八成以上入同一個科目 |
| 自動入帳上限 | 由該公司的重要性水平反推,不是拍腦袋定一個數 |
開局會有三至四成單據停下來
這是設計,不是失敗。例外率高只是花時間,入錯帳是花信譽——兩者不是同一個級數。第一個月每一筆都覆核,第二三個月抽兩成半,之後長期一成。
門檻只能憑證據放寬
同一個供應商連續多次自動入帳、而且抽查證實全對,系統才可以建議調低那一個供應商的門檻。沒有「用順手了就整體放寬」這回事。
單筆大細不是真正的風險,總量才是
系統持續計算「已自動入帳的總金額 × 抽查錯誤率 = 推算未被發現的錯誤」,並拿它跟該公司的執行重要性水平比。超過四分之一就自動收緊閘門並示警。這一條回答的是核數師真正會問的那句話:你怎麼知道沒有重大的東西出錯。
佐證:這是產品真正的交付物
因為我們沒有借用任何人的信用, 佐證層是核數師唯一有理由接受一筆機器入帳的原因。 它不是加分項,也不是之後補做的功能——它和總賬同時存在。
- 逐筆的輸入——指向那一份原始檔案,不是一批的摘要
- 模型與提示版本——生成式輸出不可重現,所以記下「當時用了什麼」比記下「我們用 AI」有意義得多
- 逐欄的置信度——連同當時的判斷依據(例如「歷史 47 次一致」)
- 匯率的來源與時間——外幣分錄的每一個換算都說得出出處
- 覆核的人、時間、以及改了什麼——橡皮圖章式的批准會記錄為「無修改」,而不是被隱藏
- 雜湊鏈——每一筆接上一筆,事後回頭改動驗得出來
一條沒有例外的規則
已入帳的分錄沒有編輯功能。錯了就沖銷,再入正確的一筆,兩筆都留在帳上並附上原因。悄悄改掉一筆已入帳的分錄,正是會摧毀整個佐證體系的那個動作——所以我們連自己都不給這個能力。
為什麼自己做總賬,而不是建在 Xero 上面
我們認真考慮過做一層在 Xero 之上,也畫過架構。最後否決,理由不是它不夠好, 是它的資料模型成形於一個沒有人想像過「機器會是主要操作者」的年代。
| 當年很合理的假設 | 今天的後果 |
|---|---|
| 介面就是產品 | API 是附屬品,銀行對賬那一下明文寫著不支援、也沒有計劃支援 |
| 機器不需要身分 | 每一筆 API 寫入的使用者一律是 System Generated——分不出哪一筆被人覆核過 |
| 軌跡只需記改動 | 記錄「改了什麼」,不記錄「憑什麼這樣判斷」 |
| 一間公司一套帳 | 事務所管三百間客戶,就是三百份訂閱 |
這四樣沒有一樣可以加個功能補回來
全部都是地基。在別人的地基上起樓,最關鍵那幾樣你永遠拿不到——所以總賬必須是自己的。代價是我們要從零累積核數師的信任,而這正是佐證層存在的意義。
我們不會迴避的限制
第一版不接銀行即時資料流,用 PDF 與 CSV 匯入;不做薪酬與強積金;不做訂製生產的在製品估值;不做稅務折舊寬免——那一項交回核數師。這些不是「稍後推出」的話術,是第一版明確不做的東西。