目錄

你的 AI agent 上線了。功能很酷,但月底帳單讓你頭皮發麻。

這是 2025-2026 年 AI 工程師的新挑戰:LLM API 定價下降了,但 agent 的 token 使用量以倍數成長。一個「簡單的」工作流程代理人,每天可能跑出幾百美元的費用。

TL;DR

AI agent 費用暴增的三個根本原因:(1) 用了比需要更強(也更貴)的模型,(2) tool call 迴圈沒有深度限制導致無限呼叫,(3) 每輪對話都把整個歷史 context 傳進去造成 token 浪費。解法不是犧牲品質,而是對任務複雜度和模型能力做精準匹配。

前置條件

  • 你有一個已部署或正在開發的 LLM-based agent
  • 正在使用商業 API(OpenAI、Anthropic、Google、DeepSeek 等)
  • 想在維持功能品質的前提下降低 token 使用量

步驟

步驟 1:評估每個任務的實際複雜度

第一步不是選模型,是分類你的 agent 任務

任務類型範例需要的模型能力
結構化資料提取從收據擷取金額、日期低:規則化,格式固定
分類/路由判斷這個 issue 應該給哪個 team低-中:需要理解,不需要推理
程式碼生成(複雜邏輯)實作一個演算法高:需要多步推理
長文摘要把 20 頁報告壓縮成重點中:需要理解,不需要複雜推理
代理人規劃分解任務、選擇工具、處理錯誤高:需要可靠的工具使用能力

常見錯誤:把所有任務都丟給 Claude Opus 或 GPT-5,即使是「把這個 JSON 轉成表格」這種任務。

步驟 2:建立模型階層

依複雜度配置不同的模型:

# 範例:依任務類型路由到不同模型
MODELS = {
    "classification": "claude-haiku-4-5",      # 便宜,快
    "extraction": "claude-haiku-4-5",
    "summarization": "claude-sonnet-4-6",      # 中等
    "code_generation": "claude-sonnet-4-6",
    "complex_planning": "claude-opus-4-6",     # 保留給真正複雜的任務
}

def get_model_for_task(task_type: str) -> str:
    return MODELS.get(task_type, "claude-sonnet-4-6")

成本參考(2026 年 5 月定價):

  • Claude Haiku 4.5:~$0.08 / M input tokens
  • Claude Sonnet 4.6:~$3 / M input tokens
  • Claude Opus 4.6:~$15 / M input tokens

同樣的任務,Haiku 可能只花 Opus 費用的 0.5%。

步驟 3:控制 Tool Call 深度

沒有深度限制的 agent 在遇到問題時可能陷入無限 tool call 迴圈:

# 錯誤:沒有迭代上限
while not task_complete:
    response = llm.call(tools=all_tools, messages=history)
    handle_tool_calls(response)

# 正確:設定最大迭代數
MAX_ITERATIONS = 10
for i in range(MAX_ITERATIONS):
    response = llm.call(tools=all_tools, messages=history)
    if not response.tool_calls:
        break  # 沒有 tool call 表示任務完成
    handle_tool_calls(response)
else:
    # 超過上限,記錄並回傳部分結果
    logger.warning(f"Agent hit max iterations for task: {task_id}")

每多一輪 tool call,就多一次 LLM 呼叫費用,加上整個 context 重新傳一遍的 token 費用。

步驟 4:精簡 Context 傳遞

每次 LLM 呼叫都把整個對話歷史傳進去是最大的 token 浪費來源之一。

策略一:滑動視窗

# 只保留最近 N 輪對話
def trim_history(messages: list, max_turns: int = 5) -> list:
    system_messages = [m for m in messages if m["role"] == "system"]
    conversation = [m for m in messages if m["role"] != "system"]
    # 保留最後 max_turns * 2 條訊息(每輪一問一答)
    recent = conversation[-(max_turns * 2):]
    return system_messages + recent

策略二:壓縮中間 tool 結果

Tool call 的回傳資料常常很大(例如整個 API 回應),但 agent 只需要其中的關鍵欄位:

def compress_tool_result(tool_name: str, result: dict) -> str:
    """只保留 agent 需要繼續決策的關鍵資訊"""
    if tool_name == "search_web":
        # 只保留標題和摘要,不要全文
        return "\n".join(
            f"- {r['title']}: {r['snippet']}"
            for r in result.get("results", [])[:3]
        )
    return str(result)  # 其他 tool 的 fallback

步驟 5:快取重複呼叫

如果你的 agent 在不同任務中重複呼叫相同的工具(例如每次都重新取得使用者資料),加快取可以大幅降低費用:

import functools

@functools.lru_cache(maxsize=128)
def get_user_profile(user_id: str) -> dict:
    """快取使用者資料,避免重複 DB 查詢和 LLM 摘要"""
    return db.get_user(user_id)

常見問題

Q:降到便宜的模型會不會讓 agent 變笨,導致更多錯誤和重試?

A:這取決於任務類型。對結構化提取和分類,Haiku 的準確率通常夠用。對需要多步推理的任務,強行降模型反而會因為重試增加總費用。先測試準確率,再做成本決策。

Q:如何衡量優化後的成本節省?

A:在每次 LLM 呼叫時記錄 token 用量:

response = client.messages.create(...)
logger.info({
    "task_id": task_id,
    "model": model,
    "input_tokens": response.usage.input_tokens,
    "output_tokens": response.usage.output_tokens,
    "cost_usd": calculate_cost(model, response.usage)
})

建立每個任務類型的 token 基準,持續追蹤偏差。

參考資料

相關標籤

相關文章