一個批次任務一個月多花了兩百刀,帳單比報錯先炸:給每個任務記一筆 token 帳

上個月對帳,批次匯出流水線一天的成本從三毛漲到快一塊錢。沒人收到警報,因為沒掛任何跟成本有關的警報。它不 crash、不超時、不降質,就是每一刀都比昨天厚一點。這種「故障」比 crash 難發現多了:crash 會喊疼,成本漂移只會安安靜靜地按月結帳。

專屬插圖
一個批次任務一個月多花了兩百刀,帳單比報錯先炸:給每個任務記一筆 token 帳

一個批次任務一個月多花了兩百刀,帳單比報錯先炸:給每個任務記一筆 token 帳

上個月對帳,批次匯出流水線一天的成本從三毛漲到快一塊錢。沒人收到警報,因為沒掛任何跟成本有關的警報。它不 crash、不超時、不降質,就是每一刀都比昨天厚一點。這種「故障」比 crash 難發現多了:crash 會喊疼,成本漂移只會安安靜靜地按月結帳。

先說清楚那兩百刀是怎麼漏的。三個原因,都不是什麼高深問題:

第一,一個任務把整份上下文塞進了 prompt。原本八千 token 能講清楚的指令,我們貼了四萬 token 的相關文件進去。貼的時候沒人覺得有什麼,反正單次也就幾塊錢。

第二,429 限流後的重試不智慧。每次重试都把完整的對話歷史重發一遍,三次重試就是三倍開銷,而失敗的調用照樣計費。

第三,某個任務類型加了「順手再總結一遍」的額外調用,沒人記住當初為什麼加,也沒人記得刪。

三個問題單獨看都「還好」,疊起來單價就翻了三倍。

所以這次做的修復只有一件事:**給每個任務記一筆帳,帳不平就動手**。

一、呼叫層記帳,任務層結帳

我們在 router 的呼叫封裝上掛了個鉤子,每次模型呼叫都落一行:


ledger.insert({
    "task_id": task_id,          # 每次執行唯一
    "task_type": "batch_export", # 預算掛在這個粒度
    "model": model_name,         # 釘死版本號,不帶 latest
    "prompt_tokens": usage.prompt_tokens,
    "completion_tokens": usage.completion_tokens,
    "cost_usd": cost,
    "ts": now(),
})

一行不到二十個欄位的 sqlite,夠用。關鍵是 task_id:呼叫歸屬到哪個任務,任務結束時就按 task_id 把幾十行呼叫匯成一行「這個任務總共花了幾塊錢」,再寫一列 `status`——成功還是失敗。

二、分母要看「成功單價」,不是「呼叫單價」

這一步最容易做歪。按呼叫算成本,一個任務調了 10 次花了五塊,看似便宜;但其中 8 次是重試,真正成功的只有 2 個產物,每個產物實際成本兩塊五,而不是五毛。

所以報表裡我們只盯一個數:**cost_usd 除以成功產物數**。失敗的呼叫不算「浪費」,算成本的一部分——因為正是重試本身讓產物變貴。

三、預算是閘門,不是報表

只記帳不動手,帳還是白記。我們給每個 task_type 設了預算上限,比如 batch_export 單次執行 0.5 美元。執行邏輯很簡單:

- 任務執行中,每次呼叫後查一下累計成本,超 80% 打日誌,超 100% **直接停掉任務**並標 `status=over_budget`。

- 超預算的任務不重試。重試的前提是失敗有原因,預算超了說明原因在任務設計裡,重試只會花第二筆錢。

- 每天早上一條彙總:昨天 over_budget 的任務列表,帶 task_id 和最終成本。

停掉超預算的任務只對過來說有一點代價:偶爾會誤殺一個只要再多跑一步就能成功的任務。但誤殺一次的成本,遠低於放任它跑飛的成本,而且誤殺會留下完整 ledger,復盤很快。

四、每週排一次「最貴任務」

帳記上兩週後,我們把報表做成一行查詢:


SELECT task_type,
       COUNT(*)            AS runs,
       SUM(cost_usd) / SUM(CASE WHEN status='success' THEN success_count ELSE 0 END) AS cost_per_success
FROM task_summary
GROUP BY task_type
ORDER BY cost_per_success DESC;

最貴的那一行就是本週要改的對象。改完下週的報表裡它應該往下掉,不掉就說明改到了別的地方。

帳單比報錯先炸這件事沒法避免,模型按量計費就是這樣的。能避免的是:等帳單來了才第一次看見這個數字。帳本的意義不在省錢本身,在於讓「哪裡在燒錢」從月底的一次驚嚇,變成每天早上一眼能看見的一行數字。

留言區

歡迎分享你的想法!

發表留言

0/500

載入留言中…