APIチームは、フィールド名をcustomer_nameからcustomer_full_nameに変更しました。彼らはそれをアナウンスし、ドキュメントを更新し、人間が保守するすべてのクライアントはプルリクエストを受け取りました。しかし、あなた方のエージェントは何も受け取りませんでした。なぜなら、誰もそれをクライアントだと考えていなかったからです。エージェントは古いフィールドを送り続け、APIはリクエストを受け入れ、未知のキーを無視し続けました。そして2週間、エージェントが作成したすべてのレコードには名前が空のまま記録されていました。
エージェントは、APIコンシューマーの中で変更に最も気づきにくく、また変更をごまかしやすい存在です。人間のクライアントなら例外をスローしますが、エージェントは200を読み取り、呼び出しが成功したと判断して次に進みます。時には、成功したかのように問題をごまかして解決しようとすることもあります。
このガイドでは、エージェントがAPIドリフトに異常に脆弱である理由、通常のクライアントを壊さない変更がエージェントを壊すケース、バージョンを固定して検出する方法、そしてCIで実行前にドリフトを検出する方法について説明します。AIエージェントが本番環境で壊れる理由に関する我々の記事では、その故障モードについて取り上げていますが、この故障モードはあなたのコードベースの外部から発生するものです。
Apidogがここで重要になるのは、検出が仕様の問題だからです。API定義の以前のバージョンと現在のバージョンがあれば、差分は機械的に特定できます。
なぜエージェントはクライアントよりも変化に気づきにくいのか
以下の4つの特性が悪い組み合わせで作用します。
暗黙の許容。ほとんどのAPIは、リクエストボディ内の未知のフィールドを無視します。フィールド名が変更された場合、新しいフィールドは存在せず、古いフィールドは破棄され、200が返されます。何もエラーは発生しません。
即興的な対応。レスポンスに値が欠けている場合、モデルは停止する代わりに、もっともらしい代替値で処理を続行することがよくあります。これは会話においては役立つ振る舞いですが、APIに対しては危険な振る舞いです。
プロンプト内の説明。エージェントのツール説明は、APIに関する仮定をテキストでエンコードしています。APIが変更されると、その説明は微妙に誤ったものとなり、誤った説明は、コードが関与することなく間違った呼び出しを引き起こします。ツールスキーマの設計に関する我々の記事では、そのテキストにどれだけの振る舞いが依存しているかを説明しています。
コンパイラがない。型付きクライアントは、フィールドがなくなるとビルド時に破損します。エージェントの契約はJSONスキーマと散文に存在し、呼び出しが失敗するまで、あるいはさらに悪いことに、何も問題なく静かに機能しなくなるまで、誰もそれをチェックしません。
結論として、一般的なクライアントには安全な変更であっても、エージェントには必ずしも安全ではないため、それらを個別に分類する必要があります。
実際にエージェントを壊す変更
通常の追加的変更と破壊的変更の分類は依然として適用されますが、エージェントには中間的なカテゴリが加わります。
すべての人にとって真に破壊的。エンドポイントの削除、フィールドの削除、フィールド名の変更、型の変更、オプションパラメータを必須にすること、URLの変更。エージェントもここで破損しますが、より静かに破損します。
型付きクライアントには安全だが、エージェントには危険な変更:
- 新しい必須フィールド。既存のすべての呼び出し元が壊れますが、エージェントは検証エラーで壊れ、値を生成することで修正しようとすることがあります。これは、明確な失敗よりも悪い状況です。
- 新しいenum値。通常のクライアントは処理できないものを無視します。エージェントは、見慣れない値について推論し、あなたの製品が意図しなかった結論を導き出す可能性があります。
- 厳格化された検証ルール。以前は任意の文字列を受け入れていたフィールドが、今ではパターンを要求するようになりました。エージェントは失敗することなしにそのパターンを学習する方法がありません。そのため、ルールはエラーメッセージに含めるべきであり、これについてはAIエージェント向けAPIエラー設計に関する我々の記事で説明しています。
- 変更されたデフォルト値。ページネーションのデフォルトが100から20に減少し、
limitを送信しなかったエージェントは、データの5分の1しか見なくなり、それをすべてであるかのように報告します。 - ドキュメントの表現変更。動作自体は何も変更ありませんが、OpenAPI仕様をエージェントツールに変換するガイドのように、仕様からツールが生成されている場合、説明テキストが変更され、それに伴いツールの選択も変わる可能性があります。
エージェントにとっても安全な変更。オプションフィールドの追加、エンドポイントの追加、デフォルトが保持されたオプションパラメータの追加、検証の緩和。
この中間のリストが注意すべき点です。なぜなら、標準的な変更レビューではこれにフラグが立てられないからです。
バージョンは常に固定する
最初の防御策は、暗黙のうちに移動することを拒否することです。
APIが提供するメカニズム(パスセグメント、ヘッダー、アカウントレベルのピンなど)が何であれ、すべてのリクエストで明示的なバージョンを送信してください。GitHubのAPIバージョン管理ドキュメントでは日付ヘッダーを使用しており、Stripeは明示的なアップグレード手順とともにアカウントごとにバージョンを固定しています。どちらも同じ特性を提供します。つまり、あなたが決定するまで、あなたの下で何も変更されることはありません。
DEFAULT_HEADERS = {
"X-API-Version": "2026-06-01",
"User-Agent": "billing-agent/1.4 (+https://example.com/agents)",
}
User-Agentはバージョンピンと同じくらい価値があります。APIプロバイダーが呼び出し元に非推奨を警告する必要がある場合、トラフィックを調べます。自身を識別するエージェントはメールを受け取りますが、デフォルトのライブラリ文字列を送信するエージェントは受け取りません。
あなたがAPIを所有している場合は、バージョンを公開し、それを維持してください。最適なAPIバージョン管理戦略に関する我々のガイドでは、利用可能なオプションについて説明しており、ApidogでのAPIバージョン管理では、複数のバージョンを同時に稼働させる方法について説明しています。
バージョン管理が全くないサードパーティAPIの場合、できる範囲で固定してください。つまり、構築時に想定したレスポンスの形状を記録し、それをチェックするのです。これは次のセクションで説明します。
実行前にドリフトを検出する
バージョン固定は時間を稼ぎます。しかし、最終的なアップグレードを止めるものではなく、バージョン管理なしに変更されるAPIには何の役にも立ちません。だから、検出が必要です。
スケジュールに基づいて仕様を比較する。プロバイダーがOpenAPIドキュメントを公開している場合、毎日それをフェッチし、ツールを生成したコピーと比較してください。フィールドの削除、型の変更、要件の追加、enumの拡張、説明の編集などをチェックします。Apidogでは、インポートした定義をプロジェクト内に保持し、バージョン間で何が変更されたかを確認できます。これにより、「何か変更があったか」という疑問が調査ではなくレポートへと変わります。
呼び出すエンドポイントのコントラクトテストを行う。エージェントが持つ各ツールに対し、既知の正常なリクエストを送信し、レスポンスの形状をアサートします。必須フィールドの存在、正しい型、期待するセット内のenum値などを確認します。これは、仕様を全く公開しないAPI(ほとんどがこれに該当します)におけるドリフトを捕捉します。APIコントラクトテストに関する我々のガイドではこのパターンを説明しており、双方向コントラクトテストでは両側から実行する方法を説明しています。
実行時に形状をアサートする。ツールラッパー内でレスポンスを期待するスキーマに対して検証し、予期しないものが出現した場合は警告をログに記録します。これは最後の砦であり、誰もアナウンスしなかった変更を捕捉するものです。
def check_shape(tool_name, payload, expected):
missing = [f for f in expected["required"] if f not in payload]
extra = [f for f in payload if f not in expected["properties"]]
if missing:
log.error("api_drift", tool=tool_name, missing=missing)
raise ApiDriftError(f"{tool_name}: missing fields {missing}")
if extra:
log.warning("api_new_fields", tool=tool_name, fields=extra)
return payload
欠落があれば失敗させ、余分なものがあれば警告します。必須フィールドが欠落している場合、エージェントは不完全なデータで作業しようとしていることを意味し、これは停止して対処する価値のある失敗です。新しいフィールドは通常、追加的なものであり、実行を中断することなく知っておく価値があります。これら両方を、エージェントツール呼び出しのトレースに関する我々の記事で説明されているトレースレコードにルーティングします。
スキーマだけでなく、振る舞いも監視する。スキーマチェックでは見えないドリフトもあります。例えば、変更されたデフォルト値、厳しくなったレート制限、遅くなったレスポンスなどです。完了したタスクあたりの呼び出し数、エンドポイントあたりの再試行率、ツールあたりの平均レスポンスサイズを追跡してください。これらのいずれかに段階的な変化が見られる場合、通常はアップストリームで何かが変更されたことを意味します。
エージェントを壊さずにアップグレードする
新しいバージョンに移行する際は、それをエージェントへの変更として扱ってください。なぜなら、実際にその通りだからです。
ツールは手動で編集するのではなく、再生成してください。そうすることで、説明とスキーマが同期します。次に、生成されたツール定義の差分を読みます。その差分こそが本当の影響範囲であり、API変更ログが示唆するよりも小さいこともあれば大きいこともよくあります。
新しいバージョンを本番環境に適用する前に、そのモックに対してエージェントを実行してください。これは最も価値の高いステップであり、最も省略されがちなものです。新しい仕様から構築されたモックを使用すると、本番ではなくモックに対してエージェントを実行するという我々の記事に従い、リスクなしに新しい形状に対してタスクスイート全体を実行できます。
選択スイートを再実行してください。説明の変更は、モデルが選択するツールをずらす可能性があり、そのリグレッションはスキーマの差分では見えません。非決定性AIエージェントのテストに関する我々のガイドのように、固定されたプロンプトセットに対してツール選択をアサートしてください。
フラグの背後で、トラフィックの一部に対して、古いバージョンを固定したまま準備してロールアウトしてください。同じ4つの数字を1日監視します。エージェントのリグレッションは、誰かが苦情を申し立てるずっと前に、タスクあたりの呼び出し回数の増加や再試行回数の増加として現れます。
本番環境に到達した3つのドリフト
名前が変更されたフィールド。冒頭の話です。すべての呼び出しで200が返され、すべてのレコードで名前が空になっており、2週間後に人間がレポートを読んで発見されました。レスポンスに対する実行時形状チェックがあれば、エージェントが読み取ると期待していたフィールドがなくなっていたため、最初の呼び出しでそれを捕捉できたでしょう。
厳格化されたページネーションのデフォルト。プロバイダーがデフォルトのページサイズを100から20に減らしました。エージェントはlimitを送信していなかったため、20件のレコードしか見なくなり、それを完全なセットであるかのように要約し始めました。何もエラーは発生しませんでした。要約は、自信満々に読める形で、単に間違っていました。修正は明示的なlimitを送信する一行でしたが、教訓はより広範囲に及びます。デフォルトに依存すると、他者の決定に宣言されていない依存関係を持つことになります。
新しいenum値。支払いAPIにstatus: "disputed"が追加されました。型付きクライアントはそれを無視しました。エージェントはそれについて推論し、係争中の請求が払い戻しと見なされると判断し、実際にはそうでないにもかかわらず、帳簿が一致していると報告しました。明示的なenum検証があれば、モデルに解釈させる代わりに、見慣れない値に対してエラーを発生させていたでしょう。
パターン:各変更はアナウンスされ、それぞれプロバイダー自身の分類では追加的または軽微なものでしたが、エージェントにとっては破壊的なものでした。このギャップこそが、設計で考慮すべき点です。
非推奨化を作業項目として扱う
プロバイダーは通常、警告を発します。警告は変更ログ、メール、またはレスポンスのDeprecationヘッダーとして届きますが、これらがエージェントを保守する人に届かないことはよくあります。
それらを通常のキューに組み込んでください。DeprecationヘッダーとSunsetヘッダーは両方とも標準化されているため、一般的なチェックはプロバイダーを横断して機能します。それらが出現したときにログに記録し、千回目に検出されるのではなく、最初に発見されたときにアラートを発します。今日3%の呼び出しで表示されるヘッダーは、サンセット日には完全な障害となります。
また、インベントリも保持してください。どのエージェントが、どのプロバイダーの、どのバージョンの、どのエンドポイントを、誰が所有しているか。ファイルに10行程度の記述で十分です。非推奨通知が届いたとき、「これは私たちに影響するか」という質問は、grepに何時間もかけるのではなく、1分で答えられるべきです。
ドリフトは作業であるため、担当者を割り当てる
検出はキューを生成します。仕様の差分、失敗したコントラクトテスト、初めて見られた非推奨ヘッダーなどです。それぞれは期限付きの小さな作業であり、失敗モードは、サンセット日が来るまで誰も所有しないチャネルに放置されることです。
それらをチームがすでに作業を追跡している場所に置きます。エージェントがデプロイされたサービスとしてではなく、コーディングランタイムとして実行される場合、それらを管理するプラットフォームがループを閉じることができます。Sharklyはタスクをエージェントまたはクルーに割り当て、目標、実行トレース、レビューを1か所にまとめます。これにより、「支払いAPIがこのエンドポイントを非推奨にした」という事態は、スレッド内のメッセージではなく、結果を伴う割り当てられたタスクになります。何を使用するにしても、ルールは同じです。担当者のいないドリフトアラートは、それが壊れる日に再び直面することになる非推奨化です。

