cd ../back to blog
$Guide//June 4, 2026//7 min read

為你的 AI API 花費設下上限:max_tokens、每位使用者預算與誠實計量

用 max_tokens 為每次呼叫設限、從 usage 物件追蹤每位使用者花費並依預算切斷,並了解為何誠實計費才讓上限名副其實。

一個沒有花費上限的 AI 功能,就是一個能向你開出無上限帳單的功能。一次 失控的代理迴圈、一個把整本小說貼進聊天框的使用者、一段讓模型滔滔不絕 寫出 4,000 個權杖的提示 — 任何一個,都會悄悄把你的帳單翻倍。解法是兩個 便宜又無聊的控制:用 max_tokens 為每一次呼叫設限,再從 usage 物件 追蹤每位使用者的花費,讓你能在某人花的錢超過他帶來的 價值之前就把他切斷。

這些都不難。難的是,你拿來設限的那些數字到底值不值得信任。一個預算的 好壞,完全取決於餵給它的權杖數 — 如果你的閘道灌水 usage, 或為失敗的呼叫向你收費,那你精心算出的「每位使用者每天 $1」上限其實是 $1.40,而你還渾然不覺。所以這篇文章做兩件事:示範運作的機制,並解釋為 什麼誠實的計費,才是讓這套機制真正成立的關鍵。

步驟一 — 用 max_tokens 為每一次呼叫設限

輸出是多數帳單最貴的一半。在 Claude Sonnet 4.6 上,輸出每 1M 權杖要 $12.75 — 是輸入費率 $2.55 的五倍。一個你預期只有三句 話、卻回了十二段的回答,不是品質問題;那是成本問題。 max_tokens 就是那道硬性天花板,讓最壞情況可以事先預知。

cap_per_request.py
# 用 max_tokens 為每一次呼叫的成本設下上限。
# 它把「輸出」這個多數帳單最貴的一半,限制在一個
# 硬性天花板內。模型一到上限就停,不會無止盡寫下去。
from openai import OpenAI

client = OpenAI(
    api_key="sk-brievio-...",
    base_url="https://api.brievio.com/v1",
)

# Claude Sonnet 4.6: 每 1M 權杖輸入 $2.55 / 輸出 $12.75。
# 沒有上限時,一個話多的回答可能跑到 4,000 個以上的輸出權杖。
# 設了 max_tokens=500,你就把「這一次呼叫」的輸出成本鎖在:
#   500 × $12.75 / 1M = $0.0064 — 不管模型「想」說多少都一樣。
resp = client.chat.completions.create(
    model="claude-sonnet-4-6",
    max_tokens=500,                 # 原生遵循 — 真正的硬性停止
    messages=[
        {"role": "system", "content": "Answer in at most 3 sentences."},
        {"role": "user", "content": user_question},
    ],
)

# 永遠要確認它為什麼停下來。"length" 代表你撞到了天花板,
# 回答可能被截斷 — 這是該為「這一類任務」調高上限的訊號,
# 而不是全面調高。
if resp.choices[0].finish_reason == "length":
    print("Truncated at the cap — consider a higher max_tokens here.")

print(resp.choices[0].message.content)
print(resp.usage)  # 誠實的輸入/輸出數量 — 見下一節

Brievio 對真正的模型原生遵循 max_tokens — 它是真正的停止, 不是建議。請依任務類型分別設定,而不是全域設一次了事:一個分類器也許 只需要 5 個權杖、一則聊天回覆 500、一份長摘要 2,000。要養成的紀律,是 為每一個呼叫點挑一個數字,並盯著 finish_reason。當它回傳 "length",代表你截斷了一個真實的回答,應該為那一條路徑調高上限 — 而不是到處全面調高、失去保護。

步驟二 — 自己替 usage 物件計價

每一個 Brievio 回應都帶著一個 usage 物件,內含那次呼叫 真實的輸入與輸出權杖數,而且每個請求都會連同它真實的權杖與成本一起被 記錄。這代表你不必等到月底帳單才知道任何東西花了多少 — 你可以在每一次 呼叫回傳的當下就替它計價:

  • usage.prompt_tokens — 實際送出的輸入權杖。
  • usage.completion_tokens — 實際生成的輸出權杖(這就是 max_tokens 所設限的對象)。
  • usage.total_tokens — 兩者的總和,方便快速核對。

把每個數量乘上公布的各模型費率,你就在自己的程式碼裡、即時地得到這次 呼叫的確切成本。各模型費率都對照官方參考公布在 定價頁面上,所以你程式碼裡的那些常數是可 稽核的 — 而不是一個你只能盲目相信的數字。

步驟三 — 追蹤每位使用者的花費,並依預算切斷

每次呼叫的上限,保護你不受單一次糟糕呼叫之害。每位使用者的預算,則保護 你不受單一個糟糕行為者之害 — 那個一天跑上千次呼叫的帳號,無論 是出於熱情、自動化,還是濫用。模式就是每位使用者一個持久的數字,你在 呼叫前檢查它、呼叫後遞增它:

