powered by TechFeed
表示モード
Deep Dive

LLMのAPIコストは「トークン単価×呼び出し回数」では計算できない — エージェントループが二次関数的に請求を膨らませる理由と、85%削減のための5つの手法

8月24日、Collabnixが「Cut Your LLM Token Bill by 85% in 2026: Caching, Routing, and Context Discipline」と題した記事を公開した。LLMのAPIコストを最大85%削減するためのキャッシング・ルーティング・コンテキスト管理の実践的な手法が詳しく紹介されている。

8月24日、Collabnixが「Cut Your LLM Token Bill by 85% in 2026: Caching, Routing, and Context Discipline」と題した記事を公開した。LLMのAPIコストを最大85%削減するためのキャッシング・ルーティング・コンテキスト管理の実践的な手法が詳しく紹介されている。


「トークンは安くなった、なのに請求額が増えた」の正体

2025年にLLM機能を本番リリースしたチームの多くが、2026年に同じ問題に直面している。確かにトークン単価は下がった。それでも請求額は増えている。

原因は構造的なものだ。単発のプロンプトではなく、エージェントループ(LLMがツール呼び出しと結果の受け取りを繰り返しながら自律的にタスクを遂行する実行サイクル)を動かすようになったからである。エージェントループはトークンを線形に消費しない。二次関数的に消費する

数式で示すと明確だ。静的なシステムプロンプトとツール定義をS、1ターンあたりのトークンをu、ツール結果のトークンをr、ステップ数をNとすると:

Total input tokens = N·S + u·N(N+1)/2 + r·N(N-1)/2

三角数の項がコストを爆発させる。具体的な数字を入れると:

ステップ数 累積入力トークン Claude Opus 5でのコスト($5/MTok)
1 6,000 $0.03
5 44,000 $0.22
10 142,000 $0.71
20 508,000 $2.54

10ステップのループは1回の呼び出しの23倍のコストがかかる。10倍ではない。ステップ数を掛け算してコストを見積もったなら、桁がひとつずれている。


2026年の価格テーブル

各施策の効果を考える前提として、現在の価格(単位:$/ 100万トークン)を確認しておきたい。

モデル 入力 キャッシュ入力 出力
Claude Opus 5 $5.00 $0.50 $25.00
Claude Sonnet 5 $2.00 $0.20 $10.00
Claude Haiku 4.5 $1.00 $0.10 $5.00
Gemini 3.7 Flash $0.75 $0.075 $3.75
Gemini 2.5 Flash-Lite $0.10 $0.01 $0.40

注目すべき非対称性が3つある。

  • 出力トークンは入力の5倍前後の価格になるモデルが多い(Claude Opus 5は入力$5・出力$25)。ただしモデルによって倍率は異なるため、一般論として捉えてほしい。200トークンの回答が900トークンのプロンプトより高くつくケースは珍しくない。
  • 非英語テキストは2〜5倍のトークンを消費するBPEトークナイザーは英語中心に訓練されているため、日本語やHindiでは1文字1トークン相当になることもある。
  • 毎回の呼び出しでコンテキスト全体に課金される。差分ではなく全体。これがエージェントワークロードでコストを破壊する。

価格は変動する。数字はコードのconfigファイルで管理すること。


まず計測する

最適化の前に計測が必要だ。cache_read_input_tokens、ルーティング判断、ステップごとのトークン消費をプロダクションで記録することが前提となる。実測データも存在する。ある計測済みのエージェントトレースでは、48,400トークン中30,400トークンがツール結果だけで占められており、そのうち40〜60%は品質を落とさずに除去できたという。カウンターなしで最適化しようとすると、間違った場所を掘り続けることになる。


5つの削減レバー

レバー1:プロンプトキャッシング(手っ取り早い25%削減)

システムプロンプト、ツール定義、few-shotサンプルが呼び出しをまたいで変わらないなら、毎回同じバイト列をフル価格で送信し続けていることになる。

各プロバイダのキャッシュヒット時の価格は**ベースレートの10%**。AnthropicGoogleOpenAIともに概ね0.1倍の価格設定だ(キャッシュ書き込みは1.25〜2倍のプレミアムがかかるが、2回目の読み出しで回収できる)。

基本原則は「静的なものを前に、動的なものを後ろに」。キャッシュはプレフィックスで機能するため、先頭付近に動的なトークンが1つあると、以下のキャッシュ全体が無効化される。

import anthropic
client = anthropic.Anthropic()
resp = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=1024,
    system=[
        {
            "type": "text",
            "text": SYSTEM_PROMPT + TOOL_DOCS + FEW_SHOT_EXAMPLES,
            "cache_control": {"type": "ephemeral"},   # ここより上がキャッシュされる
        },
    ],
    messages=[{"role": "user", "content": user_query}],   # 動的、キャッシュ対象外
)
u = resp.usage
print(f"write={u.cache_creation_input_tokens} "
      f"read={u.cache_read_input_tokens} "
      f"fresh={u.input_tokens} out={u.output_tokens}")

