テーマを切り替える

AIエージェントのコスト管理:モデルルーティング、ツール予算、キャッシュ、リトライ制御

Easton editorial illustration: agent rollout and rollback rail
7
予算レイヤー
user、tenant、workflow、task、tool、retry、cache。
4
制御アクション
route、degrade、pause、abort。
3
キャッシュ種別
prompt prefix cache、business result cache、tool response cache。
数据来源: このエンジニアリングチェックリストは、フェーズ 1 の公式ドキュメント調査をもとに整理しています。価格、割引、モデル提供状況は公開前に公式ページで再確認してください。

"OpenAI API Pricing"

午前 3 時、バックグラウンドの report Agent が空のレスポンスを返します。HTTP ステータスは 200 なのに、body は空。リトライロジックはステータスコードだけを見ているため、そのまま再試行を続けます。1 回のリクエストで 500 token を送信し、1,500 回リトライした結果、75 万 token を消費。翌朝に請求を見て、ようやく異常に気づくわけです。

根本原因は「高いモデルを選んだこと」ではありません。欠けていたのは 3 つ。サーキットブレーカー、予算チェック、エラー分類です。Agent のコスト暴走には、典型的に次の 3 パターンがあります。

リトライに上限がない。 失敗モードの分類がなく、空レスポンスをリトライ可能なエラーとして扱います。サーキットブレーカーもないため、1,500 回連続で失敗しても止まりません。各リトライで完全なコンテキストを送り直し、コストが 2〜5 倍に膨らみます。

コンテキストが膨張する。 長時間タスクを 6 時間走らせた結果、会話履歴が 80K tokens まで膨らみます。checkpoint がないため、失敗すると最初から再実行し、各ステップで再び料金が発生します。

モデルを使いすぎる。 すべてのタスクで frontier モデルを使い、ルーティング戦略がありません。単純な分類タスクまで最も高いモデルに投げ、token の 70% を無駄にします。

Agent のコスト管理は単発の最適化ではありません。予算オブジェクト、ルーティング戦略、キャッシュヒット、リトライ遮断、コストログ、アラート閾値を重ねて設計するものです。この 6 つのエンジニアリング対象を、判断表や実行可能なチェックに落とします。

予算オブジェクト設計:何を記録し、どこに持ち、どう遮断するか

コスト管理は、まず予算オブジェクトから始めます。総額だけを記録しても足りません。分解されていないと、請求異常が起きたときに、どのユーザー、どのタスク、どのツールがコストを燃やしたのか分かりません。

7 層の予算オブジェクト

予算オブジェクトは粗い粒度から細かい粒度へ、7 層に分けられます。

予算レイヤー予算オブジェクト予算上限の目安アラート条件
Layer 1userユーザーごとの日次/月次上限残り < 20% でアラート
Layer 2tenanttenant ごとの独立予算プール残り < 30% でアラート
Layer 3workflowworkflow 種別ごとの独立予算残り < 40% でアラート
Layer 4taskタスク種別ごとの独立予算残り < 50% でアラート
Layer 5toolツール呼び出しごとの独立予算上限超過でツールをスキップ
Layer 6retryリトライ回数上限 + サーキットブレーカー連続失敗 N 回でツールを停止
Layer 7cacheキャッシュヒット率の監視ヒット率 < 期待値でアラート

各層の予算上限は業務モデルに依存するため、変わりやすい設定です。一方で、階層構造そのものは安定しています。残予算フィールドはコストログに書き込み、アラートと遮断判断に使います。

各層で記録するフィールド

各予算層では、次のフィールドを記録します。

フィールド名用途型記録する理由
modelモデルの特定stringモデルルーティングが妥当か判断するため
inputTokens入力 token 数integer入力コストを計算するため
outputTokens出力 token 数integer出力コストは入力と異なるため、独立して記録する
cachedTokensキャッシュヒットした token 数integerキャッシュによる節約を計算するため
costEstimate今回の推定コストfloatリアルタイムのコスト累積に使う
budgetRemaining残予算floatサーキットブレーカーの判断根拠になる

予算オブジェクト設計の中心は「軸ごとに記録すること」です。「total_cost だけを記録すること」ではありません。マルチテナントでは tenantId ごとにコストを按分し、複数ツールを使う場合は toolName でブラックボックスを特定します。

