大型語言模型 API 的 token 與計費:估算、讀取、預算與算例
使用大型語言模型 API 就像用水電:不看錶,月底帳單會嚇你一跳;看懂錶,每一度都能心中有數。這裡的「錶」就是 token 計數。本文先講 token 是什麼、中英文怎麼粗估,再教你讀取回應中的 usage 欄位、為程式裝上預算閘門,最後用三個寫明假設的算例,把輸入 $0.25、輸出 $1.00(每百萬 token)的價格落到具體場景裡。
更新於
重點
- 計費公式:輸入 token 乘 $0.25,加輸出 token 乘 $1.00,再除以一百萬。
- 估算僅用於事前預判,實際用量以回應中的 usage 為準,串流輸出在最後一個區塊帶有 usage。
- 對話類應用的成本主因是反覆傳送的歷史,裁剪歷史最划算。
- 預算控制三招:限制 max_tokens、限制歷史長度、程式中累計花費並設定每日上限。
token 是什麼,以及如何計費
token 是模型處理文字的最小計量單位,既不是字也不是詞,而是介於兩者之間的「碎片」。你可以把它想像成水錶上的刻度:用得越多,刻度走得越快。計費分為兩塊:
| 項目 | 單價(每百萬 token) | 包含內容 |
|---|---|---|
| 輸入 | $0.25 | messages 中的所有內容:system、歷史、本次提問 |
| 輸出 | $1.00 | 模型生成的回覆 |
注意輸出單價是輸入的四倍,因此讓模型「少說廢話」比讓你「少發點上下文」通常更省錢,不過對話場景中輸入會因歷史累積而膨脹,兩頭都要管。付費方式是預付餘額,不是訂閱,餘額不會過期;新帳戶有 $0.50 試用額度,7 天內有效。
多說一句容易混淆的地方:輸出 token 是模型實際生成的數量,不是你設定的 max_tokens。max_tokens 只是上限,模型兩百字就答完了,只按兩百字對應的 token 收費。但在做預算預判時,要按上限來算最壞情況,這樣才不會被偶發的長輸出打個措手不及。
事前估算:中文、英文各如何粗估
沒發請求前,只能估。以下皆為近似值,不同內容會有浮動:
| 文字 | 粗估規則 | 範例(假設) |
|---|---|---|
| 中文 | 每字約 1 到 1.5 token | 3000 字約 3000 到 4500 token |
| 英文 | 每 4 個字元約 1 token,或每詞約 1.3 token | 1000 個單詞約 1300 token |
| 中英混排、程式碼 | 按偏高的值估 | JSON 與符號多的內容更耗 |
估算的正確用法是做「量級判斷」:這篇文章大概是一萬還是十萬 token,是否會撐破 100,000 的上下文視窗,一次呼叫大概幾分錢。要精確,就讀 usage。一個好習慣是每個業務場景抽樣跑幾十次,統計 usage 的平均值,用它取代經驗值。
舉個把估算與實測結合起來的例子。假設你要處理一批 2000 字左右的中文客戶回饋,按每字 1.3 token 粗估,單条约 2600 token,加上你的指令 200 token,輸入約 2800。先挑 30 條跑一遍,讀 usage 取平均,假設實測平均是 2500,那就把你的係數修正為約 1.15。之後整批的預算就按修正後的係數算,誤差會小很多。這個實測數字只是示範方法的假設,你的數據會有自己的數值。
讀取 usage:真正的「電錶讀數」
每次成功的回應都帶有 usage,含 prompt_tokens、completion_tokens、total_tokens 三項。串流輸出不需要額外參數,最後會自動追加一個帶 usage 的資料區塊。下面的程式碼同時示範兩種讀法,並把讀數換算成美元:
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.apidamoxing.com/v1", api_key=os.environ["API_KEY"])
PRICE_IN, PRICE_OUT = 0.25, 1.00 # 美元 / 百万 token
def cost(u):
return (u.prompt_tokens * PRICE_IN + u.completion_tokens * PRICE_OUT) / 1_000_000
# 非流式:usage 在响应对象上
r = client.chat.completions.create(
model="uncensored", max_tokens=200,
messages=[{"role": "user", "content": "用三句话解释什么是通货膨胀。"}],
)
print(r.usage.prompt_tokens, r.usage.completion_tokens, f"${cost(r.usage):.6f}")
# 流式:最后一个数据块带 usage,其余块的 usage 为空
usage_last = None
stream = client.chat.completions.create(
model="uncensored", max_tokens=200, stream=True,
messages=[{"role": "user", "content": "再用三句话解释什么是通货紧缩。"}],
)
for chunk in stream:
if chunk.usage:
usage_last = chunk.usage
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
print()
if usage_last:
print(usage_last.prompt_tokens, usage_last.completion_tokens, f"${cost(usage_last):.6f}")串流時要留意:只有最後一個區塊有 usage,前面的區塊裡它是空的,所以用 if chunk.usage 判斷即可。把每次的讀數記到日誌或資料庫裡,月底對帳、查異常、算單用戶成本,全靠這份記錄。
還有一個習慣值得養成:給每個業務功能打上標籤,記帳時一起記錄。比如「摘要」「客服」「翻譯」各記各的,月底一對帳,就能看出到底哪個功能最花錢,是該優化提示詞、裁剪歷史,還是降低 max_tokens。沒有標籤,只有一個總數,想優化都無從下手。
三個算例(假設條件已註明)
算例一:客服問答
假設:每次請求輸入 800 token(含 system 與知識片段),輸出 200 token;每天 10,000 次。
單次費用:800 × 0.25 ÷ 1,000,000 = $0.0002,輸出 200 × 1.00 ÷ 1,000,000 = $0.0002,合計 $0.0004。每天 $4.00,30 天 $120。按這個速度,$0.50 的免費試用額度可以支撐約 1,250 次這樣的呼叫。
算例二:長文章摘要
假設:每篇文章輸入 20,000 token,摘要輸出 600 token;共 500 篇。
單篇:20,000 × 0.25 ÷ 1,000,000 = $0.005,加上 600 × 1.00 ÷ 1,000,000 = $0.0006,合計 $0.0056。500 篇共 $2.80。可見長輸入、短輸出的任務很便宜。
算例三:多輪聊天與歷史裁剪
假設:system 100 token;每輪用戶輸入 60 token,回覆 150 token;一場對話 20 輪。
| 方案 | 累計輸入 token | 累計輸出 token | 總費用 |
|---|---|---|---|
| 每次帶全部歷史 | 43,100 | 3,000 | 約 $0.0138 |
| 只帶最近 3 輪 | 14,540 | 3,000 | 約 $0.0066 |
全歷史方案的輸入是:20 × (100 + 60) + 210 × (0 + 1 + … + 19) = 3,200 + 39,900 = 43,100。裁剪方案前三輪分別是 160、370、580,第 4 到第 20 輪每輪 790,合計 14,540。費用相差一半左右,而且輪次越多差距越大,因為全歷史方案的輸入是隨輪數平方級增長的。
從這三個例子可以總結出一個經驗公式:成本主要由「請求次數 × 每次的輸入輸出量」決定,而每次的輸入量裡,歷史和附帶資料是最能動手腳的部分。客服場景降低知識片段長度、聊天場景裁剪歷史、摘要場景分塊並行,都是同一個道理:別讓不必要的 token 白白付費。需要強調的是,這三個算例的數字全部來自上面註明的假設,你的實際資料請以 usage 為準。
再看一個反向的推算:如果你的月預算是 $30,想知道聊天產品每月能撐多少場 20 輪的對話。按算例三的「只帶最近 3 輪」方案,每場約 $0.0066,$30 ÷ 0.0066 約 4,545 場。同樣的預算,若用全歷史方案,每場 $0.0138,只夠約 2,174 場。這就是裁剪歷史帶來的實際差別。
預算控制:給程式裝上閥門
估算只是預測,閥門才是保險。下面是一個按美元記帳的日預算類:請求前用「最壞情況」預判(輸出用滿 max_tokens),請求後用真實 usage 記帳。
class Budget:
"""按美元计的日预算。超出时拒绝新请求。"""
def __init__(self, daily_usd):
self.limit = daily_usd
self.spent = 0.0
def check(self, est_prompt_tokens, max_tokens):
# 最坏情况:输出用满 max_tokens
worst = (est_prompt_tokens * 0.25 + max_tokens * 1.00) / 1_000_000
if self.spent + worst > self.limit:
raise RuntimeError(f"预算不足:已用 ${self.spent:.4f},本次最坏 ${worst:.4f},上限 ${self.limit}")
def record(self, usage):
self.spent += (usage.prompt_tokens * 0.25 + usage.completion_tokens * 1.00) / 1_000_000
budget = Budget(daily_usd=5.0)
budget.check(est_prompt_tokens=1200, max_tokens=500) # 请求前
# ……发请求……
# budget.record(response.usage) # 请求后除了程式內的閥門,還有三個配置層面的手段:
- max_tokens 按任務設,別一律拉到上限,預設 2048,最大 32,000;
- 對話歷史設長度上限,見聊天機器人搭建裡的作法;
- 在帳戶裡只儲值你計畫使用的額度,用完再補,預付費模式天然就是一道硬上限。
最後總結成一張核對表:事前,估算量級、設定 max_tokens、檢查歷史長度;事中,串流輸出時留意最後一個區塊的 usage;事後,記帳並按功能分類、對比預算。三步走完,帳就清楚了。
常見問題
輸入和輸出的 token 都要付費嗎?
是的。輸入每百萬 token $0.25,輸出每百萬 token $1.00,分別按 usage 裡的 prompt_tokens 和 completion_tokens 計算。
我可以提前算出確切費用嗎?
只能估個量級。準確數字要看回應裡的 usage,建議每個場景抽樣統計平均值,用來預測。
餘額會過期嗎?
儲值的預付額度不會過期。新帳戶的 $0.50 免費試用額度有效期是 7 天。
怎樣避免對話越聊越貴?
限制帶入的歷史長度,只保留最近幾輪,或把更早的內容壓縮成摘要,同時按任務設定合適的 max_tokens。
只需填寫表單即可取得金鑰
建立帳戶,複製金鑰,修改 Base URL。設定就是這麼簡單。