本番環境ではcache_read_input_tokensを必ずログに記録すること。2回目の呼び出しでこの値がゼロなら、タイムスタンプやセッションIDがプロンプトの先頭に混入している可能性が高い。キャッシュヒット率の低下はコスト回帰の初期症状だ。

レバー2:難易度でルーティングする

分類、抽出、フォーマット変換、短い事実確認——これらは最上位モデルを使う必要がない。公開されている研究(RouteLLM論文)では、ルーティングフレームワークを導入することでフロンティアモデルの品質の約95%を維持しながら、高価なモデルへの呼び出しを14〜26%に抑えられるとされている。

ROUTER_PROMPT = """リクエストを 'simple' か 'complex' に分類する。
simple  = 検索、抽出、分類、フォーマット変換、言い換え
complex = 多段階推論、コード生成、要件が曖昧なもの
1単語で回答する。"""

def route(query: str) -> str:
    verdict = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=5,
        system=ROUTER_PROMPT,
        messages=[{"role": "user", "content": query}],
    ).content[0].text.strip().lower()
    return TIERS.get(verdict, TIERS["complex"])["model"]   # 不明な場合は強いモデルへ

重要な設計指針が2つある。ルーターが判断できない場合は強いモデルに流す(誤って難しいクエリを安いモデルに送るとユーザーを失うが、簡単なクエリを高いモデルに送っても損害はわずかだ)。そしてルーティング判断を結果と合わせてログに残し、勘ではなく実績でルーティング境界を調整する。

レバー3:エージェントループのコンテキスト管理

二次関数カーブを断ち切る4つのパターン。

ツール結果をコンテキストに入れる前にフィルタリングする。 APIレスポンスの3,000トークンのうち必要なのは6フィールドだけ、というケースは頻繁に起きる。LLMに要約させるのではなく、コードで決定論的に抽出する(要約させるとトークンを使ってトークンを節約することになり本末転倒だ)。

def compact_tool_result(raw: dict, fields: list[str]) -> str:
    """決定論的な抽出。LLM呼び出しなし、トークンコストなし。"""
    rows = raw.get("results", raw.get("data", []))
    return "\n".join(
        " | ".join(f"{f}={r.get(f)}" for f in fields if r.get(f) is not None)
        for r in rows[:20]        # ハードキャップ:21行目以降が必要になることはほぼない
    )

定期的にコンテキストを圧縮する。 10〜15回のツール呼び出しごとに、蓄積されたトランスクリプトを「決定事項・確認済み事実・現在の目標」の構造化サマリーに置き換える。実測では約22%の削減、かつ二次関数カーブをのこぎり歯状に変換できる。

コーディネーターとスペシャリストを分離する。 オーケストレーターがプランを持ち、各サブタスクを新鮮な最小限のコンテキストで別のサブエージェントに委譲する設計。ベンチマークでは平均54%のトークン削減が報告されており、コーディネーター自体が消費するトークンは全体の10%未満になる。

すべてにキャップをかける。 ステップ数・リトライ数・max_tokensに上限を設定する。無制限のリトライループは、一晩で5桁の請求を生成できる唯一のバグだ。

レバー4:セマンティックキャッシング

「パスワードをリセットしたい」と「パスワード再設定の方法」は同じ質問だが、完全一致キャッシュはこれを別物として扱う。セマンティックキャッシング(クエリをベクトル埋め込みして類似度検索を行い、閾値以上なら保存済みレスポンスを返す手法)は、高頻度トラフィックで約70%のコスト削減が報告されている。応答時間も秒単位からミリ秒単位になる。実装にはRedisベースのGPTCacheなどのライブラリが利用できる。

閾値の設定が全てだ。閾値を緩めすぎると、微妙に異なる質問に対して自信満々に間違った回答を返す。0.95から始めてラベル付きデータで偽ヒット率を計測してから緩めること。個人情報やアカウント固有の情報には絶対にセマンティックキャッシュを使わない。

レバー5:非同期処理をバッチ化する

夜間サマリー、一括分類、埋め込みの再計算、評価実行——これらはリアルタイム応答が不要なのに、多くのチームが同期APIで処理している。AnthropicOpenAIGoogle各社のBatch APIは入力・出力ともに50%オフだ。エンジニアリングコストに対するリターンが最も高い手段であり、どのワークロードが本当にインタラクティブである必要があるかを見直すだけで適用できる。


詳細はCut Your LLM Token Bill by 85% in 2026: Caching, Routing, and Context Disciplineを参照していただきたい。