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

Developer cookbook

エージェントをエンドツーエンドでテスト(API)

ThunderPhone API を通じて、単発シミュレーション、並列シナリオバッチ、リリースゲートスイートを実行し、顧客が聞く前にエージェントのリグレッションを検出します。

AI エージェントの改善では、プロンプト、ツール、エッジケースの処理方法を繰り返し調整します。シミュレーション API は、指定したシナリオプロンプトを使用してエージェントに対する実際の通話を実行します。エージェントを対象にするとボット間実行が作成され、電話番号を対象にすると SIP ループバック実行が作成されます。各実行では、文字起こし、評価、請求を含む実際の通話ログが生成されるため、エージェントの動作とコストを正確に確認できます。

用途:

  • プロンプトを編集するたびのデプロイ前スモークテスト
  • CI に組み込んだリグレッションスイート(test-call.completed webhook をフックし、スコアが低下したらビルドを失敗させる)
  • 同時実行数の上限のストレステスト

ワンショット: 単一実行

curl -X POST https://api.thunderphone.com/v1/simulations \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "target_type":     "agent",
    "target_id":       12,
    "direction":       "outbound",
    "scenario_prompt": "You are a polite caller asking about refund policy for order 12345.",
    "consent_to_charge": true
  }'

フィールド:

フィールド型必須説明
target_type文字列はいagent または phone_number
target_id整数はいエージェント ID(または電話番号 ID)
direction文字列いいえoutbound(デフォルト。テスト発信者が発信)または inbound(テスト発信者が応答)
scenario_prompt文字列いいえテストボットの発話内容を指定
language / primary_language文字列いいえテスト発信者の言語。サポートされていないコードは拒否されます
simulator_product文字列いいえtesting(デフォルト)または spark。ウォーム転送の相談テストなど、より人間らしいシミュレーション発信者に使用
consent_to_chargeブール値はいtrue にする必要があります。見積もりでは、選択したエージェントとシミュレーション発信者の両方に一律の分単価と通話レッグ料金が課金されます
target_number文字列いいえリモート側の E.164 オーバーライド。指定しない場合はプラットフォームのテスト番号が使用されます

mode は読み取り専用で、target_type から導出されます。agent は mode="bot" を生成し、phone_number は mode="sip" を生成します。

レスポンスは、status="queued" のシミュレーション実行オブジェクト です。status が completed または failed になるまでポーリングしてください。call_id が設定されたら、 GET /v1/calls/{call_id}/transcript を使用して文字起こしを取得します。

バッチ: 並列シナリオ

N 個のシナリオを同時に実行します。既知のすべてのエッジケースを並列で検証するリグレッションスイートに便利です。

curl -X POST https://api.thunderphone.com/v1/simulations/batches \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "target_type":     "agent",
    "target_id":       12,
    "direction":       "outbound",
    "run_count":       5,
    "stagger_seconds": 2,
    "scenario_prompts": [
      "Ask about refund policy.",
      "Ask for hours of operation.",
      "Complain about a delayed shipment.",
      "Ask to speak with a human.",
      "Ask an unrelated trivia question."
    ],
    "consent_to_charge": true
  }'

レスポンスには、子実行 ID の run_ids リストが含まれます。バッチステータスを取得します。

curl https://api.thunderphone.com/v1/simulations/batches/{batch_id} \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"

run_count の上限は 20 です。stagger_seconds は、エージェントに過度な負荷をかけないように実行開始の間隔を設定します(0~60 秒)。

CI に組み込む

シミュレーションページ (/dashboard/simulations) でリリースゲートスイートを作成します。エージェントを選択し、シナリオを手動で追加するか、AIでシナリオを生成をクリックしてエージェントのプロンプトからシナリオのドラフトを作成します(必要に応じてエッジケースの確認も可能です)。その後、シナリオをスイートにまとめます。 スイートでは、シナリオとエージェントに加え、最低合格率と、必要に応じて重大な失敗をゼロにするルールを固定します。合格した実行は承認済みベースラインとなり、後続の合格→不合格の遷移はリグレッションとして返されます。

CI では組織 API キーを使用します。 このスクリプトはスイートをトリガーし、採点と比較が完了するまでポーリングします。判定が pass でない限り、ゼロ以外の終了コードで終了します。

#!/usr/bin/env bash
set -euo pipefail
 