遮断ロジック

残予算が閾値を下回ったら、サーキットブレーカーを発動します。

def check_budget_before_retry(budget_remaining, retry_cost_estimate):
    if budget_remaining < retry_cost_estimate:
        return "skip_retry"  # 予算超過になるためリトライをスキップ
    if budget_remaining < threshold:  # threshold は例えば 20%
        return "wait_approval"  # 残予算が少ないため承認を待つ
    return "continue"

遮断ロジックは、リトライ後ではなくリトライ前に残予算を見ます。毎回のリトライ前にコストを見積もり、予算超過なら止める。これで「空レスポンスを 1,500 回リトライして 1 日分の予算を燃やす」事故を避けられます。

安定した prefix に入れるコンテキストと、実行時変数として後ろに置くコンテキストは、同シリーズのコンテキストエンジニアリング記事で扱います。

モデルルーティング戦略:すべてのタスクに最も高いモデルは要らない

ticket triage Agent の実際の分布を考えると、70% は単純分類、20% は返信下書き、顧客向けメールを送る前に frontier モデルへ上げるべきものは 10% 程度です。ルーティング戦略によって、コストを 40〜85% 抑えられる場合があります。

モデル層ルーティング

モデル層ルーティングは、タスクの複雑さで分けます。

タスク層典型タスク推奨モデル層割合コスト特性
70% - S 級分類、抽出、フィルタリング、簡単な Q&Anano/flash(最も安い)70%出力が短く、ターン数とツール呼び出しが少ない
20% - M 級下書き、要約、コード生成、中程度の推論mid-tier(中価格帯)20%出力は中程度で、ツールを呼ぶ場合がある
10% - L 級レビュー、アーキテクチャ設計、複雑な推論、複数ツールの調整frontier(最も高い)10%出力が長く、ターン数とツール呼び出しが多い

ルーティング戦略は 3 ステップです。

第 1 歩:タスクを分類する。 各 workflow に S/M/L の複雑さ基準を定義します。出力長、ツール呼び出し回数、推論の深さ、リスクレベルを含めます。

第 2 歩:デフォルトは S 級にする。 複雑な特徴に該当したときだけ、M または L に昇格します。

第 3 歩:段階的に昇格する。 S 級モデルが失敗したら M 級へ、M 級が失敗したら L 級へ上げます。L 級でも失敗したら人間の介入に回します。昇格前に残予算を確認し、予算超過なら昇格をスキップします。

サービス層ルーティング

同じモデルでも latency priority によって分流できます。割引率と完了時間は変わりやすいため、公開前に公式価格を再確認します。

サービス層コスト割引完了時間適した場面
リアルタイム API割引なし即時応答対話型 Agent、高優先度タスク
Batch API50% cost discount(公開前に再確認)24-hour turnaround(公開前に再確認)バッチ eval、分類、embedding、コンテンツリポジトリ処理
Flex Processing低コスト(公開前に再確認)応答は遅めで、まれに利用不可低優先度の非同期タスク、model evaluations、data enrichment

オフラインタスクのルーティング判断リストです。

  • 即時応答が必要ですか?はい -> リアルタイム API。モデルルーティングを使います。
  • 24 時間の遅延を許容できますか?はい -> Batch API。
  • 低優先度で、まれな失敗を許容できますか?はい -> Flex Processing。
  • eval、分類、embedding のようなバッチ処理ですか?はい -> Batch API。

リスク分級

タスクはリスクレベルでも分け、ルーティング経路を変えます。

リスクレベル典型操作ルーティング戦略予算分岐
低リスク分類、抽出、内部要約S 級モデル + 自動経路承認なし、予算上限は緩め
中リスク顧客返信の下書き、コード変更の提案M 級モデル + 任意承認予算超過時に承認へ回せる
高リスク顧客メール送信、課金、アーキテクチャ変更L 級モデル + 必須承認承認待ち、拒否、タイムアウトが予算分岐になる

承認待ち、拒否、タイムアウトが予算分岐にどう影響するかは、同シリーズの Human-in-the-Loop 記事で扱います。

重要な制約

