你替 Agent 設好十美元預算,放心讓它同時整理幾份文件;帳面明明還沒到線,最後卻超支。這篇 Gemini API 預算上限教學,要帶你檢查三件事:設定管到哪裡、什麼時候擋新請求,以及被擋後程式是否真的停下。
這篇寫給第一次管理 API 費用、願意照著畫面和終端機練習的讀者。先完成雙入口核對單,再跑一個只用 Python 標準函式庫的本機 Mock(可控制的替身)。完全沒有技術背景,也能先看懂核對方法,再請工程夥伴協助執行程式。
截至 2026 年 10 月 22 日,Cloud Billing 發布紀錄確認 spend cap 已於 10 月 13 日對限定服務正式推出。本次實際執行的是零網路、零 API 計費的排程模擬;沒有在 Google 帳戶觸發真實上限,模擬單位也不是美元價格。
先說結論:Gemini API 預算上限=雲端閘門+本機預留+停止收據
把它想成餐廳點餐:雲端上限像櫃台停止接單;本機預留像點餐前先把錢圈住;停止收據則記下哪些菜已上桌、哪些仍在廚房。停止接單,仍可能有先前接下的菜要結帳。
- 先認清 billing account(付費帳戶)、project(專案)、服務與幣別,API Key 是專案裡的鑰匙。
- 確認設定是
Spend cap enforcement,還是只寄通知的Alerts only。 - 本機每次送出前先保留預估成本,把同時在途的請求算進去;遇到上限、未知結果或對帳異常,就關閉新工作入口。
一、先畫五個格子:誰付錢,哪個入口真的受控?
先在私人工作表寫下五欄:billing_account_label、project_id、service、payment_plan、currency。另記盤點時間、上限金額、預算期間與狀態;API Key 只寫名稱,不貼祕密值。以「同一個專案的 Gemini API」為一列,別把整張 Google Cloud 帳單混成一個數字。
Gemini 計費文件說明,同一專案的多把 Key 共同累計專案用量;它們沒有獨立計費設定。換一把同專案的 Key,不會建立新的預算邊界。Gemini 的帳戶層級上限則涵蓋該 billing account 下的相關專案,要與你自訂的專案上限分開記。
付款方式也要認:Prepay 是先買 credits;Postpay 是累積後收款。預付者要另外記錄 auto-reload 是否開啟,以及 monthly auto-charge limit。後者限制自動加值總額,手動購買不算在內;它不是每次模型請求的成本上限。官方正推進預付轉換,直接核對自己的 Billing 畫面,比按開戶年份猜方案可靠。
還要把服務寫完整:Gemini API 的服務名稱是 generativelanguage.googleapis.com;若走其他雲端產品或另外部署 Cloud Run,就另立一列。Cloud Billing 這批 spend cap 的設定單位是一個專案+一個符合資格的服務,不是一鍵封住帳戶內全部產品。
先過資格門檻:Gemini 計費文件將 Invoiced/Offline 帳戶排除在 spend cap 之外;Cloud Billing 的 spend cap 也排除經銷商帳戶。若你屬於這些範圍,本篇的本機預留仍可練習,雲端端需由帳務管理者確認可用控制,不能把下列選項當成已適用。
二、Gemini API 預算上限雙入口核對:四步留下設定證據
①「先認通知鈴」:別把預算郵件當成停止證據
打開 Cloud Billing 的 Budgets & alerts,核對目標 billing account 與專案。Alerts-only 官方說明明確指出,這種預算本身不自動封頂用量或費用。驗收時不能只截一張「100% 通知已寄出」,要看預算種類與 Spend cap status。
②「在 AI Studio 記一份」:看專案,不只看 Key
到 AI Studio 的 Spend → Monthly spend cap → Edit spend cap,核對同一個 project,再記錄金額及保存後的顯示。官方專案上限章節仍將此功能標為 experimental,並提醒約十分鐘延遲及長工作超額的可能。這個時間屬於該功能的文件描述,不能套成所有 Cloud Billing 服務的固定延遲。
③「在 Cloud Billing 再核一份」:建立正確範圍
Cloud Billing 上限採用估算毛額與牌價、不扣折扣或抵免;它在判斷是否封鎖時看的數字,可能與最終應付淨額不同。把工作表的估算支出與帳單結算分欄記,才不會拿錯數字對帳。
需要 Cloud Billing 入口時,依序選 Create new budget → Spend cap enforcement,填名稱;Scope 選同一專案與 Gemini API,Amount 填本次目標金額,再按 Finish 保存。此類期間固定為 Monthly;不要為了照做先刪掉原本有用的警示預算。既有 Alerts-only 預算不能直接轉成 spend cap,可以保留它,另建符合範圍的上限。


