AIエージェントのコンテキストウィンドウ:APIレスポンスの最適化

肥大化したJSONレスポンスは、エージェントのコンテキストウィンドウとその予算を食い潰します。ツール結果を小さく保つための、フィールド選択、厳密なリスト上限設定、ツールレイヤープロジェクション、サーバーサイドサマリーについて習得しましょう。

Ashley Innocent

Ashley Innocent

26 8月 2026

AIエージェントのコンテキストウィンドウ:APIレスポンスの最適化

Apidog エンタープライズ

オンプレミスデプロイ

SSO & RBAC

SOC 2 準拠

Apidog Enterpriseを見る

エージェントは顧客レコードを要求します。あなたのAPIは、顧客、その最新200件の注文、それらの注文のすべての明細項目、3つの形式のタイムスタンプ、そしてそれぞれの`_links`ブロックを返します。4万トークンがコンテキストウィンドウに投入されます。エージェントが必要としていたのはメールアドレスでした。 これを1回の実行で4回行うと、エージェントは要求していないJSONの読み込みに予算のほとんどを費やしてしまいます。その後、興味深い失敗が始まります。元の指示を忘れてしまったり、タスクを完了する代わりに要約してしまったり、実行あたりのコストが上昇し、品質が低下します。 これはプロンプトの問題ではなく、APIレイヤーにおける設計上の問題です。エージェントは固定のウィンドウを通して応答を消費し、あなたが返すすべてのフィールドは、指示、会話、および計画と競合します。このガイドでは、余分なデータがどこから来るのか、それを解決するフィールド選択とページネーションのパターン、APIを制御できない場合にツールレイヤー内でトリミングする方法、そしてその違いを測定する方法について説明します。「AIエージェントが本番環境で動作しなくなる理由」に関する当社の主要記事では、コンテキストの枯渇を主要な障害モードの1つとして扱っており、本稿はその実用的な側面を説明するものです。 Apidogは測定の側面をサポートします。エージェントがエンドポイントを呼び出す前に、各エンドポイントの実際の応答サイズを確認でき、APIチームが提供する前に、あなたが望むトリミングされた形をモックすることができます。 トークンがどこへ行くのか ブラウザやダッシュボード向けに設計されたレスポンスには、エージェントに実際のお金を費やさせる多くの「貨物」が含まれています。 冗長なエンベロープ。5つのフィールドを持つオブジェクトを`data`、`meta`、`links`、`included`でラップすると、ペイロードが2倍になることがあります。ハイパーメディアリンクは、それをフォローするクライアントには役立ちます。エージェントがそれを行うことはほとんどなく、すべてのURLがトークンになります。 キーの繰り返し。JSONは配列の各要素でフィールド名を繰り返します。各アイテムに15フィールドを持つ200アイテムのリストは、3,000個のキーストリング分のコストがかかります。これがリストエンドポイントがコンテキスト使用量を占める理由です。 デフォルトでのネストされた展開。関連リソースをインライン化するエンドポイントは、エージェントがそれにアクセスするまでは便利です。顧客1人、その注文、さらにその明細項目はツリーであり、ツリーは急速に成長します。 冗長なフォーマット。同じオブジェクトに`created_at`、`created_at_unix`、`created_at_human`がある場合、1つの値に対して3倍のコストがかかります。 Nullと空の値。多くのシリアライザは、設定されていない場合でもすべてのフィールドを出力します。レコードあたり20個の`null`は純粋な無駄です。 これを理解するのに役立つ方法:トークンコストはレコードの数ではなく、シリアライズされたテキストのサイズを追跡します。各レコードに5つのフィールドを持つ200レコードは、1つの深くネストされたオブジェクトよりも安価になる可能性があります。 ルール1:リソースではなくフィールドを返す 最も価値の高い変更は、呼び出し元が必要なものを要求できるようにすることです。 例えば、以下のようにリクエストを送信します。 GET /v1/customers/8812?fields=id,email,plan,status これにより、以下のようなJSONが返されます。 { "id": "8812", "email": "dana@example.com", "plan": "pro", "status": "active" } これはほとんどのAPIで完全なレコードと比較して90%の削減になり、追加するのに半日もかかりません。GoogleのAPI設計ガイドには、前例のあるバージョンが必要な場合にフィールドマスクパターンが記載されており、GraphQLは選択を必須にすることで同じ問題を解決しています。 実装に関する2つの注意点。フィールドリストをスキーマに対して検証し、不明な名前は拒否することで、幻覚で生成されたフィールドがサイレントに切り詰められたオブジェクトではなく、明確なエラーを生成するようにします。また、何も送信しない呼び出し元に対しては、すべてをデフォルトにするのではなく、小さなデフォルトセットを維持してください。 次に、ツール説明でパラメーターをモデルに公開し、フィールドを明記します。 { "name": "getCustomer", "description": "IDで顧客を取得します。常に必要なものだけを`fields`に渡してください。利用可能: id, email, name, plan, status, created_at, billing_address, order_count。", "input_schema": { "type": "object", "required": ["customerId", "fields"], "properties": { "customerId": { "type": "string" }, "fields": { "type": "array", "items": { "type": "string" }, "description": "返すフィールド名。このリストは最小限に保ってください。" } } } } これらのルールをモデルが学ぶ唯一の場所は説明文であり、OpenAIの関数呼び出しガイドもAnthropicのツール使用ドキュメントも、これらに同じ重みを置いています。`fields`を必須にすることがコツです。オプションのパラメーターはスキップされますが、必須のパラメーターはモデルに実際に何が必要かを考えさせます。 ルール2:常にリストに上限を設ける 無制限のリストエンドポイントは、爆発的な増大の2番目の大きな原因です。エージェントが「最近の注文」を要求すると、2019年以降のすべてが返されます。 デフォルトだけでなく、厳格なサーバーサイドの最大値を設定してください。エージェントが`limit=5000`を送信した場合でも、100件を返し、その旨を伝えます。「REST APIのページネーション」と「数百万レコードのページネーション設計」に関する当社のガイドではその仕組みを説明していますが、エージェント固有のルールはより限定的です。 * ページはモデルが読み取れる程度の量(一般的なレコードで20〜50アイテム)に制限する。 * 合計件数を返すことで、エージェントがページングせずにすべて見たかどうかを判断できるようにする。 * カーソルページネーションを使用する。実行中にデータが変更されるとオフセットがずれる可能性があり、ゆっくりページングするエージェントはそれに遭遇します。 * 応答に`"truncated": true`のような簡単なステートメントを含め、モデルがまだ続きがあることを知るようにする。モデルは配列の長さだけでは完了度を誤って判断しがちです。 また、エージェントにページングを完全に回避する方法も提供してください。`count`エンドポイント、範囲を絞ったフィルタリング検索、またはサマリーオブジェクトは、レコードを返さずに質問に答えることがよくあります。最も安価な応答は、データを含まないものです。 ルール3:APIがあなたの管理下ではない場合、ツールレイヤーでトリミングする サードパーティのAPIは、あなたが要求したからといってフィールド選択を追加することはありません。その代わりに、HTTP応答とモデルの間にある実行レイヤーでトリミングを行ってください。 以下はその例です。 KEEP = { "getCustomer": ["id", "email", "plan", "status"], "listOrders": ["id", "total", "status", "created_at"], } def project(tool_name, payload): keep = KEEP.get(tool_name) if keep is None: return payload if isinstance(payload, list): return [{k: item.get(k) for k in keep if k in item} for item in payload] return {k: payload.get(k) for k in keep if k in payload} 3つの改良点により、これが実際に機能します。 * 完全な応答を保存し、モデルには投影されたものを渡す。トリミングされていないペイロードは実行ログに残し、デバッグを可能にする。「エージェントツール呼び出しのトレース」に関する当社の記事では、何を記録すべきかを説明しています。 * 削除したものをモデルに伝える。`"_omitted": ["billing_address", "notes", "metadata"]`のような行は、モデルがデータが存在しないと結論付ける代わりに、本当に必要な場合に完全なレコードを要求できるようにします。 * リストをコンパクトな形式に変換する。表形式の結果の場合、CSVやMarkdownテーブルは、フィールド名が各行ごとではなく一度だけ表示されるため、JSONよりもはるかに少ないトークンで済みます。モデルはどちらも問題なく読み取ることができます。 CSVの例: id,total,status,created_at ord_91,4900,paid,2026-08-21 ord_92,1200,refunded,2026-08-22 ルール4:重いケースではサーバー側で要約する 一部の質問は、そもそもレコードを必要としません。「この顧客は今月、支払いに失敗しましたか?」という質問はブーリアン値で答えられます。モデルがそれを解決できるように40の支払いオブジェクトを返すのは、高価な回答方法です。 繰り返し発生する質問に対しては、それに直接答えるエンドポイントを追加してください。アカウントヘルスサマリー、ステータスロールアップ、小規模な集計などです。これは通常のAPI設計作業のように見えますが、その通りであり、上記のすべての中で最も価値のあるバージョンです。つまり、大きな応答をトリミングする代わりに、それを生成しないようにするのです。 2つのガードレール。サマリーの形式を安定させ、エージェントがそれに依存できるようにしてください。また、バージョン管理も行います。なぜなら、エージェントのプロンプトは特定の形式に基づいて書かれており、サイレントな変更はそれを壊すからです。「エージェントの背後でAPIが変更された場合に何が起こるか」に関する当社の記事では、そのリスクについて説明しており、「最高のAPIバージョン管理戦略」ではその仕組みについて説明しています。 変更前後の測定 これらすべてを闇雲に行う価値はありません。3つの数値が問題の所在を教えてくれます。 * エンドポイントごとの応答バイト数。エージェントが呼び出す可能性のある各ツールに現実的なリクエストを送信し、ペイロードサイズを記録します。数キロバイトを超えるものは候補となります。Apidogでは、各エンドポイントを一度実行して応答から直接サイズを読み取り、リクエストを保存してAPIが変更されたときにチェックを繰り返すことができます。 (画像: Apidogの画面キャプチャで、HTTP応答のサイズが表示されている) * ツール呼び出しごとのトークン数。バイトは代理に過ぎません。トークンが実際の請求額です。ペイロードをプロバイダーのトークナイザー(OpenAIモデルの場合はtiktokenなど)に通し、エンドポイントのランキングを付けます。ランキングは通常偏っており、1つか2つのエンドポイントがコストの大部分を占めています。 * 実行ごとのコンテキスト使用量。エージェントタスク全体で実行中の合計を記録します。タスクが制限の近くで終了する場合、トリミングは単に安価な実行だけでなく、完了した実行をもたらします。 次に、望む形を設計し、APIチームがそれを構築する前にモックアップします。トリミングされた応答を返すモックサーバーを使用すると、改善を測定し、エージェントが少ないデータでも成功するかどうかを確認できます。これが実際に重要な問題です。「本番環境ではなくモックに対してエージェントを実行する」に関する当社の記事では、そのワークフローについて説明しています。 望ましい状態とは エージェントにとって好ましい応答は、小さく、フラットで、省略した内容について正直です。 例: { "customer": { "id": "8812", "email": "dana@example.com", "plan": "pro" }, "recent_orders": [ { "id": "ord_91", "total_cents": 4900, "status": "paid" }, { "id": "ord_92", "total_cents": 1200, "status": "refunded" } ], "recent_orders_total": 47, "truncated": true, "_omitted": ["billing_address", "metadata", "order_line_items"] } 200トークン未満。一般的な質問に答え、2件の注文があることを示唆するのではなく、47件の注文があることを伝え、モデルに次に何を要求できるかを伝えます。 最も負荷の高いエンドポイントから始めましょう。それを測定し、フィールド選択を追加し、リストに上限を設け、エージェントを再度実行します。この2つの数値間のギャップは、残りの作業を正当化するのに通常十分な大きさです。測定とモックを同じプロジェクトで行いたい場合は、Apidogをダウンロードしてください。 これが役立つ3つの場面 **サポートのトリアージ。** エージェントがチケットを読み込み、顧客情報を取得し、エスカレーションすべきかどうかを判断します。素朴なバージョンでは、実際の苦情を読む前に、完全な顧客オブジェクトと最新の50件のチケットを取得し、30,000トークンを消費します。修正版では、プラン、ステータス、未解決チケット数、最終連絡日を返すサマリーエンドポイントを呼び出します。これにより約80トークンとなり、関連する事実が埋もれないため、エスカレーションの判断が向上します。 **社内運用エージェント。** デプロイエージェントが40のサービス全体の健全性をチェックします。完全なステータスオブジェクトは、12番目のサービスでウィンドウを使い果たします。サービスごとに1行(名前、状態、エラーレート)を返すロールアップを使用すると、数百トークンで40すべてのサービスを収容でき、エージェントが前半を忘れることなくフリート全体を推論できます。 **データ入力と照合。** エージェントが請求書と支払いを照合します。完全な請求書ドキュメントを返すと、数十件を超えるレコードで失敗します。`id`、`amount_cents`、`date`、`reference`をCSV形式で返すと、比較では常に4つのフィールドしか使用しないため、一度に数百件を処理できます。 これら3つのすべてに共通するパターン:エージェントは意思決定の表面を必要としていたのに、APIは文書を与えていたのです。 パターンを把握するには実行履歴が必要です 1回の実行では、応答が大きかったことしかわかりません。どのエンドポイントが予算を使い果たし、どのくらいの頻度で発生するかというパターンは、複数の実行を通してのみ明らかになります。 つまり、数値はセッションを越えて保持される必要があります。デプロイしたサービスの場合、それは独自のテレメトリーです。割り当てられた作業を実行するコーディングエージェントの場合、それはそれらを実行するプラットフォームです。Sharklyは各実行の実行トレースと結果を、それが由来するタスクに保持するため、実行ごとの比較はターミナルセッションを再構築するのではなく、タスク履歴を読むことですみます。いずれにしても、履歴のない予算強制は、何かが大きすぎることは教えてくれますが、最初に何を修正すべきかは教えてくれません。 (画像: エージェントの実行履歴の画面キャプチャ) 実行ごとだけでなく、ツールごとに予算を設定する ほとんどのチームは総コンテキストに上限を設けてそこで止まります。ツールごとの予算の方が有用です。なぜなら、それは漠然とした問題を具体的な問題に変えるからです。 各ツールに上限(例えば1,500トークン)を設定します。応答がそれを超えた場合、実行者は投影されたものにトリミングし、省略されたフィールドマーカーを追加し、オーバーフローをログに記録します。これにより、定期的に予算を超えるエンドポイントのリストが得られ、エージェントがそれらを呼び出す頻度でランク付けされるため、それがあなたの作業キューになります。 予算はまた、テストでは小さいが、ある実際の顧客にとっては巨大なエンドポイントからあなたを保護します。分布には裾野があり、4,000件の注文を持つアカウントが午前2時に実行を中断させるでしょう。厳格な上限は、それを失敗したタスクではなく、トリミングされた応答に変えます。 よくある質問 **エージェントが欠落したデータを必要とする場合、応答の切り捨てはリスクがありますか?** 切り捨てを隠した場合にのみリスクがあります。明示的なマーカーと省略されたフィールドのリストを含めることで、モデルがそれらを要求できるようにします。サイレントな切り捨てこそが誤った回答を引き起こす原因であり、トリミング自体ではありません。 **代わりにエージェントにGraphQLを使用すべきですか?** GraphQLはフィールド選択を必須にするため、これをきれいに解決しますが、クエリ構築に複雑さを移動させ、モデルはフィールドリストを誤用するよりも無効なクエリを作成する頻度が高くなります。RESTエンドポイントに`fields`を追加する方が、通常はより小さな変更です。 **ツール応答はどのくらい小さくすべきですか?** 単一レコードの読み取りでは1,000トークン未満、リストでは2,000トークン未満を目指しましょう。それ以上の場合、エージェントがレコードを必要としているのか、それとも単なる回答を必要としているのかを問い直してください。 **プロンプトキャッシュはこの問題を解決しますか?** これは繰り返されるコンテキストのコストを削減しますが、それが占めるスペースを削減するわけではありません。キャッシュされた40,000トークンの応答は依然としてウィンドウを埋め尽くすため、キャッシュは請求額には役立ちますが、信頼性の問題は手つかずのままです。 **バイナリおよびファイル応答についてはどうですか?** それらをコンテキストに含めてはなりません。ファイルを保存し、エージェントに参照と短い説明を渡し、必要なものだけを抽出するための別のツールを与えてください。 **トリミングはどこで行うべきですか、API内ですか、それともツールラッパー内ですか?** あなたがAPIを所有している場合はAPI内です。なぜなら、すべての呼び出し元が恩恵を受け、バイトがネットワークを越えることがないからです。所有していない場合はラッパー内です。両方行うのも問題ありません。

ApidogでAPIデザイン中心のアプローチを取る

APIの開発と利用をよりシンプルなことにする方法を発見できる