--- name: cost-aware-llm-pipeline description: LLM API 使用成本優化模式 — 根據任務複雜度進行模型路由、預算追蹤、重試邏輯以及提示詞快取 (Prompt Caching)。 --- # 具備成本意識的 LLM 流水線 (Cost-Aware LLM Pipeline) 在維持品質的同時控制 LLM API 成本的模式。將模型路由、預算追蹤、重試邏輯與提示詞快取整合為一個可組合的流水線。 ## 何時啟用 - 建置呼叫 LLM API (Claude, GPT 等) 的應用程式。 - 處理複雜度各異的批次項目。 - 需要將 API 支出控制在預算範圍內。 - 在不犧牲複雜任務品質的前提下優化成本。 ## 核心概念 ### 1. 依任務複雜度進行模型路由 針對簡單任務自動選擇較便宜的模型,將昂貴的模型保留給複雜任務。 ```python MODEL_SONNET = "claude-sonnet-4-6" MODEL_HAIKU = "claude-haiku-4-5-20251001" _SONNET_TEXT_THRESHOLD = 10_000 # 字元數門檻 _SONNET_ITEM_THRESHOLD = 30 # 項目數門檻 def select_model( text_length: int, item_count: int, force_model: str | None = None, ) -> str: """根據任務複雜度選擇模型。""" if force_model is not None: return force_model if text_length >= _SONNET_TEXT_THRESHOLD or item_count >= _SONNET_ITEM_THRESHOLD: return MODEL_SONNET # 複雜任務 return MODEL_HAIKU # 簡單任務 (便宜 3-4 倍) ``` ### 2. 不可變的成本追蹤 (Immutable Cost Tracking) 使用凍結資料類別 (Frozen dataclasses) 追蹤累計支出。每次 API 呼叫都會回傳一個新的追蹤器 — 絕對不要修改現有狀態。 ```python from dataclasses import dataclass @dataclass(frozen=True, slots=True) class CostRecord: model: str input_tokens: int output_tokens: int cost_usd: float @dataclass(frozen=True, slots=True) class CostTracker: budget_limit: float = 1.00 records: tuple[CostRecord, ...] = () def add(self, record: CostRecord) -> "CostTracker": """回傳包含新記錄的新追蹤器 (絕不修改自身狀態)。""" return CostTracker( budget_limit=self.budget_limit, records=(*self.records, record), ) @property def total_cost(self) -> float: return sum(r.cost_usd for r in self.records) @property def over_budget(self) -> bool: return self.total_cost > self.budget_limit ``` ### 3. 精確的重試邏輯 僅在發生暫時性錯誤時重試。若發生身分驗證或錯誤請求 (Bad Request) 錯誤,則應立即失敗。 ```python from anthropic import ( APIConnectionError, InternalServerError, RateLimitError, ) _RETRYABLE_ERRORS = (APIConnectionError, RateLimitError, InternalServerError) _MAX_RETRIES = 3 def call_with_retry(func, *, max_retries: int = _MAX_RETRIES): """僅針對暫時性錯誤進行重試,其餘錯誤則立即報錯。""" for attempt in range(max_retries): try: return func() except _RETRYABLE_ERRORS: if attempt == max_retries - 1: raise time.sleep(2 ** attempt) # 指數退避 (Exponential backoff) # 身分驗證錯誤 (AuthenticationError)、錯誤請求 (BadRequestError) 等 → 立即抛出異常 ``` ### 4. 提示詞快取 (Prompt Caching) 快取長型的系統提示詞,避免在每次請求時重複發送。 ```python messages = [ { "role": "user", "content": [ { "type": "text", "text": system_prompt, "cache_control": {"type": "ephemeral"}, # 快取此部分 }, { "type": "text", "text": user_input, # 變動部分 }, ], } ] ``` ## 組合運作 將上述四種技術整合至單一流水線函式中: ```python def process(text: str, config: Config, tracker: CostTracker) -> tuple[Result, CostTracker]: # 1. 模型路由 model = select_model(len(text), estimated_items, config.force_model) # 2. 檢查預算 if tracker.over_budget: raise BudgetExceededError(tracker.total_cost, tracker.budget_limit) # 3. 呼叫並採用重試與快取機制 response = call_with_retry(lambda: client.messages.create( model=model, messages=build_cached_messages(system_prompt, text), )) # 4. 追蹤成本 (不可變狀態) record = CostRecord(model=model, input_tokens=..., output_tokens=..., cost_usd=...) tracker = tracker.add(record) return parse_result(response), tracker ``` ## 價格參考 (2025-2026) | 模型 | 輸入 (USD/每百萬 tokens) | 輸出 (USD/每百萬 tokens) | 相對成本 | |-------|---------------------|----------------------|---------------| | Haiku 4.5 | $0.80 | $4.00 | 1x | | Sonnet 4.6 | $3.00 | $15.00 | ~4x | | Opus 4.5 | $15.00 | $75.00 | ~19x | ## 最佳實踐 - **從最便宜的模型開始**,僅在達到複雜度門檻時才路由至昂貴的模型。 - 在處理批次任務前 **設定明確的預算限制** — 寧可提早失敗也不要超額支出。 - **記錄模型選擇的決策**,以便您可以根據實際數據調整門檻。 - 針對超過 1024 tokens 的系統提示詞 **使用提示詞快取** — 可節省成本並降低延遲。 - **絕對不要在身分驗證或驗證錯誤時重試** — 僅針對暫時性故障(網路、速率限制、伺服器錯誤)執行重試。 ## 應避免的反模式 - 不論複雜度如何,對所有請求都使用最昂貴的模型。 - 在發生所有錯誤時都重試(會在永久性失敗上浪費預算)。 - 修改成本追蹤狀態(會導致偵錯與稽核變得困難)。 - 在程式碼庫中硬編碼模型名稱(應使用常數或配置檔)。 - 忽視重複性系統提示詞的快取機制。 ## 何時使用 - 任何呼叫 Claude、OpenAI 或類似 LLM API 的應用程式。 - 成本會迅速累積的批次處理流水線。 - 需要智慧路由的多模型架構。 - 需要預算防護欄 (Guardrails) 的生產系統。