Writing
用歷史資料改提示詞:Trackly 圖片記帳抽取器的證據帳本
AI,Local AI,Product,Notes · 2026-05-06
這次 Trackly 圖片記帳提示詞優化,不是從抽象原則開始,而是從一批歷史記帳資料裡反覆追問同一件事:這筆失敗到底是 prompt 錯、gold 錯,還是驗收規則錯?
我最後採用的工作方式,是把每個失敗都整理成一條證據鏈:
| 證據 | 原始觀察 | 結論 | 動作 |
|---|---|---|---|
| 訂單詳情頁缺少「實付」字樣 | 畫面已有商品價格與必付費用,但模型輸出 pending | prompt 過度依賴 final-paid label | 修改 completed/pending 規則 |
| 美團「隨單購買」 | 主訂單 17.5,另有 隨單購買 神券包 合計 ¥9.9 | 同一訂單應合併記帳 | 保留並強化合併金額規則 |
| 另一筆美團訂單 | 主訂單 1.3,隨單購買 22.9,DB gold 只有 1.3 | gold 漏掉附加購買 | 加入 gold override,不改 prompt |
| 酸辣粉截圖 | 42.7 + 1.5 = 44.2,底部又有裁切紅包 -¥13,但 OCR 未完整給出扣減 | 模型可見證據不足,屬可爭論樣本 | 標成 ambiguous_input_evidence,不拿來強改 prompt |
| titleEmoji / description 退化 | 候選 prompt 輸出固定 💰、空 description、地址塞 title | 低 token 化犧牲產品欄位 | 補回欄位語義規則 |
證據一:完成訂單不一定有「實付」標籤
第一條真正改變 prompt 的證據,是「已完成訂單被判成 pending」。有些訂單頁沒有明確寫出「實付」或「合計」,但畫面已經能看到商品價格、服務費、配送費、打包費,以及哪些項目是免收或折扣。模型當時的錯誤不是算錯,而是拒絕記帳。
這導致 prompt 裡加入更強的 completed 判斷:
已下單/已支付/交易詳情頁能由可見價格與必付費用合計時,必須 completed,不得因缺少實付標籤 pending。
這不是某一筆樣本補丁,而是把「可見金額證據」提升到 task-level decision。改完後,該類 targeted repeat 過了 3/3,再跑相鄰 small sample 也維持 20/20。
證據二:同一訂單裡的附加購買要合併
第二條證據來自美團「隨單購買」。其中一筆截圖顯示:
已優惠7.5元 ¥17.5
隨單購買
神券包 合計 ¥9.9如果只取 17.5,就漏掉同一訂單內的附加購買。正確記帳金額是:
17.5 + 9.9 = 27.4這條證據支持 prompt 裡的合併規則:
同一訂單內同時有主商品結算小計和隨單購買/附加購買合計,兩者都屬本次支出,需相加。
證據三:有些錯誤應該改 gold,不該改 prompt
第三條證據更重要,因為它沒有改 prompt,而是改 gold。另一筆美團資料顯示三種可能解讀:
main order only: 1.3
with-order purchase only: 22.9
main order + with-order purchase: 1.3 + 22.9 = 24.2候選 prompt 穩定輸出 24.2。DB gold 是 1.3,legacy prompt rerun 則輸出 22.9。人工回看原始消費紀錄後,確認 Trackly 應該記的是 24.2。所以這不是 prompt failure,而是 gold defect。處理方式是加入 gold-overrides.json,而不是把 prompt 改到迎合錯誤 DB gold。
證據四:強證據必須是模型可見的證據
第四條證據後來反過來修正了我對「強證據」的理解。酸辣粉那筆資料裡,人類回看截圖時可以得到一個合理的真實支付公式:
酸辣粉豪華單人餐 42.7
打包費 1.5
美團紅包 -13
42.7 + 1.5 - 13 = 31.2但這不是一條足夠強的 prompt 證據。模型實際可用的 OCR 只穩定給到商品價與打包費,底部紅包扣減只是在圖像邊緣露出片段,並不是一條可靠、完整、可讀的輸入證據。
所以這筆不能用來要求模型必須輸出 31.2,也不能推導出「底部裁切、final paid 缺失時仍必須 completed」這種過強規則。更合理的處理,是把它標成 ambiguous_input_evidence:如果模型看不清扣減,pending 合理;如果模型只根據 OCR 可見項計算,completed 44.2 合理;如果模型成功讀到 -13,completed 31.2 也合理。
這個修正比單純增加一條 prompt 規則更重要:歷史資料不只用來補 prompt,也用來阻止 prompt 被錯誤證據污染。最後保留的是較保守的通用規則:只有清楚可讀的商品/服務價格、必要費用、免收/贈送項與優惠扣減能閉合成加減公式時,才要求 completed;如果費用或扣減被提示但金額不可可靠讀取,就允許 pending。
證據五:低 token 不能犧牲產品欄位
最後一組證據是產品欄位退化。幾個候選版本在金額上沒問題,但輸出品質變差:
titleEmoji: 固定 💰
description: 空字串
title: 混入地址或付款資訊
products: 缺失這些不是裝飾欄位。Trackly 的記帳結果需要可讀、可掃描、可回顧。因此 prompt 補回這些規則:
title 用交易/商品/服務短標題,不放地址、長編號、帳號或冗長明細;
description 收納地址、口味、規格、店名或備註;
titleEmoji 依 title、products 或消費內容選貼切 emoji;
completed 支出不要用 💰 兜底;
有清楚主品、附帶品或免費品時輸出 products/product。最後形成的處理規則
這次優化最後留下的,不只是一份 prompt,而是一套判斷規則:
| 失敗類型 | 處理方式 |
|---|---|
| 畫面證據清楚,prompt 拒絕或算錯 | 改 prompt |
| 畫面證據清楚,DB gold 錯 | 改 gold override |
| 模型可見證據不足,或 OCR/圖像互相不完整 | 標記 ambiguous_input_evidence 或 unverifiable,不硬補單一標準答案 |
| 歷史分類不可信 | 降級為 diagnostic |
| 產品欄位退化 | 補產品語義規則 |
所以這次真正的工程結論是:歷史資料不能直接當標準答案,但可以當證據來源。每一筆失敗都必須先分類,只有能被模型實際收到的原始畫面/OCR 支持、能泛化、且能改善產品行為的證據,才有資格改 prompt。
最終成績
最後候選 prompt 通過了 1200 筆 functional gate:
| 指標 | 結果 |
|---|---|
| 驗收筆數 | 1200/1200 |
| 正確率 | 100% |
| XML schema OK | 1200/1200 |
titleEmoji present | 1200/1200 |
titleEmoji non-default | 1200/1200 |
description present | 1200/1200 |
description non-empty | 1199/1200 |
products present | 1047/1200 |
成本也明顯下降:
| 指標 | Legacy baseline | Candidate | 變化 |
|---|---|---|---|
| System prompt tokens | 3586 | 1533 | -57.25% |
| Aligned 260 avg prompt/input tokens | 6890.39 | 4837.39 | -29.80% |
| Aligned 260 avg total tokens | 7173.95 | 5028.15 | -29.91% |
| Aligned 260 avg elapsed | 29.55s | 27.12s | -8.22% |
這個結果可以比較精確地表述為:功能驗收通過,token 成本顯著下降,wall-clock 有改善但沒有宣稱通過 strict 10% elapsed certification。
真正有價值的不是單一分數,而是這次建立了一套可重複使用的證據帳本:什麼改 prompt,什麼改 gold,什麼改驗收規則,什麼不該動。