ルーティング戦略には、次の制約が必要です。

  • 価格数字をハードコードしない:価格は変わりやすい事実です。コスト式を業務ロジックに固定せず、model + pricingVersion を記録します。
  • 残予算を確認する:昇格前に budgetRemaining を確認します。予算超過なら、昇格をスキップするか承認へ回します。
  • エラーを分類する:ルーティング失敗は、復旧可能なモデル能力不足と、復旧不能なパラメータエラーや権限拒否を分けます。

ツール呼び出し予算:per-tool budget、timeout、リトライ上限

ツール呼び出しには schema と API の二重コストがあります。各呼び出しでは schema、引数、応答解析のコンテキストを送ります。さらに外部 API のレート制限やタイムアウトもあります。これらのコストはモデル呼び出しとは別です。

ツール予算の制御

各ツールに独立した予算制御を設定します。

制御項目設定の目安監視フィールド発動する動作
Per-tool budget1 回の呼び出し上限tool_cost_estimate上限超過でツールをスキップ、または降格処理
Tool timeout外部 API のタイムアウトtool_durationタイムアウトをリトライ可能エラーとして記録
Retry limit per tool単一ツールのリトライ上限tool_retry_count上限超過でツールを諦め、リトライループに入らない

検索、データベース、外部サービスなどの外部 API ツールは個別に記帳します。そうしないと、ツール呼び出しがコストのブラックボックスになります。

ツール失敗の分類

ツール失敗は、復旧可能と復旧不能の 2 種類に分けます。

失敗タイプ典型エラー処理戦略コスト影響
復旧可能な失敗ネットワークタイムアウト、503 Service Unavailable、429 Rate Limit指数バックオフと retry-after で自動リトライ各リトライで完全なコンテキストを消費
復旧不能な失敗403 Permission Denied、400 Bad Request、ツール不存在リトライせず、エラーを注入してモデルに判断させるリトライせず、無効な消費を避ける

失敗分類の中心は、「外部要因による一時的な失敗だけをリトライし、内部設定ミスはリトライしない」ことです。

サーキットブレーカー

連続失敗 N 回でツールを停止し、「空レスポンスを 1,500 回リトライ」を防ぎます。

def circuit_breaker_tool(tool_name, consecutive_failures, threshold=5):
    if consecutive_failures >= threshold:
        return "disable_tool"  # ツールを停止
    return "continue"

サーキットブレーカーの状態はログに書きます。「なぜツールが停止されたのか」を後で追えるようにするためです。遮断後は人間の介入、または自動復旧チェックを待ち、不安定なツールを繰り返し呼びません。

ツール呼び出しの基本はツール呼び出しで扱っています。この記事では、per-tool budget、timeout、リトライ上限を拡張します。

Prompt Caching 設計:安定 prefix、変数の位置、1024 token 閾値

Prompt Caching は、安定した prompt prefix の入力 token を最適化する仕組みです。業務結果キャッシュではありません。同じ prompt prefix を最近処理したサーバーへルーティングし、レイテンシと入力 token コストを下げます。

Prompt Caching は結果キャッシュではない

Prompt Caching がキャッシュするのは安定した prompt prefix であり、業務結果ではありません。違いは重要です。

  • Prompt Caching:system prompt や tool schema など、安定した prompt prefix をキャッシュします。ヒットすると入力 token を節約できますが、推論自体は再実行されます。
  • 業務結果キャッシュ:ツール呼び出し結果やデータベースクエリなど、完全な出力をキャッシュします。ヒット時は直接返し、モデルを呼びません。

目的が違います。Prompt Caching は入力 token コストを最適化します。業務結果キャッシュは呼び出し全体のコストを最適化します。両方を使えます。安定した前置きは Prompt Caching に、高頻度のツール結果は業務キャッシュに載せます。

構造上の要件

Prompt Caching の鍵は、安定した前置きと実行時変数を分けることです。

内容タイプ位置キャッシュヒットの可能性典型例
安定 prefix(cache に入る)Prompt 前部高いSystem prompt、Tool schema、Policy 文書、Few-shot 例
実行時変数(cache に入れない)Prompt 後部低いUser input、File fragments、Runtime state(現在の会話ターン、一時変数)