保存後抄回工作表:Configured 表示已設定、尚未執行封鎖;Enforced 表示已觸發;Lifted 表示曾觸發後被手動解除;Not applicable 對應只警示預算。看見 Configured,只能證明設定狀態,還不能證明你的 Agent 已通過停止測試。上述路徑與狀態可逐項對照官方設定步驟與狀態說明。
④「兩道門不相加」:同專案的 Gemini 用量一起封鎖
兩邊都設十美元,不代表得到二十美元額度,也不是只封住各自控制台。官方 FAQ 說明:哪個預算先收到成本訊號,就先觸發;不論從哪裡觸發,該專案的 Gemini API 用量會跨平台被封鎖。這也不是「數字較低的永遠先動作」的時序保證。把兩邊金額、範圍、狀態並列,才知道在查同一道業務邊界。
三、為什麼還會超額?跟著三張訂單走一次
假設每件工作最多耗用四個模擬單位,總預算十單位,三件同時啟動。如果它們都只讀延遲看板的「已花零」,每件都判斷 0 + 4 ≤ 10,三件全放行,最後是十二。這是本文設定的算術情境,沒有量到 Gemini 的超額幅度。
雲端端也有時間差。Budget API 的機制說明指出:估算成本觸發上限後,新用量暫停;在途請求繼續完成並按適用規則計費,持續資源的固定費用也可能繼續。這解釋了為何「按了停止」與「最後帳單不再變」不是同一個時點。
本機的解法是預留:允許送出前,原子地檢查 已結算+已預留+本次保守估算 ≤ 本機預算。原子就是檢查與圈錢一次完成,避免兩個工作同時搶用同一筆餘額。先圈四、再圈四,第三件看到已有八被占用,就先排隊。

