DEV Community

Cover image for OpenAPIからAIエージェントツールへ:手書きラッパーは不要
Akira
Akira

Posted on Originally published at apidog.com

OpenAPIからAIエージェントツールへ:手書きラッパーは不要

ほとんどのエージェントのコードベースには、誰も保守したがらないファイルがあります。40個ものツール定義を持ち、それぞれが手書きのJSONスキーマで、すでに別の場所に定義されているAPIエンドポイントを記述しているファイルです。APIチームが必須フィールドを追加し、仕様やドキュメントを更新しても、誰かが400エラーに気づくまでエージェントは古いペイロードを送り続けます。

今日からApidogを試す

すべてのエンドポイントには、すでに機械可読な定義があります。それがOpenAPIドキュメントです。OpenAPIをモデルが呼び出せるツール定義へ変換すれば、記憶や手作業に頼らず、API仕様とツールを自動的に同期できます。

このガイドでは、OpenAPIの操作をツールスキーマへマッピングする方法、生成時に必要な補正、200個のエンドポイントをモデルが扱える規模まで絞り込む方法、そして生成されたツールをテストする方法を説明します。エージェントがコードを書く際にAPIツールがまだ必要かどうかを知りたい場合は、こちらの記事も参考になります。

Apidogが重要なのは、生成結果を正しく動かすには、まずAPI仕様自体が正確でなければならないからです。ツール定義は、元のドキュメントにある不足や曖昧さをそのまま引き継ぎます。

手書きのツール定義が抱える問題

5個程度のエンドポイントなら、手書きでも問題ないように見えます。しかし、20個を超えると、次の3つの問題が目立ち始めます。

仕様と定義が乖離する

仕様はコード生成やAPIチームによって管理され、ツールファイルはエージェント開発者によって管理されます。両者を同期する仕組みがなければ、少しずつ内容がずれていきます。最初の兆候は、エージェントが「突然」動かなくなることです。

説明が薄くなる

40個のスキーマを手書きすると、後半の説明は1行程度になりがちです。モデルは説明文を使ってツールを選ぶため、情報量の少ない説明は選択精度を直接下げます。エージェント向けツールスキーマの設計では、説明文が重要な理由を詳しく解説しています。

実行時までエラーが分からない

APIが整数を要求しているのに、手書きスキーマで文字列として定義されていれば、エージェントが初めて実行した本番タスクで422が発生します。

OpenAPIから生成すれば、これらの問題をまとめて解決できます。

  • 信頼できる情報源を1つにできる
  • 説明文をAPIドキュメントと共有できる
  • サーバーが検証するスキーマと同じ型を使える

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]

Enter fullscreen mode Exit fullscreen mode

生成されるツール定義は次のようになります。

{
  "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"] }
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

基本ルールは4つです。

  • operationIdをツール名にする。存在しない場合は、HTTPメソッドとパスから安定した名前を生成し、仕様にも追加する。
  • パス、クエリ、ボディのパラメータを1つのプロパティオブジェクトにまとめる。モデルは値の送信先を意識しませんが、エクゼキューターは必要とするため、各パラメータの場所を記録するサイドテーブルを保持する。
  • summarydescriptionを結合してツール説明にする。summaryだけでは、ツール選択に必要な情報が不足しがちです。
  • パスパラメータとボディフィールドの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)

Enter fullscreen mode Exit fullscreen mode

これでOpenAPIとツール呼び出しの橋渡しができます。残りは、モデルが扱いやすい形に整える処理です。

ジェネレーターで補正するポイント

OpenAPIをそのままツールスキーマへ変換すると、モデルが扱いにくい定義になることがあります。少なくとも次の5点を補正してください。

$refを解決する

多くのツール呼び出しAPIはJSON Schemaのサブセットしか受け付けず、componentsへの参照をたどりません。参照をインライン化しましょう。

ただし、再帰的なスキーマには注意が必要です。無限展開を防ぐため、一定の深さで再帰を打ち切り、それより深い構造は説明文で表現します。

未対応のキーワードを変換する

oneOfallOfdiscriminatornullableはOpenAPIでは一般的ですが、ツールスキーマでは十分にサポートされていないことがあります。

  • allOfはプロパティをマージする
  • oneOfは主要なバリアントを選ぶ
  • 形状が大きく異なるoneOfは、バリアントごとに別のツールへ分割する