設計ステップです。

  1. System prompt、Tool schema、Policy を前部に置く:これらは複数回の呼び出しで安定しているため、キャッシュに当たりやすくなります。
  2. User input、File fragments、Runtime state を後部に置く:これらは毎回変わるため、安定 prefix に含めるべきではありません。
  3. Cache hit rate を監視する:cachedTokens と総入力 token を記録し、ヒット率を計算します。Cache hit rate が 40% 超なら健全、20% 未満なら prefix 構造を見直します。

閾値と効果

Prompt Caching の自動有効化閾値と効果は変わりやすい事実です。公開前に公式ドキュメントで再確認します。

  • 閾値:1024 tokens 以上で自動有効化(公開前に再確認)。
  • 効果:ヒット時にコストとレイテンシを下げられる(具体的な比率は再確認)。
  • ヒット確認:usage.prompt_tokens_details.cached_tokens フィールド。

Prompt Caching の対応モデル、閾値、割引率は変わります。公開前に公式 pricing ページで確認してください。安定している設計原則は「静的内容を前に、変動内容を後ろに置く」ことです。

失敗リトライ遮断:冪等性、状態保存、残予算チェック

リトライはコスト暴走の最大要因になりやすい部分です。バックグラウンドの report Agent が不安定なツールで止まり、各失敗で完全なコンテキストを送り直すと、1,500 回のリトライ後には通常経路から大きく外れたコストになります。

リトライ前に予算を確認する

リトライ後ではなく、リトライ前に残予算を確認します。

def should_retry(error_type, budget_remaining, retry_cost_estimate):
    # エラー分類
    if error_type in ["403", "400", "tool_not_exist"]:
        return False  # 復旧不能エラー。リトライしない

    # 予算チェック
    if budget_remaining < retry_cost_estimate:
        return False  # 予算超過。リトライしない

    return True  # リトライ可能

予算チェックはリトライロジックの前に置きます。これで「空レスポンスを 1,500 回リトライして 1 日分の予算を燃やす」ことを避けられます。

冪等性

リトライで、メール送信や課金のような副作用を重複実行してはいけません。

  • ツール呼び出しには requestId などの冪等 ID を使います。外部 API が同じ ID を受け取ったら、処理を繰り返さずキャッシュ済み結果を返すようにします。
  • 冪等 ID はコストログに書き、重複呼び出しを判断できるようにします。

冪等設計の中心は「同じ操作で二重に消費しない」ことです。これがないと、リトライがコストと副作用の両方を増幅します。

状態保存(Checkpoint)

長時間タスクは、失敗しても全体を再実行しない形で復旧します。

  • Agent が重要なノードに到達したら、checkpoint を保存します。完了済みステップ、現在状態、コンテキスト要約を含めます。
  • 失敗復旧時は最初からではなく checkpoint から続行します。
  • Checkpoint は永続化ストレージに書きます。メモリ内だけに置かないでください。

checkpoint と thread state の設計は、LangGraph Agent アーキテクチャで扱っています。

リトライ戦略

エラー種別ごとに、リトライ戦略を変えます。

エラー種別典型エラーリトライ戦略コスト影響
ネットワークタイムアウト10 秒応答なし指数バックオフ + retry-after、最大 3 回各リトライで完全なコンテキストを消費
503/429Service Unavailable、Rate Limitレート制限ウィンドウ + retry-after を待ち、最大 3 回待機時間は token を消費しないが、リトライは消費する
403/400Permission Denied、Bad Requestリトライせず、エラーを注入してモデルに判断させるリトライせず、無効な消費を避ける

リトライ戦略の中心は「復旧可能なエラーだけをリトライする」ことです。無効なリクエストを何度もモデルに投げ直してはいけません。

サーキットブレーカー

連続失敗 N 回でリトライを止め、人間の介入を待ちます。

def circuit_breaker(consecutive_failures, threshold=5):
    if consecutive_failures >= threshold:
        return "stop_retry"  # リトライを停止
    return "continue"

サーキットブレーカーの判断はログに書きます。「なぜリトライを止めたのか」を後で説明できるようにするためです。遮断後は、人間の介入または予算回復を待ち、不安定なツールやモデルを繰り返し呼びません。

コストログとアラート:記録するフィールドと閾値

コスト可観測性は、コスト管理の前提です。ログ項目が不足していると、問題の場所を特定できません。

