コンピュータアクセスシステム

エージェントコスト最適化:API費用を削減するための実践ガイド


エージェントコスト最適化:API費用を削減するための実践ガイド

あなたのエージェントは順調に動いている。1日200リクエストをこなし、ユーザーも満足している。そしてAPIの請求書を確認すると、今月は3,400ドル。数字を詳しく見ると、エージェントは1リクエストあたり平均12回のAPIコールを行い、それぞれに4,000トークンのシステムプロンプトが含まれていることがわかる。システムプロンプトだけで1日あたり960万の入力トークンになる。100万トークンあたり3ドルとすると、繰り返しコンテンツだけで月864ドルになる。

コストは、本番環境でのエージェント運用が縮小・廃止される最大の理由だ。最適化は時期尚早ではなく、生き残りのための手段だ。朗報としては、ほとんどのエージェント運用では、システム全体の再設計を必要としないシンプルな変更によって、50〜80%のコスト削減が可能だ。

このガイドでは、ROI(投資対効果)順に7つのコスト削減戦略を紹介する。上から順に取り組み、予算目標に達したら止めよう。各セクションには具体的な数字が含まれているため、コードを1行も書く前に削減効果を試算できる。


1. トークン計測:費用の発生源を把握する

計測できないものは最適化できない。何かを変える前に、エージェントワークフローのどこにすべての費用が発生しているかを完全に把握しよう。

入力トークンの内訳

Claudeへのすべてのアクシコールには、入力側にいくつかのトークンカテゴリが含まれる:

  • システムプロンプト — 指示、ペルソナ、制約。多くの場合1,000〜5,000トークンで、すべてのコールで繰り返される。
  • ツール定義 — エージェントが使用できる各ツールのJSONスキーマ。10個のツールで2,000〜3,000トークンを簡単に消費する。
  • 会話履歴 — 会話内のすべての過去メッセージ。ステップごとに増加する。
  • ツール結果 — 以前のツールコールの出力をコンテキストに注入したもの。非常に大きくなる場合がある(完全なウェブページ、データベースの結果など)。

出力トークンの内訳

出力トークンは入力トークンより3〜5倍高価であるため、重要な最適化対象となる:

  • エージェントの推論 — 内部の思考連鎖(特に拡張思考を使用する場合)。
  • ツールコールの生成 — ツール呼び出し用のJSON。
  • 最終的な応答 — ユーザー向けの回答。

タスクあたりのコスト計算

1つのエージェントタスクの総コストは次のとおりだ:

総コスト = Σ (入力トークン数 × 入力単価 + 出力トークン数 × 出力単価)
タスク内の各APIコールについて

コスト内訳の例

Claude Sonnet(入力$3/M、出力$15/M)を使用した10ステップのリサーチエージェントタスクの現実的な内訳を示す:

ステップコンポーネント入力トークン出力トークン入力コスト出力コスト合計
1初期計画4,200800$0.0126$0.0120$0.025
2ウェブ検索コール4,800200$0.0144$0.0030$0.017
3検索結果の処理8,500600$0.0255$0.0090$0.035
4精読(ページ1)12,000500$0.0360$0.0075$0.044
5精読(ページ2)15,200500$0.0456$0.0075$0.053
6追加検索16,800200$0.0504$0.0030$0.053
7結果の処理20,100600$0.0603$0.0090$0.069
8統合22,5001,200$0.0675$0.0180$0.086
9検証24,000400$0.0720$0.0060$0.078
10最終応答25,5001,500$0.0765$0.0225$0.099
合計153,6006,500$0.461$0.098$0.558

入力コストが支配的であり、会話履歴が蓄積されるにつれてステップごとに増加することに注目してほしい。ステップ8〜10はステップ数全体の30%に過ぎないにもかかわらず、総コストの47%を占めている。

コスト追跡コード

初日からトラッキングラッパーを実装しよう:

import anthropic
import time
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class CostRecord:
step: int
model: str
input_tokens: int
output_tokens: int
cache_read_tokens: int = 0
cache_creation_tokens: int = 0
input_cost: float = 0.0
output_cost: float = 0.0
total_cost: float = 0.0
duration_ms: float = 0.0
# Pricing per million tokens (as of early 2026)
MODEL_PRICING = {
"claude-haiku": {"input": 0.25, "output": 1.25, "cache_read": 0.025, "cache_write": 0.30},
"claude-sonnet": {"input": 3.00, "output": 15.00, "cache_read": 0.30, "cache_write": 3.75},
"claude-opus": {"input": 15.00, "output": 75.00, "cache_read": 1.50, "cache_write": 18.75},
}
@dataclass
class TaskCostTracker:
task_id: str
budget_limit: Optional[float] = None
records: list = field(default_factory=list)
total_cost: float = 0.0
def record_call(self, step: int, model: str, usage) -> CostRecord:
pricing = MODEL_PRICING.get(model, MODEL_PRICING["claude-sonnet"])
input_cost = (usage.input_tokens / 1_000_000) * pricing["input"]
output_cost = (usage.output_tokens / 1_000_000) * pricing["output"]
cache_read_cost = (getattr(usage, 'cache_read_input_tokens', 0) / 1_000_000) * pricing["cache_read"]
cache_write_cost = (getattr(usage, 'cache_creation_input_tokens', 0) / 1_000_000) * pricing["cache_write"]
total = input_cost + output_cost + cache_read_cost + cache_write_cost
record = CostRecord(
step=step,
model=model,
input_tokens=usage.input_tokens,
output_tokens=usage.output_tokens,
cache_read_tokens=getattr(usage, 'cache_read_input_tokens', 0),
cache_creation_tokens=getattr(usage, 'cache_creation_input_tokens', 0),
input_cost=input_cost + cache_read_cost + cache_write_cost,
output_cost=output_cost,
total_cost=total,
)
self.records.append(record)
self.total_cost += total
print(f" Step {step} [{model}]: {usage.input_tokens} in / {usage.output_tokens} out = ${total:.4f} (cumulative: ${self.total_cost:.4f})")
if self.budget_limit and self.total_cost > self.budget_limit:
raise BudgetExceededError(
f"Task {self.task_id} exceeded budget: ${self.total_cost:.4f} > ${self.budget_limit:.4f}"
)
return record
def summary(self) -> dict:
return {
"task_id": self.task_id,
"total_steps": len(self.records),
"total_input_tokens": sum(r.input_tokens for r in self.records),
"total_output_tokens": sum(r.output_tokens for r in self.records),
"total_cost": self.total_cost,
"cost_by_model": self._cost_by_model(),
}
def _cost_by_model(self) -> dict:
by_model = {}
for r in self.records:
if r.model not in by_model:
by_model[r.model] = {"calls": 0, "cost": 0.0}
by_model[r.model]["calls"] += 1
by_model[r.model]["cost"] += r.total_cost
return by_model
class BudgetExceededError(Exception):
pass

最適化の前から今日すぐ計測を始めよう。改善を測定するためにベースラインの数字が必要だ。


2. タスクに応じたモデル選択

これはあなたが使える最大のコスト削減手段だ。すべてのエージェントステップに最も強力なモデルが必要なわけではない。

モデルのティアと価格

Claudeファミリーを参考として使用する:

モデル入力(100万トークンあたり)出力(100万トークンあたり)最適な用途
Haiku$0.25$1.25分類、ルーティング、抽出、シンプルなフォーマット

関連記事