ほとんどのエージェントのコードベースには、誰も保守したがらないファイルが含まれています。それは40のツール定義を保持しており、それぞれが手書きのJSONスキーマで、すでにどこかにスキーマがあるエンドポイントを記述しています。APIチームが新しい必須フィールドを出荷し、仕様が更新され、ドキュメントが更新されても、誰かが400エラーに気づくまでエージェントは古いペイロードを送信し続けます。
すべてのエンドポイントには、すでに機械可読な記述があります。それがOpenAPIドキュメントです。そのドキュメントを、モデルが呼び出せるツール定義に変換し、記憶に頼るのではなく自動的に同期を保つことが仕事です。
このガイドでは、OpenAPIの操作がツールスキーマにどのようにマッピングされるか、ジェネレーターが途中で修正する必要があること、200エンドポイントの仕様をモデルが理解できるものにトリミングする方法、および生成されたツールの動作をテストする方法について説明します。スタックのより早い段階にいる場合は、エージェントがコードを書くときにAPIツールがまだ必要かどうかに関する私たちの投稿が、より広い文脈を設定しています。
Apidogがここで重要なのは、そこから生成されるものが正しく機能するためには、まず仕様が正しくなければならないからです。ツール定義は、それが由来するドキュメントのあらゆるギャップを受け継ぎます。
手書きのツール定義のコスト
手書きでツールを作成するのは、5つのエンドポイントであれば問題ないと感じるでしょう。しかし、およそ20を超えると、3つの理由で問題になり始めます。
定義が乖離する。仕様はコードから生成されるか、APIチームによって保守されます。ツールファイルは、エージェントを構築した人によって保守されます。両者をつなぐものは何もないため、静かに乖離していき、最初の症状はエージェントが「突然」動作しなくなったことです。
記述が薄くなる。人が40のスキーマを手書きすると、最後の20は1行の説明になります。モデルはそれらの説明を読んでツールを選択するため、薄いテキストはツールの選択精度を直接低下させます。エージェント向けツールスキーマの設計に関する私たちの投稿では、言葉の重みがなぜそれほど大きいのかについて詳しく説明しています。
エラーが実行時まで見えない。APIが整数を要求するのに、手書きのスキーマがフィールドが文字列であると述べている場合、エージェントがそれを最初に試行したとき、本番環境で、実際のタスクで422が発生します。
仕様から生成することで、これら3つの問題すべてが一度に解決されます。信頼できる情報源は1つであり、説明はドキュメントで使用されているのと同じテキストから得られ、型はサーバーが検証するのと同じスキーマから得られます。
OpenAPI操作がツールになる方法
マッピングは見た目よりも直接的です。単一の操作を見てみましょう。
paths:
/orders/{orderId}/refund:
post:
operationId: refundOrder
summary: Refund an order
description: >
Issues a full or partial refund against a completed order.
Refunds are irreversible. Partial refunds require an amount
no greater than the remaining refundable balance.
parameters:
- name: orderId
in: path
required: true
schema: { type: string }
description: The order to refund.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [reason]
properties:
amount:
type: integer
description: Amount in cents. Omit for a full refund.
reason:
type: string
enum: [duplicate, fraudulent, requested_by_customer]
そこから生成されるツール定義は次のとおりです。
{
"name": "refundOrder",
"description": "完了した注文に対して全額または一部の払い戻しを行います。払い戻しは取り消しできません。一部の払い戻しには、残りの払い戻し可能な残高を超えない金額が必要です。",
"input_schema": {
"type": "object",
"required": ["orderId", "reason"],
"properties": {
"orderId": { "type": "string", "description": "払い戻しを行う注文。" },
"amount": { "type": "integer", "description": "セント単位の金額。全額払い戻しの場合は省略します。" },
"reason": { "type": "string", "enum": ["duplicate", "fraudulent", "requested_by_customer"] }
}
}
}
4つのルールがほとんどの作業を行います。
operationIdがツール名になります。操作にoperationIdがない場合は、メソッドとパスから安定したものを生成し、それを仕様に追加します。- パス、クエリ、ボディのパラメータは1つのプロパティオブジェクトにフラット化されます。モデルは値がどこを通過するかを気にしません。あなたのエクゼキューターは気にしますので、どのパラメータがどこに行くかを記録するサイドテーブルを保持してください。
summaryとdescriptionが結合されてツール記述になります。両方を結合します。サマリーだけでは、選択を導くには通常簡潔すぎます。- 必須配列は結合されます。必須のパスパラメータと必須のボディフィールドの両方が、同じ
requiredリストに含まれます。
エクゼキューターはもう一方の半分であり、それは小さいものです。
def execute(tool_name, args, spec_index, http):
op = spec_index[tool_name] # メソッド、パステンプレート、パラメータの場所
path = op.path
query, body = {}, {}
for name, value in args.items():
location = op.locations[name] # "path" | "query" | "header" | "body"
if location == "path":
path = path.replace("{" + name + "}", str(value))
elif location == "query":
query[name] = value
elif location == "body":
body[name] = value
return http.request(op.method, path, params=query, json=body or None)
これが橋渡し全体です。その他はすべて、途中のクリーンアップです。
ジェネレーターが修正すべきこと
仕様をツールスキーマに素朴にダンプすると、モデルがうまく扱えないツールが生成されます。5つの調整が重要です。
$refポインタを解決する。ほとんどのツール呼び出しAPIはJSON Schemaのサブセットを受け入れ、componentsセクションへの参照をたどりません。これらをインライン化してください。再帰的なスキーマに注意してください。インライン化すると無限に展開されてしまいます。固定された深さで再帰をカットし、より深い構造を散文で記述してください。
サポートされていないキーワードを削除する。oneOf、allOf、discriminator、およびnullableは仕様で一般的ですが、ツールスキーマではほとんどサポートされていません。allOfはプロパティをマージして結合してください。oneOfの場合、主要なバリアントを選択するか、操作を2つのツールに分割し、形状ごとに1つずつ作成します。この後者のオプションは、通常、より良いツール選択につながります。
深いネストを平坦化する。3レベルも深いボディは、モデルが正しく入力するのに苦労します。注文作成ペイロードがcustomer.address.postal_codeをネストしている場合、より平坦なツールサーフェスを検討し、エクゼキューターでネストされた形状を再構築してください。
レスポンススキーマを削除する。ツール定義は入力を記述します。完全なレスポンススキーマは定義に含まれるべきではなく、含めるとコンテキストが無駄になります。レスポンスがどのように見えるかは結果が返されたときに重要であり、それはエージェントのコンテキストウィンドウ内にAPIレスポンスを保持する方法に関する私たちの投稿でカバーされている別の問題です。
安全フラグを保持する。書き込み操作は、エクゼキューターが承認ゲートを介してルーティングできるようにマークする必要があります。仕様がx-agent-requires-approvalのような拡張機能を使用している場合、それを読み取り、尊重してください。AIエージェントのガードレールに関する私たちのガイドのパターンと組み合わせてください。
モデルに200個のエンドポイントすべてを与えないでください
最大の実際的な問題は変換ではありません。それは量です。成熟したAPIには何百もの操作があり、それらすべてをツールリストに貼り付けると、2つの失敗が同時に発生します。タスクが開始する前にコンテキストがスキーマで満たされ、モデルがほとんど同じオプションの中から選択するため、選択精度が低下します。
これらを削減する方法は3つあり、おおよそ効果が高い順に並べます。
タグでフィルタリングする。OpenAPIの操作にはタグがあり、タグは通常、製品領域にマッピングされます。払い戻しを処理するエージェントには、adminやanalyticsではなく、ordersとpaymentsのタグが必要です。これは1行のフィルターであり、通常、ほとんどの表面を削除します。
許可リストを管理する。このエージェントが呼び出しを許可されている操作をoperationIdで書き出し、それらだけを生成します。これはセキュリティ制御としても機能し、エンドポイントのツールがないエージェントは誤って呼び出すことができません。AIエージェントがAPIを破壊するのを防ぐ方法に関する私たちの投稿は、まさにこのような狭い表面を推奨しています。
オンデマンドでツールを取得する。非常に大規模なAPIの場合、操作をインデックス化し、タスクに基づいて一度に少数を選択します。これは取得ステップとそれ自体の失敗モードを追加するため、フィルタリングとキュレーションだけでは不十分になった場合にのみ使用してください。
プロトコルルートもあります。Model Context Protocolは、サーバーがクライアントにツールを公開する方法を標準化しており、OpenAPIドキュメントに裏打ちされたMCPサーバーは、フレームワークごとに1つではなく、1つの統合ポイントを提供します。MCPとは何かに関する私たちの説明はモデルをカバーし、ApidogでMCPサーバーを構築するは構築をカバーしています。