OpenTelemetry trace span attributes

コストログは 3 層の span で設計します。

Agent run span(最上位):

フィールド名用途型記録する理由
runId個別実行を特定string同じ workflow の複数実行を区別する
tenantIdtenant を特定stringマルチテナントでコストを按分する
userIdユーザーを特定stringユーザーごとのコスト傾向を見る
workflowNameworkflow を特定stringworkflow 種別ごとにコストを見る
totalCost総コスト見積もりfloatリアルタイムのコスト累積に使う
budgetRemaining残予算floatサーキットブレーカーの判断根拠
totalRetries総リトライ回数integerリトライ増幅を把握する

Model call span(子 span):

フィールド名用途型記録する理由
modelモデルを特定stringモデルルーティングが妥当か判断する
pricingVersion価格バージョンstringコスト式をハードコードしないため
inputTokens入力 token 数integer入力コストを計算する
outputTokens出力 token 数integer出力コストを独立して記録する
cachedTokensキャッシュ hit token 数integerキャッシュ節約を計算する
costEstimate今回のコスト見積もりfloatリアルタイムのコスト累積に使う
latencyMs呼び出しレイテンシintegerBatch/Flex に回せるか判断する

Tool call span(子 span):

フィールド名用途型記録する理由
toolNameツールを特定stringツール呼び出しの overhead を特定する
toolBudgetツール予算上限floatサーキットブレーカーの判断根拠
toolTimeoutツールタイムアウトintegerタイムアウト失敗を分類する
retryCountリトライ回数integerリトライ増幅を把握する
errorTypeエラー種別string復旧可能か復旧不能かを分ける

total_cost だけを記録してはいけません。軸ごとに分解します。これらのフィールドがないと、請求異常を見ても「超過した」ことしか分からず、どのユーザー、どのツール、どのリトライが原因か分かりません。

ログ、アラート、失敗復旧の全体設計はAgent 監視と復旧で扱っています。この記事では、コストフィールドと予算オブジェクトを補います。

アラート閾値

アラート閾値は軸ごとに設定します。

アラート軸アラート閾値アラート方法発動する動作
全体予算消費70%、90%、100%Slack/メール通知70% で通知、90% で降格、100% で遮断
単一 user/tenant の消費平均の 3 倍超Slack/メール通知異常呼び出しの有無を確認
単一モデルの失敗率> 5%Dashboard アラートモデルルーティングまたはサービス状態を確認
単一ツールのリトライ回数> 閾値Dashboard アラートツール安定性を確認
キャッシュヒット率< 期待値Dashboard アラートprompt 構造の誤りを確認

アラート閾値はコストログに書き、自動アラートとサーキットブレーカーの発動に使います。

降格戦略

アラート発動後の降格経路です。

降格経路降格方法適した場面コスト影響
モデル降格大きいモデル -> 小さいモデル単一モデルの失敗率が高いコストは下がるが、品質が下がる可能性
経路降格リアルタイム API -> Batch API -> Flex Processing全体予算の消費が速すぎるレイテンシは増え、コストは下がる
機能降格非コアのツール呼び出しを停止単一ツールのリトライ回数が多いツール呼び出し overhead を減らす
ユーザー降格レート制限、キュー投入、「後で再試行」案内単一ユーザーの消費が異常1 人のユーザーが予算を燃やすのを防ぐ

降格戦略は予算ロジックの中に書きます。アラート発動時に自動で降格し、人間が気づいてから対応する形にしないためです。

次に見るもの

Agent のコスト管理は単独では成り立ちません。監視、ツール呼び出し、コンテキストエンジニアリングと合わせて考えます。

  • 公開済み:Agent 監視と復旧:ログ項目、アラート設定、失敗復旧。この記事ではコストフィールドと予算オブジェクトを補います。
  • 公開済み:LangGraph Agent アーキテクチャ:checkpoint、thread state、失敗復旧。長時間タスクの状態保存に使います。
  • 公開済み:ツール呼び出し:ツール呼び出しの基本。この記事では per-tool budget、timeout、リトライ上限を拡張します。
  • 同シリーズ:コンテキストエンジニアリング:安定 prefix とキャッシュヒット。どのコンテキストを安定 prefix に入れ、どれを実行時変数にするか。
  • 同シリーズ:Human-in-the-Loop:承認待ち、拒否、タイムアウトの予算分岐。承認がコストとリトライ経路にどう影響するか。

