AI業務活用 2026.04.22

Claude API高額請求を防ぐ4つの方法【2026年版】レート制限・使用量監視・バジェットアラート実装

タグ:Claude / API / コスト管理 / エラー対策

高額請求が起きる典型パターン

# ❌ 危険なコード(無限ループ)
while True:  # ← 止まらない
    response = client.messages.create(
        model="claude-opus-5",      # 最高額モデル
        max_tokens=4096,             # 最大出力
        messages=[{"role": "user", "content": large_file}]  # 大きなファイル
    )
    # エラーハンドリングなし → 例外で止まらない

# ✅ 安全なコード
MAX_CALLS = 100
calls = 0

while calls < MAX_CALLS:
    try:
        response = client.messages.create(
            model="claude-haiku-4-5-20251001",  # コスト最小のモデルを選ぶ
            max_tokens=512,                       # 必要最小限のmax_tokens
            messages=[{"role": "user", "content": prompt[:5000]}]  # 入力を制限
        )
        calls += 1
    except Exception as e:
        print(f"エラー: {e}")
        break  # エラーで停止

対策1: レート制限ラッパー

# rate_limiter.py
# APIコールに1日の上限とレート制限を設けるラッパー

import time
import json
from pathlib import Path
from datetime import date
import anthropic

client = anthropic.Anthropic()

class BudgetedClaude:
    """コスト上限付きのClaude APIラッパー"""
    
    PRICES = {
        "claude-haiku-4-5-20251001": (0.80, 4.00),
        "claude-sonnet-4-5": (3.00, 15.00),
        "claude-opus-5": (15.00, 75.00),
    }
    
    def __init__(self, daily_budget_usd: float = 5.0, min_interval_s: float = 1.0):
        self.daily_budget_usd = daily_budget_usd
        self.min_interval_s = min_interval_s
        self._last_call = 0.0
        self._stats_file = Path(".claude_usage.json")
    
    def _load_today_cost(self) -> float:
        if not self._stats_file.exists():
            return 0.0
        stats = json.loads(self._stats_file.read_text())
        if stats.get("date") != str(date.today()):
            return 0.0
        return stats.get("cost_usd", 0.0)
    
    def _save_cost(self, additional_cost: float) -> None:
        today_cost = self._load_today_cost() + additional_cost
        self._stats_file.write_text(json.dumps({
            "date": str(date.today()),
            "cost_usd": today_cost
        }))
    
    def create(self, model: str, max_tokens: int, messages: list) -> dict:
        """予算チェック付きAPIコール"""
        # 予算チェック
        today_cost = self._load_today_cost()
        if today_cost >= self.daily_budget_usd:
            raise RuntimeError(f"1日の予算上限 ${self.daily_budget_usd} に達しました(使用額: ${today_cost:.2f})")
        
        # レート制限(最小間隔)
        elapsed = time.time() - self._last_call
        if elapsed < self.min_interval_s:
            time.sleep(self.min_interval_s - elapsed)
        
        response = client.messages.create(
            model=model, max_tokens=max_tokens, messages=messages
        )
        
        # コスト記録
        inp, out = self.PRICES.get(model, (3.00, 15.00))
        cost = (response.usage.input_tokens * inp + response.usage.output_tokens * out) / 1_000_000
        self._save_cost(cost)
        self._last_call = time.time()
        
        print(f"[コスト] この呼び出し: ${cost:.4f} / 今日の合計: ${self._load_today_cost():.2f} / 上限: ${self.daily_budget_usd}")
        return response

# 使用例
budgeted = BudgetedClaude(daily_budget_usd=2.0)
response = budgeted.create(
    model="claude-haiku-4-5-20251001",
    max_tokens=512,
    messages=[{"role": "user", "content": "こんにちは"}]
)

対策2: Batches APIで50%削減

# batch_processing.py
# リアルタイム不要な処理はBatches APIで半額にする

import anthropic

client = anthropic.Anthropic()

def create_analysis_batch(items: list[str]) -> str:
    """大量のテキストをバッチ処理(通常料金の50%)"""
    
    requests = [
        {
            "custom_id": f"item-{i}",
            "params": {
                "model": "claude-haiku-4-5-20251001",
                "max_tokens": 256,
                "messages": [{
                    "role": "user",
                    "content": f"以下のレビューを「ポジティブ」「ネガティブ」「ニュートラル」に分類してください: {item}"
                }]
            }
        }
        for i, item in enumerate(items)
    ]
    
    batch = client.beta.messages.batches.create(requests=requests)
    print(f"バッチID: {batch.id}")
    print(f"件数: {len(items)}件(通常料金の50%で処理)")
    return batch.id

# 1000件のレビューを分類(通常$0.40 → バッチで$0.20)
reviews = ["素晴らしい!", "最悪でした", "普通です"] * 333
batch_id = create_analysis_batch(reviews)

対策3: コンソールで予算上限を設定する

Anthropicコンソール → Billing → Usage Limits で設定:

月間上限例:
  開発環境: $10/月
  ステージング: $50/月
  本番(小規模): $200/月
  本番(大規模): 要検討

上限到達時: APIが自動停止(429エラー)
→ コード側で429を適切にハンドリングする

あわせて読みたい

参考ソース