まず仕様が正しくなければならない
生成は品質問題を上流に移動させます。OpenAPIドキュメントの曖昧な説明は、曖昧なツール説明になり、モデルは間違ったエンドポイントを選択します。サーバーが実際には必須とするオプションのフィールドは、エージェントが最初の試行で誤って呼び出すツールになります。
したがって、何かを生成する前に、エージェントの視点から仕様を監査してください。
- すべての操作には
operationIdがあり、それは動詞と名詞のように読み取れます。 - すべての操作には、それが何をするのか、何を変えるのか、いつ使用すべきではないのかを記述する説明があります。「ユーザーを削除する」だけでは不十分です。「ユーザーとすべてのセッションを永久に削除します。元に戻すことはできません。一時的にアクセスを無効にするには、deactivateUserを使用してください。」が十分です。
- すべてのパラメータには、単位とフォーマットを含む説明があります。
amountは曖昧です。「セント単位の金額、最低50」は曖昧ではありません。 - 列挙型は、散文で記述するのではなく宣言され、モデルが推測するのではなく閉じたセットを得られるようにします。
- 必須は正確です。仕様はすべてをオプションとマークする傾向があり、これにより検証エラーが実行時に発生します。
これは一般的な仕様の衛生管理であり、公開ドキュメントも同じテキストを使用するため、2重に効果があります。Apidogでは、仕様、ドキュメント、モックサーバー、テストが1つのプロジェクトから生まれるため、説明を厳密にすることで、それらすべてが一度に改善されます。ApidogでのAPIバージョン管理に関する私たちのガイドは、生成されたツールを長期的に正確に保つためのもう一方の半分をカバーしています。
ツールセットを共有し、コピーしない
生成されたツールセットは設定であり、ある開発者のチェックアウトにある設定は、手書きのスキーマと同じように乖離します。フィルターリスト、許可リスト、および固定された仕様バージョンは、それが由来する仕様とともにバージョン管理された共有アーティファクトであるべきです。
一部のプラットフォームでは、これがデフォルトの単位となります。Sharklyでは、エージェントは使い捨てのプロンプトではなく、保存された作業設定です。その指示、ランタイム、スキル、リポジトリ、実行設定はエージェントと一緒に移動し、スペース全体で共有できるため、機能するツール設定はチームが再利用するものであり、各個人が再構築するものではなくなります。その下のランタイムは、Claude Code、Codex、またはすでに実行しているものでも構いません。変わるのは、それを取り巻く設定がローカルではなくなることです。