まずは Session 単位の防線から始めます。per-session cost limit を設定し、単一セッションが予算を超えたら自動で終了します。暴走した 1 タスクが 1 日分の予算を燃やすのを止める、最も早く効く一手です。その後、予算オブジェクトの階層化、モデルルーティング、ツール呼び出し予算、Prompt Caching、リトライ遮断、コストログへ広げていきます。

Agent のコスト予算とサーキットブレーカーを設計する

予算オブジェクト、モデルルーティング、サービス層ルーティング、キャッシュ、ツール予算、リトライ制御を使い、Agent のコスト管理を各 run の実行前に前倒しします。

⏱️ 目安時間: 45 分

  1. 1

    ステップ 1: すべてのコスト経路を洗い出す

    Agent のモデル呼び出し、ツール呼び出し、ファイル読み取り、外部 API、バッチ処理、キャッシュ、リトライ経路を列挙します。
  2. 2

    ステップ 2: 予算オブジェクトを定義する

    tenant、user、run、workflow、model、tool、retry、cache、time window の軸で予算オブジェクトを記録します。
  3. 3

    ステップ 3: ルーティング戦略を設定する

    タスク種別ごとにモデル層ルーティングとサービス層ルーティングを設定し、online、batch、flex、queue を分けます。
  4. 4

    ステップ 4: キャッシュヒットを設計する

    安定したコンテキストを prompt prefix に置き、変動する内容を後ろに置きます。同時に prompt caching、業務結果キャッシュ、ツール応答キャッシュを区別します。
  5. 5

    ステップ 5: ツールとリトライを制限する

    各ツールに timeout、max retries、idempotency key、per-tool budget、fallback を設定します。
  6. 6

    ステップ 6: コスト span を記録する

    run/span に token、cached token、tool、retry、latency、estimated cost、budget remaining、traceId を記録します。
  7. 7

    ステップ 7: 降格と遮断を設定する

    降格、停止、サーキットブレーカー、アラート閾値を設定し、実際の失敗ケースで回帰テストします。

FAQ

Agent のコストはユーザー、セッション、タスク、ツールのどの単位で集計すべきですか?
user、tenant、workflow、task、tool、retry、cache の 7 層で集計します。各層に独立した予算とサーキットブレーカーを持たせます。total_cost だけでは、請求異常の原因になったユーザー、ツール、リトライ経路を特定できません。
モデルルーティングは、簡単なタスクを小さいモデルに替えるだけで十分ですか?
十分ではありません。モデル層ルーティングに加えて、Batch/Flex/リアルタイムのサービス層ルーティングとリスク分級が必要です。同じモデルでも latency priority で分岐できます。オフライン処理は Batch API、低優先度の処理は Flex Processing に回せます。
Prompt Caching と通常の業務キャッシュは何が違いますか?
Prompt Caching は system prompt、tool schema、policy などの安定した prompt prefix をキャッシュします。業務結果そのものではありません。業務結果キャッシュは完全な出力やツール応答を保存します。目的が違うため、併用できます。
ツール呼び出しが失敗したら何回リトライすべきですか?
固定回数だけで決めません。失敗分類、残予算、サーキットブレーカーを見ます。復旧可能なエラーだけ少数回リトライし、403、400、ツール不存在などの復旧不能エラーはリトライしません。
長時間タスクの途中で Agent の予算が尽きそうなときは、降格、停止、失敗のどれを選ぶべきですか?
まず pause して checkpoint を保存し、予算回復または人間の承認を待つのが堅実です。即失敗は進捗を失い、無理な降格は品質を落とします。多くの場合、停止がより安全な設計です。
コストログにはどの項目を記録すべきですか?
少なくとも runId、tenantId、workflow、model、input/output/cached tokens、toolName、retryCount、latency、costEstimate、budgetRemaining、decision、traceId を記録します。

10分で読めます · 公開日: 2026年9月17日 · 更新日: 2026年9月17日

コメント

GitHubアカウントでログインしてコメントできます

Easton BlogEaston Blog