チェックリスト
- すべてのリクエストが明示的なAPIバージョンと識別可能な
User-Agentを送信していること。 - サードパーティの仕様ドキュメントがスケジュールに基づいて取得され、差分が比較されていること。
- エージェントが呼び出すことができるすべてのツールに、レスポンス形状をアサートするコントラクトテストがあること。
- ツールラッパーが実行時にレスポンスを検証していること:欠落がある場合は失敗させ、新しいものがある場合は警告を出すこと。
- エンドポイントごとに振る舞いのメトリクスが追跡され、暗黙のドリフトが表面化すること。
- バージョンアップグレードでは、手動で編集するのではなく、ツールを再生成すること。
- タスクスイートと選択スイートの両方が、まず新しいバージョンのモックに対して実行されること。
- ロールアウトがフラグで制御され、旧バージョンが固定されたままで元に戻せること。
APIチームは変更を継続的にリリースしますが、それは問題ありません。必要なのは、あなたのエージェントが変化に気づくクライアントであることであり、そのためにはバージョン固定、コントラクトテスト、および実行時の形状チェックが必要です。本番稼働前に仕様を比較し、次のバージョンをモックするためにApidogをダウンロードしてください。
よくある質問
サードパーティの仕様変更をどのくらいの頻度でチェックすべきですか?ほとんどの場合、毎日で十分であり、自動化も安価です。公開された仕様がないAPIの場合、CIで実行されるコントラクトテストに頼ってください。なぜなら、それらは外部から同じドリフトを検出するからです。
常に最も古い動作するバージョンに固定すべきですか?いいえ。アップグレードが意図的になるように固定し、その後スケジュールに従ってアップグレードしてください。古いバージョンが削除されるまでそれに固執することは、計画的な変更を緊急事態に変えてしまいます。
変更後もエージェントが正常に動作する場合はどうなりますか?仮定するのではなく、検証してください。危険な結果とは、名前が変更されたフィールドが静かに破棄された場合のように、引き続き200を返すものです。形状アサーションは、正常な実行では分からないことを教えてくれます。
エージェントのために自分のAPIのバージョン管理を異なる方法で行う必要がありますか?異なる方法ではありませんが、より厳密にです。新しい必須フィールド、新しいenum値、変更されたデフォルト値を、型付きクライアントにとっては追加的であっても、エージェントコンシューマーにとっては破壊的であるものとして扱い、同じ方法でアナウンスしてください。
どのエージェントがどのエンドポイントを呼び出しているかをどうやって知るのですか?トレースからわかります。実行ごとのツール名とエンドポイントによって依存関係マップが得られ、非推奨化によって誰が影響を受けるかを正確に教えてくれます。エージェントツール呼び出しのトレースに関する我々の記事では、レコードの形状について説明しています。
エージェントはAPIの変更に自律的に適応できますか?時には可能です。しかし、それに頼るべきではありません。欠落したフィールドに対して即興的に対応するモデルは、何かが間違っているというシグナルなしに、もっともらしい出力を生成します。大声で失敗させ、代わりにツールを修正してください。
