realtime について
ElevenLabs Realtimeを使う開発者向けのスキルです。ElevenAgentsのリアルタイム音声モードの設定や、OpenAI Realtime SDKを使うブラウザーアプリの移行について、モデル選択、利用条件の確認、設定検証を案内します。
主な機能
- 01ElevenAgentsのリアルタイム音声モード設定
- 02MiniとMaxのモデル要件の比較
- 03コンプライアンスとデータ所在地の確認
- 04エージェント設定の公開と検証
- 05ブラウザー音声アプリの移行
活用シーン
- 01ElevenAgentsエージェントでRealtimeモデルを有効化
- 02ワークスペース条件に合うモデルの確認
- 03OpenAI RealtimeのブラウザーアプリをElevenLabsへ移行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ elevenlabs/ skills --skill realtimeインストール後、Claude Code で/realtimeを入力して読み込まれたか確認します。
同梱ファイルreferences/browser-audio.mdreferences/session-config.md
詳細
ElevenLabs Realtime
Realtime モデルは、低遅延の音声会話向けに構築された ElevenLabs のモデルです。利用方法は 2 つあります。
- ElevenAgents エージェント(エージェント ID、ダッシュボード、または
agent_configs/を含むelevenlabs agentsプロジェクト):エージェントの Voice モードをconversation_config.realtime_modelで Realtime に設定します。LLM、TTS モデル、ASR 設定は ElevenLabs が管理します。Realtime モデルでエージェントを実行するを参照してください。 - OpenAI の Realtime SDK をベースに構築されたブラウザーアプリ:SDK はそのまま使用し、OpenAI 互換の ElevenLabs Realtime API(
wss://api.elevenlabs.io/v1/convai/realtime)を指定します。OpenAI Realtime からアプリを移行するを参照してください。
ユーザーが一から始めようとしていて、どちらを望んでいるのか明確でない場合は、確認してください。エージェントでは、管理されたシステムプロンプト、ツール、ナレッジベース、ウィジェット、テレフォニーを利用できます。Realtime API は、OpenAI のリアルタイムイベントにすでに対応しているコードを使う場合に、より手軽な方法です。音声モード以外のエージェント機能(プロンプト、ツール、ワークフロー、ウィジェット)には、agents スキルを使用してください。
モデル
| モデル | モデル ID | 最適化対象 |
|---|---|---|
| Eleven Realtime v1 Mini | eleven_realtime_v1_mini | 最低レイテンシと低コスト。デフォルトです。 |
| Eleven Realtime v1 Max | eleven_realtime_v1_max | 応答前に推論を行うため、複雑な指示や複数ステップのツール使用に適しています。コストは高くなります。 |
まずは Mini をお試しください。作業に長い指示や複雑な指示、複数ステップのツール呼び出しが含まれ、Mini の応答では不十分な場合や、移行対象のアプリが推論を多用する作業でより大型の OpenAI モデルを使用していた場合は、Max を選択してください。エージェントでは、コンプライアンスやデータレジデンシーの制約によって選択肢が限られることがあります。モデルを選択するを参照してください。
Realtime モデルでエージェントを実行する
すべての音声エージェントには Voice モードがあります。Custom モードでは、エージェントの LLM、TTS モデル、ASR 設定を個別に選択します。Realtime モードでは、エージェントが Realtime モデルで動作し、これらの設定は ElevenLabs が管理します。モードは 1 つのフィールドで決まります。conversation_config.realtime_model にモデル ID を設定すると Realtime になり、null を設定すると Custom になります。
システムプロンプト、最初のメッセージ、音声、言語、温度、ツール、ナレッジベース、会話フローの設定(発話ターンの積極性、タイムアウト、中断)は、どちらのモードでも同じように機能します。
始める前に
- これらの手順では ElevenLabs API を呼び出します。CLI と SDK は環境から
ELEVENLABS_API_KEYを読み取ります。設定されていない場合は、setup-api-keyスキルを使用してください。会話内にキーを貼り付けるようユーザーに求めないでください。 - Realtime モデルは段階的に提供されています。API が
realtime_modelに対してRealtime models are not available for this workspace.を返す場合、そのワークスペースではまだ利用できません。作業を中断してユーザーに伝えてください。設定を変更しても解決しません。
ステップ 1:エージェントが Realtime を使用できるか確認する
既存のエージェントの場合は、まず設定を取得します(elevenlabs agents pull --agent <agent-id>、または SDK の agents.get)。エージェントを Custom モードのままにし、次のいずれかに該当する場合は、その理由をユーザーに伝えます。
| 使用上の制約 | 確認する場所 |
|---|---|
| カスタム LLM または Amazon Bedrock | conversation_config.agent.prompt.llm が custom-llm または Bedrock モデルであること |
| Speech Engine など、別の ElevenLabs 製品を通じて作成されたエージェント | 不明な場合はユーザーに確認します。Realtime モデルを使用できるのは ElevenAgents のエージェントのみです |
| 特定の LLM または TTS モデルが必要 | 現在の agent.prompt.llm または tts.model_id が必須かどうか、ユーザーに確認します |
ワークフローノードが管理対象の設定または agent.prompt.max_tokens を上書きする | エージェントの workflow 配下にあるノードの上書き |
| Custom モードのエージェントとの間で転送する | このエージェント、およびこのエージェントへ転送するすべてのエージェントにある transfer_to_agent ツールと agent_transfer ワークフローノード |
| テキスト専用エージェント | conversation_config.conversation.text_only が true であること。Realtime モデルは音声向けに設計されています |
ワークフローの上書きは削除でき、転送先のエージェントも Realtime に切り替えられます。ただし、いずれもセットアップの他の部分の動作を変えるため、ユーザーの同意が必要です。
ステップ 2:モデルを選択する
まず eleven_realtime_v1_mini を使用します。エージェントが長文または複雑な指示に従う場合、複数段階のツール呼び出しに依存していて Mini では不十分な場合、または Zero Retention Mode や HIPAA への準拠が必要な場合は、eleven_realtime_v1_max を選択します。そのうえで、利用可能かどうかを確認します。
| 環境 | eleven_realtime_v1_mini | eleven_realtime_v1_max |
|---|---|---|
| US | 利用可能 | 利用可能 |
| EU データレジデンシー | 利用可能 | 利用可能 |
| India データレジデンシー | 利用可能 | 利用不可 |
| Singapore データレジデンシー | 利用可能 | 利用不可 |
| Zero Retention Mode と HIPAA | 利用不可 | US および EU で利用可能 |
Zero Retention Mode は、ワークスペースで強制されている場合でも、エージェントで有効になっている場合でも適用されます。ワークスペースのデータレジデンシーやコンプライアンス設定がプロジェクトから明確に分からない場合は、ユーザーに確認します。エージェントの環境でどちらのモデルも利用できない場合は、Custom モードのままにします。
Max には、agent.prompt.max_tokens を 1024 以上に設定するか、上限なしにする場合は -1 を設定する必要もあります。
ステップ 3:モデルを設定する
既存のエージェントでは、realtime_model だけを変更し、それ以外の設定はそのままにします。
CLI を使う場合は、エージェントを pull し、agent_configs/ 内のファイルでフィールドを設定してから push します。
elevenlabs agents pull --agent <agent-id>
{
"conversation_config": {
"realtime_model": "eleven_realtime_v1_mini"
}
}
elevenlabs agents push --agent <agent-id>
SDK を使う場合:
from elevenlabs import ElevenLabs
elevenlabs = ElevenLabs()
elevenlabs.conversational_ai.agents.update(
agent_id="<agent-id>",
conversation_config={
"realtime_model": "eleven_realtime_v1_mini",
},
)
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
const elevenlabs = new ElevenLabsClient();
await elevenlabs.conversationalAi.agents.update("<agent-id>", {
conversationConfig: {
realtimeModel: "eleven_realtime_v1_mini",
},
});
新しいエージェントの場合は、agents.create に渡す conversation_config に、プロンプト、最初のメッセージ、音声とともに realtime_model(TypeScript では realtimeModel)を設定します。LLM モデルや TTS モデルは選択しないでください。Realtime エージェントではこれらは無視されます。
Realtime を無効にするには、realtime_model を null(Python では None)に設定します。エージェントは、保存されている LLM、TTS モデル、ASR の設定に戻ります。
管理対象の設定
Realtime モデルが設定されている間、エージェントは conversation_config 内の以下のフィールドに保存された値を無視します。エージェントを Custom に切り替えると再び使用されるため、消去しないでください。また、Realtime エージェントの調整にこれらを編集しないでください。
| 設定 | フィールド |
|---|---|
| LLM | agent.prompt.llm |
| 推論の負荷 | agent.prompt.reasoning_effort |
| 思考バジェット | agent.prompt.thinking_budget |
| 並列ツール呼び出し | agent.prompt.enable_parallel_tool_calls |
| カスケードタイムアウト | agent.prompt.cascade_timeout_seconds |
| TTS モデル | tts.model_id |
| 表現力モード | tts.expressive_mode |
| ASR プロバイダー | asr.provider |
agent.prompt.max_tokens は引き続き適用されます。温度設定も適用されますが、Realtime モードではダッシュボードに表示されないため、CLI または API から変更してください。Realtime モデルでエラーが発生した場合や、時間内に応答しなかった場合、エージェントはバックアップ LLM にフォールバックします(LLM カスケード)。Realtime モデルによって待機時間が決まります。
ステップ 4:公開して確認する
ステップ 1 のルールは、エージェントの下書きを保存したときではなく、公開するときにチェックされます。ルールに違反する下書きは保存できますが、公開時に変更が必要な設定を示すエラーが発生します。
- エージェントを取得し、
conversation_config.realtime_modelに選択したモデルが設定されていることを確認します。push、更新、またはユーザーによるダッシュボードでの公開に失敗した場合は、以下のエラーに照らして確認してください。 - このエージェントに転送するすべてのエージェントを見つけ、それらも Realtime モードになっていることを確認します。Custom モードのエージェントから Realtime エージェントへの転送は、そのエージェントを次に公開するときまで検出されません。それまでは、会話中に転送が拒否され、発信者は現在のエージェントにとどまります。
- ユーザーにテスト会話をしてもらいます。
エラー
| エラー | 原因と対処方法 |
|---|---|
Realtime models are not available for this workspace. | このワークスペースはまだアクセス権がありません。設定で対処できることはありません。 |
Transfers between default and Realtime model modes are not supported. | Custom モードのエージェントとの間で転送しようとしています(「default」は Custom を意味します)。両方のエージェントを同じモードにしてください。 |
| Realtime モデルの名前を示すエラー | エージェントのコンプライアンスまたはデータレジデンシーの設定では、このモデルを利用できません。ステップ 2 を参照してください。 |
| 設定名を示す公開エラー | ステップ 1 の制約事項のいずれか、または Max のトークン上限に該当しています。その設定を変更するか、エージェントを Custom のままにしてください。 |
料金
Realtime エージェントには、標準の ElevenAgents 分単位料金に加えて、入力、キャッシュされた入力、出力の各トークンが Realtime モデルの料金で課金されます。Max は Mini よりもトークンあたりの料金が高くなります。料金を引用するのではなく、ユーザーには https://elevenlabs.io/pricing を案内してください。
OpenAI Realtime からアプリを移行する
ElevenLabs Realtime は OpenAI の GA Realtime API と同じワイヤープロトコルに対応しており、WebSocket 経由で同じクライアントイベントとサーバーイベントを使用します。OpenAI の Realtime SDK で構築されたアプリでは、引き続きその SDK を使用します。移行で変更するのは、認証情報の発行元、トランスポートの接続先 URL、モデル、音声、セッションの設定です。
構造上の変更点は 1 つです。ElevenLabs Realtime は WebSocket 専用です。ブラウザーでは、RealtimeSession はデフォルトで WebRTC を使用し、マイクとスピーカーを自動的に接続します。WebSocket トランスポートに切り替えると、アプリ側で音声の取得と再生を行う必要があります。
この手順は、ブラウザーからリアルタイム接続を開くアプリを対象としています。サーバーが接続を開き、独自のプロトコル(専用の WebSocket リレーや電話接続ブリッジなど)でクライアントに音声をストリーミングするアプリは対象外です。サーバーから ElevenLabs Realtime に接続することはできるはずですが、このスキルにはその手順がありません。その旨をユーザーに伝え、サーバー側の移行方法を推測するのではなく、セットアップの内容を説明して https://github.com/elevenlabs/skills で issue または pull request を作成するよう案内してください。
ステップ 0:アプリの構成を把握する
編集する前に、アプリが OpenAI Realtime を使用している箇所をすべて見つけます。
grep -rnE "api\.openai\.com/v1/realtime|client_secrets|realtime/sessions|@openai/agents-realtime|@openai/agents/realtime|gpt-realtime|gpt-4o(-mini)?-realtime|OpenAIRealtimeWebRTC|OpenAIRealtimeWebSocket|RealtimeSession|OPENAI_API_KEY" --include='*.{ts,tsx,js,jsx,mjs,py}' .
見つかった項目は、それぞれ移行方法が異なるため、次のように分類します。
- 認証情報の発行:
/v1/realtime/client_secrets(GA)または/v1/realtime/sessions(beta)を呼び出すサーバールートです。ステップ 1 で移行します。 - ブラウザーのセッション:
RealtimeSession、OpenAIRealtimeWebRTC、OpenAIRealtimeWebSocket、または独自実装のWebSocket/RTCPeerConnectionです。ステップ 2 から 4 で移行します。 - サーバー側のリアルタイム接続:リレー(独自の WebSocket プロトコルでクライアントに音声をストリーミングするものなど)、電話接続ブリッジ、
openaiPython のclient.realtime.connect()、または完全な API キーを使って Node で実行されるRealtimeSessionなど、リアルタイムソケットを直接開く Node または Python プロセスです。対象外です。上記の対象範囲を確認してください。アプリにブラウザーセッションもある場合は、ユーザーの同意を得たうえで、その部分のみを移行します。 - 音声会話以外の機能:関数ツール、ハンドオフ、ガードレール、MCP サーバー、画像入力、SIP です。ElevenLabs がドキュメント化しているのは音声会話のフローのみです。このコードはそのまま残し、ElevenLabs での動作が未検証であることをユーザーに伝えて、テストしてもらいます。
OPENAI_API_KEY は、ほかの OpenAI 呼び出しにも使われていることがよくあります。ほかに使用箇所がない場合に限り、削除してください。
ステップ 1:ElevenLabs からクライアントシークレットを発行する
ブラウザーから ElevenLabs API キーが見えることはありません。サーバールートで有効期間の短いクライアントシークレットを発行し、その value のみを返します。
| 項目 | OpenAI | ElevenLabs |
|---|---|---|
| URL | POST https://api.openai.com/v1/realtime/client_secrets | POST https://api.elevenlabs.io/v1/convai/realtime/client_secrets |
| 認証ヘッダー | Authorization: Bearer $OPENAI_API_KEY | xi-api-key: $ELEVENLABS_API_KEY |
session.model | gpt-realtime、… | eleven_realtime_v1_mini または eleven_realtime_v1_max |
| レスポンス | { value, expires_at, session } | 同じ形式 |
リクエストボディには GA 形式の { session, expires_after } を使用します。ここで送信するセッション設定が、その認証情報に対する正式な初期セッションです。model 文字列でエージェントの動作を直接選択します。agent_id はありません。
ElevenLabs SDK(npm install @elevenlabs/elevenlabs-js または pip install elevenlabs)を使って発行します。この SDK は xi-api-key ヘッダーを自動で送信します。
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
const elevenlabs = new ElevenLabsClient();
const clientSecret =
await elevenlabs.conversationalAi.realtime.createClientSecret({
session: {
type: "realtime",
model: "eleven_realtime_v1_mini",
instructions:
"You are a helpful, friendly voice assistant. Keep replies concise.",
outputModalities: ["audio"],
audio: {
input: {
format: { type: "audio/pcm", rate: 24000 },
turnDetection: { type: "semantic_vad", eagerness: "medium" },
},
output: {
format: { type: "audio/pcm" },
voice: "brian",
},
},
},
expiresAfter: { anchor: "created_at", seconds: 600 },
});
import os
from elevenlabs import (
CreateClientSecretRequest,
ExpiresAfter,
OpenAiAudioConfigInput,
OpenAiAudioInputConfigInput,
OpenAiAudioInputFormat,
OpenAiAudioOutputConfigInput,
OpenAiAudioOutputFormat,
OpenAiSessionConfigInput,
OpenAiTurnDetection,
)
from elevenlabs.client import ElevenLabs
elevenlabs = ElevenLabs(api_key=os.environ["ELEVENLABS_API_KEY"])
client_secret = elevenlabs.conversational_ai.realtime.create_client_secret(
request=CreateClientSecretRequest(
session=OpenAiSessionConfigInput(
type="realtime",
model="eleven_realtime_v1_mini",
instructions="You are a helpful, friendly voice assistant. Keep replies concise.",
output_modalities=["audio"],
audio=OpenAiAudioConfigInput(
input=OpenAiAudioInputConfigInput(
format=OpenAiAudioInputFormat(type="audio/pcm", rate=24000),
turn_detection=OpenAiTurnDetection(type="semantic_vad", eagerness="medium"),
),
output=OpenAiAudioOutputConfigInput(
format=OpenAiAudioOutputFormat(type="audio/pcm"),
voice="brian",
),
),
),
expires_after=ExpiresAfter(anchor="created_at", seconds=600),
),
)
clientSecret.value(Python では client_secret.value)のみをブラウザーに返します。
既存のフレームワーク、パス、レスポンスの契約は維持し、上流への呼び出しのみを変更してください。アプリがベータ版の /v1/realtime/sessions エンドポイントで発行していた場合、フロントエンドは client_secret.value を読み取ります。フロントエンドでトップレベルの value を読み取るように更新するか、フロントエンドを変更せずに済むよう、ルートから { client_secret: { value } } を返してください。
ステップ 2:セッション設定を GA 形式に変換する
GA 形式のセッションを送信してください。OpenAI のベータ版 API 向けに書かれたアプリでは、フラットなフィールド(modalities、voice、input_audio_format、turn_detection、…)が使われていますが、これらは変換が必要です。また、ElevenLabs は非推奨の modalities フィールドを完全に拒否します。これは発行リクエストのボディや、独自に実装した session.update で特に重要です。SDK の config オプションを使うと、非推奨の camelCase フィールドは GA のワイヤー形式に変換されますが、非推奨警告をなくすため、設定も GA 形式に変更することをおすすめします。
ベータ版から GA へのフィールド対応表、音声の扱い、SDK の config オプションで使用する camelCase 形式については、セッション設定のマッピングを参照してください。
ステップ 3:ブラウザーのセッションを ElevenLabs に接続する
トランスポートを ElevenLabs の URL を指定した OpenAIRealtimeWebSocket に置き換え、セッションにモデルを設定し、発行した value を API キーとして渡します。
import {
OpenAIRealtimeWebSocket,
RealtimeAgent,
RealtimeSession,
} from "@openai/agents-realtime";
const { value: clientSecret } = await fetch("/api/token").then((res) =>
res.json(),
);
const agent = new RealtimeAgent({
name: "Assistant",
instructions:
"You are a helpful, friendly voice assistant. Keep replies concise.",
});
const transport = new OpenAIRealtimeWebSocket({
url: "wss://api.elevenlabs.io/v1/convai/realtime",
});
const session = new RealtimeSession(agent, {
transport,
model: "eleven_realtime_v1_mini",
config: {
outputModalities: ["audio"],
audio: { output: { voice: "brian" } },
},
});
await session.connect({ apiKey: clientSecret });
アプリ既存の RealtimeAgent の名前、指示、イベントハンドラーはそのままにしてください。WebRTC 専用のオプション(audioElement、mediaStream、changePeerConnection)と、transport: "webrtc" の設定は削除してください。これらに WebSocket に対応するものはありません。
ステップ 4:音声を接続する(アプリが WebRTC を使用していた場合)
以前に WebRTC を使用していたアプリ(明示的に OpenAIRealtimeWebRTC や transport: "webrtc" を使用していた場合、またはブラウザーでトランスポートを指定していなかった場合)は、次の対応が必要です。
- マイク音声を 24 kHz の PCM16 でキャプチャし、
session.sendAudio(...)でストリーミングします。 - セッションの
audioイベントから PCM16 チャンクを再生します。 audio_interruptedで再生を停止します。これを行わないと、すでにバッファーに入っている音声が再生され続けるため、ユーザーが割り込んだ後もアシスタントが話し続けます。- クリーンアップ時にマイクを解放し、セッションを閉じます。
wavtools(OpenAI が独自の WebSocket サンプルで使用しているヘルパー)を使った実装例と注意点については、WebSocket 経由のブラウザー音声を参照してください。
すでに OpenAIRealtimeWebSocket を使っているアプリでは、この接続処理は実装済みです。サンプルレートが 24 kHz であることを確認し、そのまま使用してください。
ステップ 5:検証
-
サーバーが
OPENAI_API_KEYをどこから読み込んでいるか(.env、.env.local、デプロイ時のシークレット)を確認し、ユーザーにELEVENLABS_API_KEYをそこに保存するよう依頼します。会話でキーを尋ねたり、自分でファイルに書き込んだりしないでください。プロジェクトに.env.exampleがあれば、空のELEVENLABS_API_KEY=を追加します。 -
ユーザーがキーを設定したことを確認したら、アプリを実行し、会話を開始して、音声を再生します。
-
session.createdトランスポートイベントで、eleven_realtime_*モデルと選択した音声が報告されることを確認します。session.on("transport_event", (event) => { if (event.type === "session.created") console.log(event); }); -
アシスタントの発話中に割り込み、再生が停止することを確認します。
-
ステップ 0 の機能のうち、未検証のもの(ツール、ハンドオフ、ガードレールなど)をユーザーに伝えます。
トラブルシューティング
| 症状 | 原因と対処 |
|---|---|
WebSocket がコード 4003 で閉じる | この ElevenLabs ワークスペースでは Realtime が有効になっていません。ElevenLabs に問い合わせてください。このコードでは対処できません。 |
WebSocket がコード 4001 で閉じる | クライアントシークレットが拒否されました。有効期限切れか、session.connect() の apiKey に渡した発行済みの value ではありません。 |
| Mint が 401 を返す | まだ Authorization: Bearer を送信しています。ElevenLabs では xi-api-key ヘッダーを使用します。 |
Mint または session.update が拒否される | modalities などのベータ版形式のフィールドが原因です。マッピングに従って変換してください。 |
| 接続できるが、どちらからも音声が聞こえない | アプリが WebRTC を使用していましたが、音声はまだ接続されていません。ステップ 4 を参照してください。 |
| 音声にノイズが入る、異常に速くなる、または遅くなる | サンプルレートまたはバッファーの不一致です。24 kHz で録音・再生してください。音声リファレンスの注意事項を参照してください。 |
| 割り込み後もアシスタントがユーザーの発話に重ねて話す | audio_interrupted で再生が停止されていません。 |