SSD Nodes Learn
指南 Matt Connor作者: Matt Connor · 已更新 2026-07-24

如何在 VPS 上控制 AI Agent 成本並防止帳單暴增

在 VPS 上執行 unattended agent 時,若無人監控迴圈,極易造成 Token 消耗失控。本文提供實用的成本控制策略,包含設定硬性上限、任務預算、利用 prompt caching 與 batching 技術,並教您如何透過 usage fields 精準追蹤各項任務的實際支出。

如何防止持續運行的 AI agent 產生高額帳單

在 VPS (virtual private server) 上控制 AI agent 的成本,關鍵在於啟動 agent 前設定上限,因為執行期間無人監控用量。請使用 max_tokens 限制每次回應的成本,在程式碼中限制迴圈迭代次數,快取不變動的 prompt 部分,並記錄每次回應的使用量以分析各項任務的支出。伺服器租金為固定月費,但 model API 是按 token 計費,且不受監控的迴圈非常容易在無人察覺的情況下消耗大量 token。

本文假設您已擁有一個從自有主機呼叫 Messages API 的現成 agent。使用 Claude 在 VPS 上建立 AI agent 介紹了相關的架構機制。

為什麼 unattended agent 的成本結構不同

互動式 session 包含人類參與。當 model 進入錯誤路徑或讀取 40,000 行的 log 時,觀察者可以停止操作。unattended agent 沒有這種制動機制:它會持續執行直到 loop 結束,接著 timer 會再次啟動它。

執行頻率是容易被忽略的乘數。每 5 分鐘執行一次的工作,每天執行 288 次,每月約執行 8,640 次。單次執行的成本,就是你需要乘算的基準。許多「always-on」agent 並不需要持續開啟。它們只需要在指定分鐘數內做出回應,這本身就是一種排程。

Agent 的支出也包含 chat window 無需負擔的項目。

  • Tool definitions 會隨每個 request 一起傳送。 在 Claude Opus 4.8 使用 tool_choiceautonone 時,tool-use system prompt 成本為 290 tokens;使用 anytool 時則為 410 tokens。bash tool 會額外增加 325 tokens。你掛載的每個 MCP server 都會將其 schemas 增加至該負載中,MCP 指的是 model context protocol。
  • Tool results 會轉換為 input tokens。 一個輸出 8,000 行內容的 command,會將這 8,000 行內容帶入下一個 request,以及該回合中後續的每個 request。
  • 擷取的網頁會轉換為 input tokens。 平均 10 kB 的網頁約為 2,500 tokens,500 kB 的研究用 PDF 約為 125,000 tokens。max_content_tokens 僅會截斷文字內容,因為它「適用於文字內容,而非 PDF 等二進位內容」。請改用 max_usesallowed_domains 來處理 PDF。
  • Web search 按次計費,每 1,000 次搜尋為 $10,無論回傳多少結果。發生錯誤的搜尋不會計費。

上述項目單次執行並不昂貴。但若執行 8,640 次,總成本將非常高昂。

Hard ceilings 與 soft ceilings 解決不同的問題

max_tokens 是強制執行的。 這是單次請求總輸出(包含思考與回應文字)的硬上限。Claude 絕不會超過此限制,且模型無法得知該數值。達到此限制會導致 stop_reason: "max_tokens" 並產生截斷的回答。對於 Agent 而言,關鍵點在於:工具使用迴圈中的每次請求都帶有各自的 max_tokens,因此它限制的是單次回應而非整個任務。若每次工具呼叫為 4,000 token,則該回合的總上限為 40,000 token。

任務預算(Task budget)僅供參考。 task_budget 包含在 output_config 之中,用來告知模型整個 Agent 迴圈可使用的 token 總數,計算範圍包含思考、工具呼叫、工具結果與輸出。

resp = client.beta.messages.create(
    model="claude-opus-4-8",
    max_tokens=4096,
    betas=["task-budgets-2026-03-13"],
    output_config={"task_budget": {"type": "tokens", "total": 64000}},
    messages=messages,
)

