ThunderPhone 2.0、提供開始。セルフサービスで、1分あたり2¢から。発表内容を見る

Developer cookbook

ツール連携を構築する(API)

会話の途中でエージェントからAPIを呼び出し、データベースの検索、チケットの作成、注文の照会を行えます。

ツール統合は、エージェントが通話中に呼び出せる再利用可能な HTTP エンドポイントです。ツールの JSON スキーマ記述とエンドポイント URL を ThunderPhone に渡すと、エージェントは会話に基づいて呼び出すタイミングを判断し、ThunderPhone がそのサーバーからアウトバウンド HTTP リクエストを送信して、応答をエージェントに返します。

このガイドでは、天気を検索するツールをエンドツーエンドで作成します。

ツールの構成

構成要素は 2 つです。

  1. スキーマ — ツールの機能と受け取る引数を LLM に伝える OpenAI 形式の関数定義 ({type: "function", function: {name, description, parameters}})。
  2. エンドポイント — LLM がツールを使用すると判断した際に、ThunderPhone のサーバーが呼び出す URL。 リクエストは JSON POST で、本文には LLM が選択した引数が含まれます。

1. 保存方法を選択する

エージェントにインラインで追加

単発のツールをエージェントの tools 配列に追加します。シンプルですが、 再利用はできません。

保存済み統合

ツールを再利用可能な統合として保存し、 複数のエージェントからリンクします。複数回使用するものにはこちらを推奨します。

このガイドでは、保存済み統合の方法を使用します。

2. 統合を作成する

curl -X POST https://api.thunderphone.com/v1/integrations \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "display_name": "Weather API",
    "spec": {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Return the current weather for a zip code.",
        "parameters": {
          "type": "object",
          "properties": {
            "zip": { "type": "string", "description": "5-digit US ZIP code" }
          },
          "required": ["zip"]
        }
      }
    },
    "endpoint_url":    "https://api.example.com/weather",
    "endpoint_method": "GET",
    "headers": [
      { "key": "X-Api-Key", "value": "your-provider-key" }
    ]
  }'

返された id(UUID)を保存します。

3. エンドポイントをサンドボックスでテストする

統合をエージェントにリンクする前に、ThunderPhone のサーバーから署名付きリクエストを送信し、 接続を確認します。

curl -X POST https://api.thunderphone.com/v1/integrations/test-request \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url":    "https://api.example.com/weather?zip=94110",
    "method": "GET",
    "headers": { "X-Api-Key": "your-provider-key" }
  }'
Response
{
  "ok": true,
  "status": 200,
  "elapsed_ms": 187,
  "response_headers": { "content-type": "application/json" },
  "response_preview": "{\"temperature_f\": 64, ...}"
}

このテストでは ThunderPhone の SSRF 防御も強化されます。localhost またはプライベート IP 範囲へのリクエストは、400 code=url_not_allowed を返します。

4. 統合をエージェントにリンクする

エージェントを作成または更新する際に、integration_ids を使用して紐付けます。

curl -X PATCH https://api.thunderphone.com/v1/agents/12 \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "integration_ids": ["f9b5a1a4-..."]
  }'

1つのエージェントに複数の統合をリンクできます。エージェントのプロンプトから名前で参照できます。たとえば、発信者が気象状況について質問した場合は get_weather を使用するよう指定できます。また、スキーマの説明から暗黙的に検出することもできます。

5. エンドポイントを実装する

エージェントがツールを呼び出すと、ThunderPhone は署名付き POST リクエストを endpoint_url に送信します。

POST /weather HTTP/1.1
Host: api.example.com
X-Api-Key: your-provider-key
X-ThunderPhone-Signature: <HMAC-SHA256 hex>
X-ThunderPhone-Call-ID: 987654321
Content-Type: application/json

{"zip": "94110"}

サーバーは、LLM に返される JSON で応答します。

{"temperature_f": 64, "condition": "Partly cloudy", "wind_mph": 8}

LLM はその応答を取り込み、発信者に自然な要約を音声で伝えます。

6. ループをテストする

エージェントに対してマイクセッションを実行し、ツールが処理する質問(「94110 の天気は?」)をします。通話の文字起こしには、往復のすべての処理が表示されます。

{
  "call_id": 987654321,
  "transcripts": [
    { "role": "user",
      "content": "What's the weather in 94110?" },
    { "role": "tool_call",
      "content": "{\"tool_call\": \"get_weather\", \"arguments\": {\"zip\": \"94110\"}}" },
    { "role": "tool_response",
      "content": "{\"tool_name\": \"get_weather\", \"response\": {\"temperature_f\": 64, \"condition\": \"Partly cloudy\"}}" },
    { "role": "agent",
      "content": "It's 64 degrees and partly cloudy." }
  ]
}

これはGET /v1/calls/{call_id}/transcriptで取得できます。エントリごとのタイミングと音声オフセットを含む生イベントストリームは、GET /v1/calls/{call_id}/historyで取得できます。

よくある注意点

エージェントがツールを呼び出さない

LLM はツールの説明に基づいて判断します。発信者の質問が説明と一致しない場合、モデルはツールを呼び出しません。説明を具体化し(よく使われる同義語や表現を追加)、またはエージェントのプロンプトで明示します(「発信者が天気について質問した場合は get_weather を使用する。」)。

ツールが返すデータ量が多すぎる

6 kB を超える応答は、文字起こしのプレビューで切り詰められます。行全体ではなく、LLM が必要とするフィールドのみを返してください。

タイムアウト

ツールエンドポイントのデフォルトタイムアウトは 10 秒です。より長い時間が必要な場合は、非同期で処理してください。{"status": "pending", "request_id": "..."} を返し、別のツール呼び出しで結果を提示します。

バージョニング

統合に対する PATCH は、すべて新しいリビジョンを作成します。GET /v1/integrations/{id}/versionsを確認して、誰が何を変更したかを把握できます。ツールのスキーマを壊してしまった場合は、古いスナップショットを PATCH で戻すことで手動でロールバックできます。


次のステップ