: "${THUNDERPHONE_API_KEY:?Set THUNDERPHONE_API_KEY}"
: "${THUNDERPHONE_ORG_ID:?Set THUNDERPHONE_ORG_ID}"
: "${THUNDERPHONE_SUITE_ID:?Set THUNDERPHONE_SUITE_ID}"
 
base="https://api.thunderphone.com/v1/orgs/${THUNDERPHONE_ORG_ID}/suites/${THUNDERPHONE_SUITE_ID}"
auth="Authorization: Bearer ${THUNDERPHONE_API_KEY}"
 
run_id="$(curl --fail --silent --show-error -X POST "${base}/run" \
  -H "$auth" -H "Content-Type: application/json" -d '{}' | jq -r '.id')"
 
deadline=$((SECONDS + 1800))
while (( SECONDS < deadline )); do
  result="$(curl --fail --silent --show-error \
    "${base}/runs/${run_id}" -H "$auth")"
  status="$(jq -r '.status' <<<"$result")"
  if [[ "$status" == "completed" ]]; then
    jq . <<<"$result"
    [[ "$(jq -r '.verdict' <<<"$result")" == "pass" ]]
    exit
  fi
  sleep 10
done
 
echo "ThunderPhone suite timed out" >&2
exit 1

POST /v1/orgs/{org_id}/suites/{suite_id}/run は実行 ID を含む 202 を返します。GET /v1/orgs/{org_id}/suites/{suite_id}/runs/{run_id} は status、verdict、pass_rate、critical_failure_count、およびベースラインの regressions リストを返します。どちらのエンドポイントも、URL 内の組織を API キーの組織に紐付けます。

スケジュールに従ってスイートを実行する

エージェントの シミュレーション タブを開き、リリースゲートスイートを選択して、スイートを作成または編集します。 スケジュールに従って実行をオンにし、頻度と タイムゾーンを選択してから、表示に従って毎時の分、ローカル時刻、または曜日を設定します。 スイートを保存を選択します。スケジュールに従って実行のチェックを外すと、 ダッシュボードのスケジュールが削除されます。

API 経由

スイートを PATCH して、スケジュールを追加または置き換えます。完全な スイートオブジェクトとエンドポイントについては、スイート(リリースゲート)を参照してください。

curl -X PATCH https://api.thunderphone.com/v1/suites/{suite_id} \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "schedule": {
      "enabled": true,
      "frequency": "daily",
      "timezone": "America/Chicago",
      "hour": 6,
      "minute": 30
    }
  }'

frequency には hourly、daily、または weekly を指定できます。IANA タイムゾーンを使用してください。 毎時スケジュールでは minute、毎日スケジュールでは hour と minute を使用します。 毎週スケジュールでは weekday も使用し、月曜日は 0、日曜日は 6 です。 スイートのレスポンスには next_run_at と last_run_at が含まれます。

時刻は、選択したタイムゾーンの夏時間の変更に従います。スケジュールされた実行は スイートの実行履歴に表示され、現在のエージェント、シナリオ、基準、および承認済みベースラインを使用します。生成される各テスト通話では test-call.completed が発行されます。スイートレベルの完了 webhook はありません。スケジュールされた 通話には、手動のスイート実行と同じシミュレーション料金が適用され、スイート実行には trigger: "schedule" が記録されます。

タイミングを変更せずにスケジュールを一時停止するには、完全な既存の スケジュールオブジェクトに "enabled": false を指定して PATCH します。frequency は必須です。 タイムゾーンと時刻のフィールドを省略するとデフォルト値にリセットされるため、既存の値を含めてください。 スケジュールを削除するには "schedule": null を送信します。

パターン

プロンプトごとの回帰コーパス

{name, scenario_prompt, expected_outcome} のタプルを含む JSON ファイルを維持します。 プロンプトを変更するたびに、全セットをバッチとして実行し、前回の実行結果と文字起こしおよび評価を比較します。

リリースごとのスモークテスト

デプロイ後に毎回実行する、正常系シナリオ 5 件の単一バッチです。 レイテンシーの影響を受けやすいため、stagger_seconds: 0 を維持します。

レイテンシーベンチマーク

異なるプロダクトティア(spark、bolt、storm-base)に対して同一のシナリオを実行します。各通話ログから call.graded スコアと duration_seconds を比較します。


次のステップ