「任務預算僅是軟性提示,而非硬性上限。」Claude 可能在執行中途超過預算,但輸出的強制限制仍為 max_tokens。「倒數計時僅模型可見」,且回應中不包含剩餘預算欄位。接受的最小 task_budget.total 為 20,000 token,低於此值會回傳 400 error。若預算不足以完成工作,模型會表現出類似拒絕的行為,進而縮減任務規模或提早停止。

有一個細節會增加成本而非節省成本。若您的 client 在每次後續請求中遞減 task_budget.remaining,變動後的數值會使包含該數值的任何快取前綴(cached prefix)失效。請在第一次請求時設定一次即可。

任務預算目前在 Claude Fable 5、Claude Opus 4.8 與 Claude Opus 4.7 處於 beta 階段。Claude Sonnet 5 與 Claude Haiku 4.5 被列為 Not supported,且任務預算不適用於 Claude Code,因此 Claude Code session detached in tmux 需依賴 session 的維護管理。

第三種限制位於 Claude Console:為 Agent 分配獨立的 workspace,接著設定每月消費限額與每分鐘速率限制。「無法在 Default Workspace 設定限制」,且「組織層級的限制始終有效,即便 workspace 的限制總和較高亦然」。建議啟用消費通知,以便在達到上限前收到警示。

每項任務的模型選擇,以及實際影響成本的因素

模型選擇是針對個別任務的決策。截至 2026 年 7 月,每百萬 token 的輸入與輸出成本如下:Claude Fable 5 為 $10 與 $50;Claude Opus 4.8 與 Opus 4.7 為 $5 與 $25;Claude Sonnet 5 為 $3 與 $15;Claude Haiku 4.5 為 $1 與 $5。目前 Sonnet 5 的價格低於標價,因為「2026 年 8 月 31 日前,每百萬輸入/輸出 token 的優惠價格為 $2/$10」。若步驟僅需進行 log 行分類,則不需要使用 Opus。

「Effort」是第二個變數。output_config.effort 接受 lowmediumhighxhighmax,預設值為 high,因此明確設定 high 與省略不寫的效果相同。降低 effort 不僅是縮短推理長度:根據文件,這會讓 Claude 減少 tool calls 並將多個操作合併為一個。對於 Agent 而言,這能帶來更大的節省,因為避免一次 tool call 就等於避免了一次完整的 request。

陷阱在於 effort 會與 cache 產生衝突。在不同 request 之間更改該值會導致 prompt caching 失效。在文件範例中,request 2 回報了 cache_read_input_tokens: 3546;request 3 將 effort 從 high 改為 medium,回報的 cache_creation_input_tokens 為 3546,cache_read_input_tokens 為 0。因此,請針對不同工作負載調整 effort,切勿在同一個已快取的對話中使用不同的設定。若要在不破壞 cache 的情況下引導深度,請在 prompt 中進行:例如在最新的 user message 中加入「直接回答,無需深思熟慮」之類的指令,即可保持先前的 breakpoint 不受影響。

Thinking tokens 按 output 費率計費,並計入 max_tokens,這也是為何回答被截斷通常代表 thinking 耗盡了預算。具體數值請參閱 usage.output_tokens_details.thinking_tokens什麼因素會導致 Claude 帳單增加 詳細解析了計費細節。

快取穩定前綴,避免意外失效

五分鐘快取的寫入成本為基礎輸入價格的 1.25 倍,一小時快取則為 2 倍。讀取成本僅為 0.1 倍,因此「對於 5 分鐘快取,只需 1 次讀取即可回本 (1.25x 寫入);對於 1 小時快取,只需 2 次讀取即可回本 (2x 寫入)」。

這對持續運行的 Agent 非常適用:「每次使用快取內容時,都會以零額外成本重新整理快取。」若針對五分鐘快取每兩分鐘執行一次任務,只需一次寫入即可讓前綴全天保持熱狀態。

三種可能導致快取無預警失效的情況。

前綴發生變動。 「快取前綴依下列順序建立:toolssystem,接著是 messages。」該順序中任何位元組的變動都會導致後續內容失效,且修改工具定義會使整個快取失效。常見的錯誤是在 System Prompt 中加入時間戳記或 Run ID:這會導致每次請求都帶有不同的前綴,進而產生 1.25x 的新寫入,且無法讀取任何快取。判斷依據是相同請求下的 usage.cache_read_input_tokens 為 0。請將變動內容移至最新的 User Message 中。