通常、後者のほうがツール選択の精度は高くなります。

深いネストを平坦化する

3階層以上のネストしたボディは、モデルが正しく入力しにくくなります。たとえば、注文作成ペイロードのcustomer.address.postal_codeを、より平坦なツール入力として公開し、エクゼキューター側でネストした形に再構築する方法を検討してください。

レスポンススキーマを除外する

ツール定義が記述するのは入力です。完全なレスポンススキーマまで含めると、コンテキストを無駄に消費します。

レスポンスの扱いは、実行結果を受け取った時点で重要になります。これはエージェントのコンテキストウィンドウ内にAPIレスポンスを保持する方法で扱っている別の問題です。

安全フラグを維持する

書き込み操作には安全フラグを付け、エクゼキューターで承認ゲートへルーティングできるようにします。

仕様でx-agent-requires-approvalのような拡張を使っている場合は、ジェネレーターで読み取り、その指示を必ず尊重してください。AIエージェントのガードレールのパターンとも組み合わせられます。

200個のエンドポイントをモデルに渡さない

最大の問題は変換処理ではなく、ツールの数です。

成熟したAPIの全操作をツールリストへ含めると、タスク開始前にコンテキストがスキーマで埋まり、似た選択肢が増えることで選択精度も下がります。

削減方法は、効果が高い順に次の3つです。

1. タグで絞り込む

OpenAPIのタグは、多くの場合、製品領域に対応しています。

払い戻しを扱うエージェントなら、adminanalyticsではなく、orderspaymentsの操作だけを生成します。1行のフィルターでツールの大半を除外できることもあります。

2. 許可リストを管理する

エージェントが呼び出してよい操作をoperationIdで列挙し、それだけを生成します。

これはセキュリティ制御としても機能します。ツールとして公開されていないエンドポイントは、エージェントから誤って呼び出されません。AIエージェントがAPIを破壊するのを防ぐ方法でも、狭いツールサーフェスを推奨しています。

3. 必要な時だけツールを取得する

非常に大規模なAPIでは、操作をインデックス化し、タスクに応じて少数のツールだけを取得します。

ただし、取得処理とその失敗モードが新たに発生します。タグによるフィルタリングと許可リストだけでは不十分な場合に採用してください。

MCPを統合ポイントにする

別の選択肢として、Model Context Protocolがあります。MCPは、サーバーがクライアントへツールを公開する方法を標準化します。

OpenAPIドキュメントを基盤にしたMCPサーバーを用意すれば、フレームワークごとに個別統合を作るのではなく、1つの統合ポイントを提供できます。MCPとは何かでは概念を、ApidogでMCPサーバーを構築するでは実装方法を解説しています。

OpenAPI仕様からMCPツールを生成する図

まずAPI仕様を正しくする

生成によって、品質問題は上流へ移動します。OpenAPIの説明が曖昧なら、ツール説明も曖昧になり、モデルは誤ったエンドポイントを選びます。サーバーが実際には必須とするフィールドを任意として定義すれば、実行時エラーにつながります。

生成前に、エージェントの視点で仕様を監査しましょう。

  • すべての操作にoperationIdがあり、動詞と名詞の組み合わせとして読める
  • 操作の目的、変更内容、使用すべきでない状況が説明されている
  • すべてのパラメータに単位やフォーマットを含む説明がある
  • 列挙型が宣言され、モデルが値を推測しなくてよい
  • 必須フィールドが正確に定義されている

たとえば、「ユーザーを削除する」だけでは不十分です。次のように書けば、不可逆性や代替手段まで伝わります。

ユーザーとすべてのセッションを永久に削除します。元に戻すことはできません。一時的にアクセスを無効にするには、deactivateUserを使用してください。

これは仕様の衛生管理でもあります。仕様と同じ説明文が公開ドキュメントやモックサーバーにも使われるため、改善効果は複数の場所に及びます。

ApidogでのAPIバージョン管理では、生成されたツールを長期的に正確に保つための運用方法を説明しています。Apidogでは、仕様、ドキュメント、モックサーバー、テストを1つのプロジェクトから管理できます。

ツールセットを共有し、コピーしない

生成されたツールセットも設定ファイルです。1人の開発者のチェックアウトにだけ存在すれば、手書きスキーマと同じように乖離します。

次の項目は、元の仕様とともにバージョン管理する共有アーティファクトにしてください。

  • タグのフィルター
  • 許可リスト
  • 固定するOpenAPI仕様のバージョン