生成されたツールのテスト
生成されたツールは、手書きのツールとは異なる方法で失敗するため、呼び出しだけでなく生成もテストしてください。
スキーマのラウンドトリップチェックから始めます。生成されたツールごとに、スキーマから有効な例を作成して送信します。400または422を返すものは、ツールスキーマとサーバーが一致しないことを意味し、修正すべきは仕様です。
次に選択をテストします。正しいツールが分かっているタスクプロンプトを少量作成し、実行し、モデルがどのツールを選択したかを記録します。これは、誰かが操作の名前を変更したり、説明を短縮したりしたときに、安価な回帰テストスイートとして機能します。出力は非決定性であるため、非決定性エージェントのテストに関する私たちのガイドのラインに沿って、厳密な引数ではなくツール名についてアサートしてください。
最後に、実際の環境に展開する前に、モックに対してエージェントを実行します。同じ仕様から生成されたモックサーバーは、副作用なしに現実的なレスポンスを提供し、リトライロジックが処理すべき500エラーやタイムアウトを注入することができます。AIエージェントが本番ではなくモックをヒットすべき理由に関する私たちの投稿では、その設定について説明しています。
これで何ができるか
仕様は契約であり、ツールリストはその投影であるべきで、手動で保守される並列コピーであってはなりません。ツールを生成し、厳しくフィルタリングし、説明を正直に保ち、形状と選択の両方をテストしてください。
まずOpenAPIドキュメントをエクスポートし、説明がない操作の数を数えてください。その数が、信頼できるエージェントツールを手に入れるまでに残された作業量です。修正中に仕様、モック、テストを1か所にまとめたい場合は、Apidogをダウンロードしてください。
よくある質問
Swagger 2.0ドキュメントからツールを生成できますか? はい、ただしまずOpenAPI 3.xに変換してください。2.0のボディモデルは十分に異なっているため、ジェネレーターは一貫して扱えず、3.xが現行のツールが対象としているものです。OpenAPI Specificationリポジトリには違いが記載されています。
モデルは一度にいくつのツールを扱えますか? 技術的な制限に達するずっと前から精度が低下し始め、実用的な上限は通常数十個です。それ以上のリストは、テストする制限としてではなく、タグでフィルタリングするか許可リストを管理するシグナルとして扱ってください。
ツール名はoperationIdと完全に一致させるべきですか? はい、operationIdが読みやすい場合は一致させるべきです。これにより、ツール呼び出しから仕様操作への直接的な検索が可能になり、追跡とデバッグがはるかに容易になります。名前が悪い場合は、ジェネレーターではなく仕様で名前を変更してください。
GraphQL APIについてはどうですか? 同じ考え方が異なるソースに適用されます。スキーマをイントロスペクトし、クエリまたはミューテーションごとにツールを生成します。GraphQLスキーマはより多くの表面を公開するため、量の問題はより深刻になり、フィルタリングはさらに重要になります。
まだ手書きでツールを作成する必要はありますか? いくつかあります。複数の呼び出しを1つのアクションに連結する複合ツールや、HTTP以外のものをラップするツールは、依然として手動で作成されます。重要なのは、ルーティンな1エンドポイントラッパーが手作業ではなくなるという点です。
テスト中にエージェントが書き込みエンドポイントを呼び出すのをどのように防ぐことができますか? HTTPメソッドでフィルタリングして、テスト実行用に読み取り専用のツールセットを生成し、書き込みを行うものについてはエージェントをモックに向けます。AIエージェントが本番ではなくモックをヒットすべき理由に関する私たちの投稿では、その設定について説明しています。