前綴長度不足。 每種模型都有最小快取長度限制,低於此長度時請求將不進行快取,且「不會回傳錯誤」。例如 Claude Opus 4.8 與 Claude Sonnet 5 的門檻為 1,024 tokens,而 Claude Haiku 4.5 為 4,096 tokens。因此,將任務從 Sonnet 移至 Haiku 可能會導致快取靜默失效。

對話長度超過回溯範圍。 「回溯視窗為 20 個 blocks。」系統在每個斷點最多檢查 20 個位置。在範例中,若一個回合包含 35 個 blocks 且斷點位於第 35 個 block,系統會檢查第 35 到第 16 個 blocks;前一個回合在第 15 個 block 的內容會超出視窗,因此無法命中。若 Agent 每回合新增數個 Tool-use 與 Tool-result blocks,只需兩到三個回合就會超過 20 個。每次請求最多有四個斷點,請將其中一個分配給最近的訊息。

將非即時任務傳送至 Batches API

所有輸入與輸出皆按標準 API 價格的 50% 計費。批次處理為非同步作業,大部分批次會在 1 小時內完成;結果會在所有請求結束或 24 小時後提供(以先發生者為準)。此為常見情況,而非保證。

持續輪詢 processing_status 直到其值為 ended。回傳 erroredcanceledexpired 的請求不會計費。若您有設定支出上限,請注意:「批次作業可能會略微超過 Workspace 設定的支出限制。」

折扣可以疊加。由於批次處理可能超過 5 分鐘,若多個批次共享相同 context,文件建議使用 1 小時快取。請進行任務拆分:任何需要人工或 webhook 等待的任務應維持在即時路徑;而每日摘要或昨天的日誌分類,則應使用半價的批次處理。

將每次回應的使用量欄位記錄至您的儲存空間

若未記錄支出,便無法進行費用歸屬。每次回應都會顯示其成本。

u = resp.usage
row = {
    "job": job_name,
    "model": resp.model,
    "uncached_input": u.input_tokens,
    "cache_write": u.cache_creation_input_tokens,
    "cache_read": u.cache_read_input_tokens,
    "output": u.output_tokens,
    "stop_reason": resp.stop_reason,
}

針對每次 API 呼叫,在 JSON-lines 檔案中新增一行並標記您的 job name。一週後,您即可辨識哪些 job 產生了實際支出,哪些僅是看似繁忙。請注意 cache_read:在自架 agent 中,全為零的欄位是最常見的成本錯誤。

有一個欄位容易誤讀。input_tokens 僅計算最後一個 cache breakpoint 之後的 tokens,因此實際的 prompt size 為 total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens。若 agent 對大型 prompt 回報 input_tokens: 400,代表成本並不低:其餘部分來自 cache。

在發送前進行計算。Token 計數是免費的,且其 rate limits 與訊息建立是分開計算的,因此請使用 count_tokens 來拒絕過大的附件,而非支付費用後才發現。結果僅為估計值,因此請針對不同 model 重新測量,且切勿重複使用其他 vendor tokenizer 的計數結果。Claude Opus 4.7 及之後的 Opus models、Claude Fable 5 與 Claude Sonnet 5 使用較新的 tokenizer,對於相同文本「會產生大約 30% 更多的 tokens」。Claude Sonnet 4.6 及之前的版本(包含 Claude Haiku 4.5)則使用舊版 tokenizer。

若需取得權威數據,Admin API 會在 https://api.anthropic.com/v1/organizations/usage_report/messages 回報使用量,並在 https://api.anthropic.com/v1/organizations/cost_report 回報成本。兩者皆需透過 anthropic-version: 2023-06-01 將 admin key (sk-ant-admin01-...) 作為 x-api-key: $ANTHROPIC_ADMIN_KEY,並接受 bucket_width=1dgroup_by[]=modelapi_key_ids[]=。一個限制:「Admin API 不提供給個人帳戶使用。」

最後一個參數是一個低成本的歸屬技巧:為每個 job 分配專屬的 API key,使用 api_key_ids[] 進行過濾,並依據 group_by[]=api_key_id 拆分報告。過濾條件為複數,分組維度為單數。請將 keys 儲存在 environment 中而非 code 內,如同 a first Claude API app on a VPS 的處理方式。