一部のプラットフォームでは、これをエージェントの標準単位として扱います。Sharklyでは、エージェントを使い捨てのプロンプトではなく、保存された作業設定として管理します。

指示、ランタイム、スキル、リポジトリ、実行設定をエージェントと一緒に共有できるため、動作するツール設定をチームで再利用できます。ランタイムはClaude Code、Codexなど、すでに使っているものを選べます。変わるのは、周辺設定が個人のローカル環境に閉じなくなることです。

SharklyのUIのスクリーンショット

生成されたツールをテストする

生成ツールは、手書きツールとは異なる形で壊れます。そのため、ツールの実行だけでなく、生成処理自体もテストしてください。

1. スキーマのラウンドトリップを確認する

生成された各ツールについて、スキーマから有効な入力例を作成してAPIへ送信します。

400または422が返った場合は、ツールスキーマとサーバーの検証ルールが一致していません。修正対象は通常、生成後のツールではなくOpenAPI仕様です。

2. ツール選択を検証する

正しいツールが既知のタスクプロンプトを少数用意し、モデルが選択したツール名を記録します。

操作名の変更や説明文の短縮による回帰を、安価に検出できます。モデル出力は非決定的なので、非決定性エージェントのテストの方針に従い、厳密な引数ではなくツール名を検証してください。

3. 本番前にモックで実行する

実環境へ展開する前に、エージェントをモックサーバーへ接続します。

同じ仕様から生成したモックサーバーなら、副作用なしで現実的なレスポンスを返せます。リトライロジックが処理すべき500エラーやタイムアウトも注入できます。[AIエージェントが本番ではなくモックをヒットすべき理由](https://apidog.com/jp/blog/ai-agents-mock-apis-not次の順序で進めます。

  1. OpenAPIからツールを生成する
  2. $refや未対応キーワードを補正する
  3. タグと許可リストでツールを絞る
  4. 説明、型、必須項目を正確に保つ
  5. スキーマ、ツール選択、モック実行をテストする
  6. 仕様とツールセットをバージョン管理する

まずOpenAPIドキュメントをエクスポートし、説明がない操作の数を数えてみてください。その数が、信頼できるエージェントツールを得るまでに残された作業量です。

仕様、モック、テストを1か所で管理したい場合は、Apidogをダウンロードしてください。

よくある質問

Swagger 2.0ドキュメントからツールを生成できますか?

はい。ただし、先にOpenAPI 3.xへ変換してください。Swagger 2.0のボディモデルはOpenAPI 3.xと大きく異なるため、ジェネレーターが一貫して扱いにくい場合があります。3.xは現在のツールが主に対象としている形式です。

違いについては、OpenAPI Specificationリポジトリを参照してください。

モデルは一度にいくつのツールを扱えますか?

技術的な上限に達する前から精度は低下します。実用上の上限は通常、数十個程度です。それ以上になったら、限界をテストするのではなく、タグでフィルタリングするか許可リストを導入してください。

ツール名はoperationIdと完全に一致させるべきですか?

operationIdが読みやすいなら、一致させるべきです。ツール呼び出しから仕様上の操作を直接検索でき、追跡とデバッグが容易になります。

名前が不適切な場合は、ジェネレーターで書き換えるのではなく、OpenAPI仕様側で修正してください。

GraphQL APIではどうですか?

同じ考え方を別のスキーマへ適用できます。GraphQLスキーマをイントロスペクトし、クエリまたはミューテーションごとにツールを生成します。

GraphQLはより広いサーフェスを公開するため、ツール数の問題はさらに深刻になります。フィルタリングはREST API以上に重要です。

手書きのツールが必要な場合はまだありますか?

あります。複数のAPI呼び出しを1つのアクションへまとめる複合ツールや、HTTP以外の処理をラップするツールは、引き続き手動で作成します。

重要なのは、通常の1エンドポイントラッパーを手作業で保守しなくてよくなることです。

テスト中にエージェントが書き込みエンドポイントを呼び出すのを防ぐには?

HTTPメソッドでフィルタリングし、テスト専用に読み取り専用のツールセットを生成します。書き込み操作を含む場合は、エージェントをモックサーバーへ接続してください。

設定方法については、AIエージェントが本番ではなくモックをヒットすべき理由を参照してください。

Top comments (0)