cap_per_user.py
# 從 usage 物件追蹤每位使用者的花費,再依預算切斷。
# usage 會回傳這次呼叫「真實」的輸入/輸出權杖數。你在本機
# 拿這些數字對照公布的各模型費率算出成本,再累加到一個
# 以使用者為鍵的累計數字上。
from decimal import Decimal

# Brievio 公布費率,每 1M 權杖的美元計價(約比官方表低 15%)。
RATES = {
    "claude-sonnet-4-6": {"in": Decimal("2.55"), "out": Decimal("12.75")},
    "claude-haiku-4-5":  {"in": Decimal("0.85"), "out": Decimal("4.25")},
}

def cost_usd(model: str, usage) -> Decimal:
    r = RATES[model]
    million = Decimal("1000000")
    return (usage.prompt_tokens     * r["in"]  / million +
            usage.completion_tokens * r["out"] / million)

# 你選用的儲存方式 — Redis 計數器、一個 SQL 欄位,都行。重點
# 是每位使用者有一個持久的數字。失敗的 4xx/5xx 呼叫在 Brievio
# 上免費,所以你只會為真正回傳了結果的呼叫累加成本。
DAILY_BUDGET = Decimal("1.00")  # 每位使用者每天 $1

def chat_for_user(user_id: str, question: str, model="claude-sonnet-4-6"):
    spent = get_spent_today(user_id)            # Decimal,預設為 0
    if spent >= DAILY_BUDGET:
        raise BudgetExceeded(f"{user_id} hit ${DAILY_BUDGET}/day")

    resp = client.chat.completions.create(
        model=model,
        max_tokens=500,
        messages=[{"role": "user", "content": question}],
    )

    add_spent_today(user_id, cost_usd(model, resp.usage))  # 累加真實成本
    return resp.choices[0].message.content

從你的單位經濟學挑出門檻:如果一個付費席位是每月 $20,而你希望 AI 維持 在,比方說,營收的 20% 以下,那就是每位使用者每天大約 $0.13 的預算。在 80% 時軟性警示(一條橫幅、一封電郵),在 100% 時硬性切斷(就是上面那條 BudgetExceeded 路徑)。對免費方案的使用者,把上限設低,並 把模型降一階 — 把非關鍵流量從 Sonnet 移到 Haiku 4.5,輸入 $0.85 / 輸出 $4.25,可以把每權杖成本 砍掉大約三分之二,同時維持同樣誠實的計量。

為什麼誠實的計費讓這些數學值得信任

這裡是大多數成本控制指南略過的部分。上面那兩個控制 — 每次呼叫的天花板 與每位使用者的預算 — 都是在權杖數上做算術。如果那些數量被灌水,下游 每一個數字都會被同一個倍數悄悄地算錯。有兩個計費行為,決定了你的上限 是否名副其實:

  • 失敗的呼叫免費。在 Brievio 上,一個 4xx 或 5xx 回應 不花你一毛 — 你是為結果付費,不是為嘗試付費。這對預算尤其要緊:一場 針對不穩定下游的重試風暴,不該把一位使用者當天的額度耗光。因為你只在 有回傳結果的呼叫上累計成本,你的花費曲線追蹤的是交付的價值,而不是 吞下的錯誤。
  • 數量不被灌水。usage 物件反映的是真正的模型實際處理的權杖 — 沒有灌水的提示,沒有憑空加進 計量表的幻影輸出。誠實的做法不是把這個拿來盲信:送出一段已知的固定 提示,讀回 prompt_tokens,確認它跟分詞器算出來的相符。 我們寫了一段 20 行的權杖灌水自我測試 就是在做這件事 — 在你信任任何閘道(包含我們)的數字之前,先對它跑 一遍。

這層關聯是直接的:一個用灌水數量算出的預算,會太早把使用者切斷,並 高估你的成本;一個把失敗呼叫也算進去的預算,則會因為你基礎設施狀況不好 而懲罰使用者。誠實的計量,才是讓一個「每天 $1」的天花板真正等於一美元 的關鍵。Brievio 把聊天計價約定在 比官方表低 15%、用多少 付多少,餘額永不過期 — 所以你設的上限就是你拿到的上限,沒用完的預算 仍然是你的。

把它們組合起來

一套可上線的花費姿態,就是四個小習慣,而且沒有一個會花掉你超過一個 下午:

  • 每一個呼叫點都設好 max_tokens,大小依 它的任務而定。任何地方,都不要有無上限的輸出。
  • 每一個回應都從 usage 計價,用公布的 費率,再累加到每位使用者的累計上。
  • 每位使用者都有一個預算,帶著一道軟性警示與一道硬性 切斷,都從你的單位經濟學畫出來。
  • 較便宜的流量降一階,改用一個較小的模型(Haiku、 mini 等級),而不是為不需要旗艦的工作付旗艦費率。

做到這四件事,你最壞情況的帳單就是一個你選定的數字,而不是一個你 發現的數字。至於更深層的槓桿 — 提示快取、批次處理、模型選擇、提示 精簡 — 請見 成本最佳化攻略,以及 文件裡完整的 usage 結構描述, 還有 Brievio 支援的 OpenAI 相容參數。成本控制不是一個你被帳單嚇到後 才補上的功能 — 它就是兩行程式加一個計數器,而且在一個你信得過的計量表 上運作得最好。