估算也要有來源。Gemini token 文件區分送出前計算輸入 token 與回應後讀 usage;輸入計數無法預知最後輸出、思考及其他計費項目。正式整合要按所用模型與功能的價格、輸出上限及工具用量保守預留,再用實際 usage 對帳。若無法建立可信的單次上界,就縮小工作與並行數,把未知結果保留成占額,而不是默認免費。
四、零計費 Mock:驗收競爭、在途收尾、拒絕與續跑
在已有 Python 3 的電腦新建練習資料夾,把下面內容存成 budget_mock.py,執行 python3 budget_mock.py。它只用標準函式庫,沒有 SDK、金鑰或網路呼叫;會在目前資料夾建立 budget-checkpoint.json,請使用空白練習目錄,避免覆寫同名練習檔。
"""Local scheduling exercise. No HTTP, SDK, credentials or real currency."""
from concurrent.futures import ThreadPoolExecutor
from threading import Barrier, Lock
import json
from pathlib import Path
class Budget:
def __init__(self, limit):
self.limit, self.spent, self.held = limit, 0, 0
self.lock = Lock()
def reserve(self, amount):
with self.lock:
if self.spent + self.held + amount > self.limit:
return False
self.held += amount
return True
def settle(self, reserved, actual):
with self.lock:
self.held -= reserved
self.spent += actual
# Three workers see the same stale provider report before any settles.
barrier = Barrier(3)
def naive(_):
reported = 0
allowed = reported + 4 <= 10
barrier.wait()
return 4 if allowed else 0
with ThreadPoolExecutor(max_workers=3) as pool:
naive_total = sum(pool.map(naive, range(3)))
assert naive_total == 12
# Reserve every in-flight request before sending it.
budget, gate = Budget(10), Barrier(3)
def guarded(task):
accepted = budget.reserve(4)
gate.wait()
if not accepted:
return task, "pending"
budget.settle(4, 4)
return task, "done"
with ThreadPoolExecutor(max_workers=3) as pool:
states = dict(pool.map(guarded, ["A", "B", "C"]))
assert budget.spent == 8 and budget.held == 0
assert list(states.values()).count("pending") == 1
# Synthetic provider cap: A and B were accepted before enforcement.
provider = {"enforced": False, "spent": 0, "attempts": 0}
def mock_send():
provider["attempts"] += 1
return "CAP_ENFORCED" if provider["enforced"] else "accepted"
assert mock_send() == mock_send() == "accepted"
provider["spent"] += 4 # A completes; then cap is enforced.
provider["enforced"] = True
provider["spent"] += 4 # B was already in flight; it completes.
assert mock_send() == "CAP_ENFORCED"
assert provider["attempts"] == 3 # Rejection causes no automatic retry.
receipt = {"spent": budget.spent, "reserved": budget.held,
"tasks": states, "stopped": True, "requires_reconcile": True}
Path("budget-checkpoint.json").write_text(json.dumps(receipt, indent=2))
# Read the saved state; reconciliation and a NEW total budget allow resume.
saved = json.loads(Path("budget-checkpoint.json").read_text())
budget = Budget(14) # Rebuild from the saved checkpoint.
budget.spent = saved["spent"] # Keep prior spent=8; do not reset it.
assert saved["reserved"] == 0 # Reconcile unknown in-flight work first.
resumed = 0
for task, status in saved["tasks"].items():
if status == "pending" and budget.reserve(4):
budget.settle(4, 4)
states[task], resumed = "done", resumed + 1
assert resumed == 1 and budget.spent == 12
assert all(s == "done" for s in states.values())
print(json.dumps({"naive": naive_total, "guarded": saved["spent"],
"pending_at_stop": 1, "provider_attempts": 3,
"resumed": resumed, "final_spent": budget.spent}))
本次本機執行輸出為 {"naive":12,"guarded":8,"pending_at_stop":1,"provider_attempts":3,"resumed":1,"final_spent":12}。逐欄讀:只看舊報表的版本放行十二;先預留的版本停在八,留一件 pending;模擬供應商先接受兩次,再拒絕第三次,所以總嘗試三次;讀回收據、把總預算改成十四後,只續做一件,累計十二。
程式裡 Barrier 是讓工作等在同一個起跑點,穩定演出競爭;Lock 是保護共享帳本。CAP_ENFORCED 是本文自訂的模擬訊號,不是 Google 真實錯誤碼。兩筆已接受工作在封鎖前後完成,也只是明確安排的教學時間線。這份結果驗證本機範例,不替你的 Google 專案或正式 Agent 背書。
此範例沒有實作跨程序交易、當機後的在途對帳或真正 API 錯誤分類。上線時要以共享儲存的原子交易取代單程序 Lock;請求送出後若逾時,標為 unknown 並維持預留,查明實際結果才結算。不能在 finally 一律退回占額,否則只是沒收到回覆,就又把錢借給下一件。整合時對照Gemini 官方錯誤與重試文件,另外驗收 SDK 自動重試與佇列重試是否重疊。
五、停止收據怎麼驗?三段都要留下紀錄
- 新請求:觸發本機預算或確認雲端上限後,關閉排程入口,檢查後續沒有新的 attempt;不要自動換專案、Key 或供應商繼續花。
- 在途請求:逐筆標成 done、failed 或 unknown;保留已完成輸出,unknown 先維持預留。收據記 task ID、attempt ID、估算、實際用量、輸出位置與 UTC 時間,不寫 Key 或私人文件全文。
- 解除後續跑:先核對所有上限與未知請求,再設定新的總預算,只重排 pending;原先 spent 繼續累計。完成項目與有外部副作用的工作,要先查重。
錯誤分類不能只看 429。官方速率限制文件也把某些花費速率限制列為 429 RESOURCE_EXHAUSTED;因此同一狀態可能關於時間窗配額。把 HTTP 狀態、錯誤本文與控制台狀態一起看。對已確認的預算封鎖先保存並停;對可重試的暫時故障,才採退避、隨機等待、總期限與次數上限,而且每次仍先過預算閘門。
Cloud Billing 的 Lift spend cap 更要小心:官方解除規則指出,手動解除後,該預算在同一期間不會再次觸發,除非提高目標金額並重新設定;下一期間會重置。恢復服務也可能需要最多一小時。Lifted 不能當成仍有原上限在保護。先修好本機閘門、確認新的成本決定,再解除,別為了改金額在正式工作仍狂送時先開門。
此外,兩份官方文件對移轉 billing account 的敘述有差異:AI Studio 章節說專案 cap 保留、累計重置;Cloud Billing FAQ 則說舊帳戶的預算刪除、新帳戶需重建。這裡不把兩種物件合成單一規則。移轉後一律重新核對雙入口、專案身分及保存狀態,驗收完成才重開排程。
Gemini API 預算上限 FAQ:八個直接答案
1. 收到 100% 預算郵件,就代表請求被擋了?
不代表。先看是 Alerts only 還是 spend cap,以及是否 Enforced;郵件與實際停止紀錄分開驗。
2. 雙入口各設十美元,可以花二十美元?
不能這樣相加。同專案 Gemini 用量跨平台受封鎖,先收到成本的控制先觸發。
3. 換同專案另一把 Key 能獨立控費?
不能把它當成獨立帳本。同專案 Key 共用專案累計,請先確認專案歸屬。
4. 上限觸發後還可能有費用?
會有這種情況。延遲與先前在途工作可產生超額;固定資源費也要另查。
5. 關掉 auto-reload 就等於工作預算設好了?
還要檢查其他層。它處理是否自動買 credits,工作端仍需預留、停止與對帳。
6. 本機 Mock 通過,Google 上限就驗收完了?
還沒有。它只驗本機排程設計;雲端設定證據與實際整合紀錄要另外留存。
7. 所有 429 都應立刻重試?
先分類。時間窗配額、花費限制與暫時故障要按錯誤本文辨認;預算封鎖先停,不進無限重試。
8. Lifted 之後原預算還會繼續擋?
該期間不會按原設定再次觸發。重新設定與恢復要連同本機累計、pending 和 unknown 一起驗。
給新手的三個重點
- 上限要寫清楚帳戶、專案、服務、期間與狀態;只看到金額不夠。
- 把在途工作先圈進預算,才能避免多個工作同時借到同一筆錢。
- 停下來時保留已完成、待辦與未知結果;續跑改總額,別抹掉先前消費。
接著閱讀
左右滑動查看更多推薦
下一步:先證明第三張訂單會被留下
今天先填完雙入口工作表,再跑一次 Mock,親眼看見第三件工作先留在 pending;接著檢查你的 Agent 是否也會保留 unknown,而不是逾時就把預留清空。記住:Gemini API 預算上限=雲端閘門+本機預留+停止收據。能解釋每筆錢與每件工作去了哪裡,再增加並行數。
想把這套方法延伸成完整工作流,可從AlphaLab AI 專區補齊觀念,或到AlphaLab 線上課程挑一個小任務,把開始、停止、對帳與續跑一起完成。






