コンテンツにスキップ

Realtime Agent を Twilio に接続

Twilio は Media Streams API を提供しており、通話の元音声を WebSocket サーバーへ送信できます。これを利用して、あなたの音声エージェント を Twilio に接続できます。websocket モードのデフォルト Realtime Session トランスポートを使えば、Twilio からのイベントを Realtime Session に接続できます。しかし、正しいオーディオ形式の設定と、Web ベースの会話よりも遅延が大きい電話通話に合わせた割り込みタイミングの調整が必要になります。

このセットアップを簡単にするために、Twilio への接続、割り込み処理、音声転送を自動で行う専用のトランスポートレイヤーを作成しました。

  1. Twilio アカウントと Twilio 電話番号を用意してください。

  2. Twilio からのイベントを受信できる WebSocket サーバーをセットアップします。

    ローカルで開発する場合は、ngrokCloudflare Tunnel のようなローカルトンネルを設定し、ローカルサーバーを Twilio からアクセス可能にする必要があります。TwilioRealtimeTransportLayer を使って Twilio に接続できます。

  3. extensions パッケージをインストールして Twilio アダプターを追加します:

    Terminal window
    npm install @openai/agents-extensions
  4. アダプターとモデルをインポートして RealtimeSession に接続します:

    import { TwilioRealtimeTransportLayer } from '@openai/agents-extensions';
    import { RealtimeAgent, RealtimeSession } from '@openai/agents/realtime';
    const agent = new RealtimeAgent({
    name: 'My Agent',
    });
    // Create a new transport mechanism that will bridge the connection between Twilio and
    // the OpenAI Realtime API.
    const twilioTransport = new TwilioRealtimeTransportLayer({
    twilioWebSocket: websoketConnection,
    });
    const session = new RealtimeSession(agent, {
    // set your own transport
    transport: twilioTransport,
    });
  5. RealtimeSession を Twilio に接続します:

    session.connect({ apiKey: 'your-openai-api-key' });

RealtimeSession で期待できるすべてのイベントや挙動 ― ツール呼び出し、ガードレール など ― がそのまま機能します。RealtimeSession を音声エージェントで使用する方法は、音声エージェントの概要 を参照してください。

  1. 速度が最重要です。

    必要なイベントと音声を Twilio から受け取るためには、WebSocket 接続を取得したらすぐに TwilioRealtimeTransportLayer インスタンスを生成し、直後に session.connect() を呼び出してください。

  2. 元の Twilio イベントへアクセスする。

    Twilio から送信される生イベントを取得したい場合は、RealtimeSession インスタンスで transport_event をリッスンしてください。Twilio からの各イベントは type: twilio_message を持ち、message プロパティに元イベントデータが入っています。

  3. デバッグログを確認する。

    状況を詳しく確認したい場合は、環境変数 DEBUG=openai-agents* を設定すると Agents SDK のすべてのデバッグログが表示されます。Twilio アダプターのログだけを有効にする場合は DEBUG=openai-agents:extensions:twilio* を使用してください。

以下は、Twilio からのリクエストを受け取り、それを RealtimeSession に転送する WebSocket サーバーのエンドツーエンド例です。

Fastify を使ったサーバー例
import Fastify from 'fastify';
import dotenv from 'dotenv';
import fastifyFormBody from '@fastify/formbody';
import fastifyWs from '@fastify/websocket';
import { RealtimeAgent, RealtimeSession } from '@openai/agents/realtime';
import { TwilioRealtimeTransportLayer } from '@openai/agents-extensions';
// Load environment variables from .env file
dotenv.config();
// Retrieve the OpenAI API key from environment variables. You must have OpenAI Realtime API access.
const { OPENAI_API_KEY } = process.env;
if (!OPENAI_API_KEY) {
console.error('Missing OpenAI API key. Please set it in the .env file.');
process.exit(1);
}
const PORT = +(process.env.PORT || 5050);
// Initialize Fastify
const fastify = Fastify();
fastify.register(fastifyFormBody);
fastify.register(fastifyWs);
const agent = new RealtimeAgent({
name: 'Triage Agent',
instructions:
'You are a helpful assistant that starts every conversation with a creative greeting.',
});
// Root Route
fastify.get('/', async (request, reply) => {
reply.send({ message: 'Twilio Media Stream Server is running!' });
});
// Route for Twilio to handle incoming and outgoing calls
// <Say> punctuation to improve text-to-speech translation
fastify.all('/incoming-call', async (request, reply) => {
const twimlResponse = `
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>O.K. you can start talking!</Say>
<Connect>
<Stream url="wss://${request.headers.host}/media-stream" />
</Connect>
</Response>`.trim();
reply.type('text/xml').send(twimlResponse);
});
// WebSocket route for media-stream
fastify.register(async (fastify) => {
fastify.get('/media-stream', { websocket: true }, async (connection) => {
const twilioTransportLayer = new TwilioRealtimeTransportLayer({
twilioWebSocket: connection,
});
const session = new RealtimeSession(agent, {
transport: twilioTransportLayer,
});
await session.connect({
apiKey: OPENAI_API_KEY,
});
console.log('Connected to the OpenAI Realtime API');
});
});
fastify.listen({ port: PORT }, (err) => {
if (err) {
console.error(err);
process.exit(1);
}
console.log(`Server is listening on port ${PORT}`);
});
process.on('SIGINT', () => {
fastify.close();
process.exit(0);
});