カスタムLLMインテグレーション
カスタムLLMインテグレーション
Speech Engine SDKを使用して、独自のLLMでTwilio電話エージェントを動かします。
概要
ElevenAgentsのネイティブTwilio連携は、ElevenLabsがLLMをホストするケースに対応しています。独自モデル、RAGパイプライン、関数呼び出しのルーティング、その他のサーバーサイド推論など、LLMの頭脳を自前のサーバーで完全に制御する必要があり、かつエージェントをTwilioの電話番号で運用したい場合は、このガイドを使用してください。
カスタムLLM側はSpeech Engine SDKで実現します。これはElevenLabsとサーバーの間にWebSocketを開き、通話の進行に合わせてLLMが応答をストリーミングで返せるようにします。Twilio側では、Media Streamsを使用して通話オーディオをエージェントへ中継します。
アーキテクチャ
Speech Engine SDKは、エージェントの会話システム内で2つのWebSocketエンドポイントを公開します。
- brain WebSocketはサーバー上で動作します。ElevenLabsはこれに接続し、文字起こしを受け渡してLLM生成テキストを受信します。
- conversation WebSocketはElevenLabs上で動作します。クライアントはこれに接続してオーディオを送信し、合成オーディオを受信します。Twilioブリッジは署名付きURL経由で接続し、μ-lawオーディオを双方向に中継します。
Twilio Media StreamsとSpeech Engineはいずれもulaw_8000を使用するため、ブリッジはトランスコードなしでbase64エンコードされたオーディオを中継します。
必要に応じて、ブリッジとbrainサーバーを同じプロセスで実行できます。以下の例では両者を統合しています。
このパターンを使う場合
このガイドとネイティブTwilio連携は、どちらもエージェントをTwilioの電話番号に割り当てます。違いはLLMを誰が管理するかです。
- ネイティブ連携:ElevenLabsがLLMをホストし、エージェントを通じて設定します。よりシンプルです。
- Speech Engine SDK経由のカスタムLLM(このガイド):LLMを自前のサーバーでホストします。モデル、RAG、関数呼び出し、ビジネスロジックを完全に制御できます。構成要素は増えます。
LLMロジックが標準のエージェント設定に収まる場合は、ネイティブ連携をおすすめします。brainで自社インフラ上のコードを実行する必要がある場合は、このガイドを使用してください。
このパターンでは、サーバーとElevenLabs APIの間の通信にWebSocket接続を使うSpeech Engine SDKを使用します。Speech Engine SDKの代わりにOpenAI互換HTTPエンドポイントを使用するカスタムLLMガイドも利用できます。
主な違いは、WebSocketかHTTPリクエストかです。WebSocketではターンごとに新しいHTTP接続を確立するのではなく、単一の接続を維持するため、レイテンシーが改善する場合があります。
前提条件
- Twilioアカウントと、音声通話対応の電話番号。
- Speech Engineリソース。Speech Engineクイックスタートに従って作成し、brainサーバーのパターンを確認してください。
- 公開HTTPSトンネル(例:ngrok)。Twilioは公開インターネット経由でブリッジに接続します。
- Python 3.9以降またはNode.js 18以降。
μ-lawオーディオ用にエージェントを設定する
Twilio Media Streamsは8 kHzのμ-lawオーディオを使用します。ブリッジでトランスコードする必要がないよう、Speech Engineが同じ形式を受信・出力するように設定してください。
eleven_flash_v2はテキスト読み上げのレイテンシーを低く保つため、電話通話で重要です。request_headersブロックは、すべてのbrain WebSocket接続にx-api-key: <shared-secret>を含めるようElevenLabsに指示します。brainサーバーはこのヘッダーを確認し、自分のSpeech Engineだけが接続できるようにします。
ブリッジサーバーを構築する
ブリッジは3つのルートを提供します。
POST /incoming-call— Twilio webhook。Twilioに/media-streamへのMedia Streamを開くよう指示するTwiMLを返します。GET /media-stream— Twilio Media Streams WebSocket。Speech Engine conversation WebSocketとの間でオーディオを中継します。GET /ws— Brain WebSocket。会話開始時にElevenLabsがここへ接続します。標準のengine.serve()/engine.attach()サーバーを実行します。
Speech Engine用の署名付きURLを生成する
ブリッジは新しい通話が着信するたびに署名付きURLをリクエストします。このURLにはSpeech Engine IDと一回限りの署名が埋め込まれるため、ブリッジで生のAPIキーを使用する必要はありません。
TwiMLレスポンスを返す
通話が着信すると、Twilioは/incoming-callへPOSTします。レスポンスは、ブリッジ自身の/media-stream WebSocketへのMedia Streamを開くTwiMLです。
RequestValidator(Python)とtwilio.webhook({ validate: true })(Node)は、X-Twilio-SignatureヘッダーをTWILIO_AUTH_TOKENと照合します。検証しない場合、公開インターネット上の誰でも/incoming-callにPOSTでき、アカウントに通話料金が請求される可能性があります。
Media Streamをブリッジする
Media Streamは、connected、start、media(オーディオペイロード)、stopという一連のJSONイベントを送信するWebSocketです。ブリッジはstart時にSpeech Engine conversation WebSocketを開き、ストリームが閉じるまでオーディオを双方向に中継します。
Speech EngineのinterruptionイベントはTwilioストリームでclearイベントをトリガーし、バッファリングされたオーディオを破棄するため、割り込み発話がスムーズに機能します。pingイベントにはpongで応答し、conversation WebSocketを維持します。
brainサーバーも同時に実行する
brainサーバーは、クイックスタートで示されている標準のSpeech Engineサーバーです。追加するのはWebSocketアップグレード時の共有シークレットチェックだけです。x-api-keyがSpeech Engineに設定した値と一致する場合にのみ、接続を受け入れてください。
LLM呼び出しとストリーミング応答を含む完全なon_transcript実装については、Speech Engineクイックスタートを参照してください。
Twilioをブリッジに接続する
Speech Engineのws_urlを更新する
ElevenLabsが接続先を認識できるよう、speech_engine.ws_urlをbrainエンドポイントの公開WebSocket URLに設定してください。
本番環境での考慮事項
- Webhookの検証:
/incoming-callでは必ずX-Twilio-Signatureを検証してください。上記の例ではTwilioのヘルパーライブラリを使用しています。この手順は省略しないでください。 - 共有シークレット:brain WebSocketで共有シークレットを必ず適用してください。適用しないと、ngrok URLを推測した第三者が接続し、ElevenLabsになりすます可能性があります。
- 安定したホスト:ngrok無料プランのURLは再起動のたびに変わります。再起動ごとにSpeech Engineの
ws_urlとTwilio Webhookを更新しなくて済むよう、予約済みのngrokドメインまたは実際のホスト名を使用してください。 - レイテンシー:各通話では、LLMの最初のトークンが生成されるまでの時間に加えて、ネットワークホップが2回発生します。低レイテンシーのモデルを使用し、レスポンスをストリーミングして体感レイテンシーを抑えてください。
- 1プロセスまたは2プロセス:この例では、1つのngrokトンネルですべてをカバーできるよう、bridgeとbrainを同じポートに配置しています。本番環境では、それぞれにパブリックURLがあれば、2つのサービスに分割できます。
- プロンプトインジェクション:電話で話された入力は、信頼できないユーザー入力です。ツール呼び出しやデータベースへの書き込みに影響する前に、文字起こしを検証してください。