Bound the loop, because nothing else will

A bounded iteration count is not optional here. The loop is yours, so the counter is yours:

for step in range(MAX_STEPS):          # MAX_STEPS = 12, never "while True"
    resp = client.messages.create(...)
    if resp.stop_reason != "tool_use":
        break
else:
    log.warning("job %s hit MAX_STEPS=%d, giving up", job_name, MAX_STEPS)

Neither ceiling above does it for you: max_tokens caps one response, and the model is only advised of a task budget.

Put a second brake outside the process. Run the job from a systemd timer instead of a permanent process, and set RuntimeMaxSec= on its service unit. With RuntimeMaxSec=600, a hung run is killed after ten minutes instead of spinning until you notice. Running a program as a systemd service and timer covers the unit files themselves. Read what a run did with journalctl -u triage-agent.service --since "1 hour ago".

Cap retries as well, because a handler that retries forever bills every attempt. A 429 or a 500 deserves a few tries with backoff. A 400 deserves none, since the same request fails the same way.

AI agent 成本控制始於分析數據

無人能預測持續運行的 agent 成本,因為成本等於「每次運行的 token 數」乘以「每日運行次數」,而這兩個數值皆由您決定。請執行一次任務,記錄其 usage 行,並乘以您的排程。兩天後將實際成本報告與該計算結果進行比對。若兩者不符,差異通常是由快取失效或運行時間超出預期的迴圈所造成。

這項計算前提是使用 API key,因為 agent 是由您自己的程式呼叫 Messages API。若為個人互動使用,請參閱 哪種 Claude 方案符合您的工作方式 以了解訂閱相關資訊。此處所有價格與限制均以 2026 年 7 月的 Anthropic 文件為準,在編列預算前請重新閱讀定價頁面。

FAQ

在 VPS 上執行持續運行的 AI Agent 成本是多少?

會有兩份帳單,且只有一份是可預測的。伺服器費用為固定的月費。Model API 則按 token 計費,因此成本等於單次執行消耗量乘以執行頻率。Anthropic 並未公布自架持續運行 Agent 的具體數據,因此任何引用的數字僅供參考。請記錄一次實際運行的 usage,再乘以您的執行排程。

max_tokens 與 Task Budget 有何區別?

max_tokens 是強制執行且對模型不可見的限制。它限制單次請求的輸出量(包含思考過程),觸發此限制會導致 stop_reason: "max_tokens"。Task Budget 則相反:模型會得知該數值並根據此數值調整 Agent 迴圈的節奏,但「Task budgets 是軟性提示而非硬性限制」,強制限制仍為 max_tokens

為什麼我的 Agent 的 cache_read_input_tokens 總是 0?

因為呼叫間的 Prefix 發生變化,或是長度太短無法進行 Cache。常見原因是 System Prompt 中插入了 Timestamp 或 Run ID:Cache 是以 Prefix 為 Key,因此任何位元組(byte)的變動都會使後續內容失效。更改 Tool definitions 或 effort 值也會導致相同結果。此外,若 Prompt 過短則不會進行 Cache,且系統不會回傳錯誤。

如何防止 AI Agent 無限迴圈?

請在迴圈程式碼中計算迭代次數,並在固定最大值時停止,因為 max_tokens 僅限制單次回應,而 Agent 會進行多次回應。在 Process 外部增加實時時鐘(wall-clock)限制:使用設定了 RuntimeMaxSec= 的 systemd timer 來啟動工作,以便在卡住時按時終止。同時也要限制 Retry 次數,因為每次 Retry 迴圈都會產生費用。

我可以針對單一 Claude API Key 設定消費限額嗎?

文件記載的消費限額是針對 Workspace 而非單一 Key,因此請為 Agent 提供獨立的 Workspace 並在該處設定每月消費上限。「You cannot set limits on the Default Workspace」。建議開啟消費通知,以便在達到閾值時收到警示。若需進行費用歸屬(attribution),請為每個工作分配獨立的 Key,然後使用 group_by[]=api_key_id 進行使用量報告的分組。

#claude#ai#agents#api#cost