ElevenLabs Realtime
Les modèles Realtime sont des modèles ElevenLabs conçus pour la conversation vocale à faible latence. Il y a deux façons de les utiliser :
- Un agent ElevenAgents (un ID d'agent, le dashboard, ou un projet
elevenlabs agentsavecagent_configs/) : réglez le Voice mode de l'agent sur Realtime avecconversation_config.realtime_model, et ElevenLabs gère son LLM, son modèle TTS et ses paramètres ASR. Voir Run an agent on a Realtime model. - Une application web construite sur le Realtime SDK d'OpenAI : conservez le SDK et pointez-le vers l'API ElevenLabs Realtime compatible OpenAI,
wss://api.elevenlabs.io/v1/convai/realtime. Voir Migrate an app from OpenAI Realtime.
Quand l'utilisateur démarre de zéro et qu'il n'est pas clair ce qu'il souhaite, demandez. Un agent fournit un system prompt géré, des outils, une base de connaissances, un widget et la téléphonie ; l'API Realtime est le chemin le plus rapide pour du code qui parle déjà les événements realtime d'OpenAI. Pour les fonctionnalités d'agent au-delà du voice mode (prompt, outils, workflows, widget), utilisez la skill agents.
Models
| Model | Model ID | Optimized for |
|---|---|---|
| Eleven Realtime v1 Mini | eleven_realtime_v1_mini |
Latence et coût les plus bas. C'est le modèle par défaut. |
| Eleven Realtime v1 Max | eleven_realtime_v1_max |
Raisonne avant de répondre, pour les instructions complexes et l'utilisation d'outils multi-étapes. Coûte plus cher. |
Commencez avec Mini. Choisissez Max quand le travail implique des instructions longues ou complexes ou des appels d'outils multi-étapes et que les réponses de Mini ne sont pas assez bonnes, ou quand une application en migration provenait d'un modèle OpenAI plus grand pour un travail lourd en raisonnement. Les agents ajoutent des contraintes de conformité et de résidence des données au choix ; voir Choose the model.
Run an agent on a Realtime model
Chaque agent vocal a un Voice mode. En mode Custom, le LLM, le modèle TTS et les paramètres ASR de l'agent sont choisis individuellement. En mode Realtime, l'agent s'exécute sur un modèle Realtime et ElevenLabs gère ces paramètres. Le mode est un seul champ : conversation_config.realtime_model défini sur un ID de modèle signifie Realtime, null signifie Custom.
Le system prompt, le premier message, la voix, les langues, la température, les outils, la base de connaissances et les paramètres de flux de conversation (tour eagerness, timeouts, interruptions) fonctionnent de la même façon dans les deux modes.
Before you start
- Ces étapes appellent l'API ElevenLabs. Le CLI et les SDKs lisent
ELEVENLABS_API_KEYdepuis l'environnement ; si elle n'est pas définie, utilisez la skillsetup-api-key. Ne demandez jamais à l'utilisateur de coller la clé dans la conversation. - Les modèles Realtime se déploient progressivement. Si l'API rejette
realtime_modelavecRealtime models are not available for this workspace., l'espace de travail n'a pas encore accès. Arrêtez-vous et informez l'utilisateur ; aucun changement de configuration ne le résout.
Step 1: Check the agent can use Realtime
Pour un agent existant, récupérez d'abord sa configuration (elevenlabs agents pull --agent <agent-id>, ou agents.get dans le SDK). Gardez l'agent en mode Custom, et expliquez à l'utilisateur pourquoi, si l'un de ces cas s'applique :
| Blocker | Where to look |
|---|---|
| LLM personnalisé ou Amazon Bedrock | conversation_config.agent.prompt.llm est custom-llm ou un modèle Bedrock |
| Créé via un autre produit ElevenLabs, tel que Speech Engine | Demandez à l'utilisateur en cas de doute ; seuls les agents ElevenAgents peuvent utiliser un modèle Realtime |
| Nécessite un LLM ou un modèle TTS spécifique | Demandez à l'utilisateur si le agent.prompt.llm ou tts.model_id actuel est une exigence |
Les nœuds de workflow remplacent un managed setting ou agent.prompt.max_tokens |
Remplacements sur les nœuds sous le workflow de l'agent |
| Transferts vers ou depuis des agents en mode Custom | Outils transfer_to_agent et nœuds de workflow agent_transfer sur cet agent et sur tout agent qui transfère vers celui-ci |
| Agent texte uniquement | conversation_config.conversation.text_only est true ; les modèles Realtime sont conçus pour la voix |
Un remplacement de workflow peut être supprimé et un partenaire de transfert peut aussi basculer vers Realtime, mais seulement avec l'accord de l'utilisateur : les deux changent la façon dont d'autres parties de leur configuration se comportent.
Step 2: Choose the model
Commencez avec eleven_realtime_v1_mini. Choisissez eleven_realtime_v1_max quand l'agent suit des instructions longues ou complexes ou repose sur des appels d'outils multi-étapes et que Mini n'est pas assez bon, ou quand l'agent doit se conformer au Mode de rétention zéro ou à HIPAA. Ensuite, vérifiez la disponibilité :
| Environment | eleven_realtime_v1_mini |
eleven_realtime_v1_max |
|---|---|---|
| US | Available | Available |
| EU data residency | Available | Available |
| India data residency | Available | Not available |
| Singapore data residency | Available | Not available |
| Zero Retention Mode and HIPAA | Not available | Available in the US and EU |
Le Mode de rétention zéro s'applique qu'il soit appliqué sur l'espace de travail ou activé sur l'agent. Demandez à l'utilisateur quand la résidence des données ou les paramètres de conformité de l'espace de travail ne sont pas clairs à partir du projet. Si aucun modèle n'est disponible pour l'environnement de l'agent, gardez-le en mode Custom.
Max nécessite aussi agent.prompt.max_tokens d'au moins 1024, ou -1 pour pas de limite.
Step 3: Set the model
Sur un agent existant, changez uniquement realtime_model ; laissez le reste de la configuration inchangé.
Avec le CLI, tirez l'agent, réglez le champ dans son fichier sous agent_configs/, et poussez :
elevenlabs agents pull --agent <agent-id>
{
"conversation_config": {
"realtime_model": "eleven_realtime_v1_mini"
}
}
elevenlabs agents push --agent <agent-id>
Avec les SDKs :
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",
},
});
Pour un nouvel agent, mettez realtime_model (realtimeModel en TypeScript) dans le conversation_config passé à agents.create, à côté du prompt, du premier message et de la voix. Ne sélectionnez pas de LLM ou de modèle TTS pour lui ; un agent Realtime les ignore.
Pour désactiver Realtime, réglez realtime_model sur null (None en Python). L'agent revient aux paramètres LLM, TTS et ASR stockés sur lui.
Managed settings
Pendant qu'un modèle Realtime est défini, l'agent ignore les valeurs stockées de ces champs dans conversation_config. Elles reviendront en usage quand l'agent basculera vers Custom, donc ne les effacez pas, et ne les éditez pas pour affiner un agent Realtime :
| Setting | Field |
|---|---|
| LLM | agent.prompt.llm |
| Reasoning effort | agent.prompt.reasoning_effort |
| Thinking budget | agent.prompt.thinking_budget |
| Parallel tool calls | agent.prompt.enable_parallel_tool_calls |
| Cascade timeout | agent.prompt.cascade_timeout_seconds |
| TTS model | tts.model_id |
| Expressive mode | tts.expressive_mode |
| ASR provider | asr.provider |
agent.prompt.max_tokens continue de s'appliquer. La température aussi, mais le dashboard la masque en mode Realtime, donc changez-la via le CLI ou l'API. Si le modèle Realtime erreur ou ne répond pas à temps, l'agent bascule sur ses LLMs de secours (LLM cascading) ; le modèle Realtime définit combien de temps il attend.
Step 4: Publish and verify
Les règles de l'étape 1 sont vérifiées quand l'agent est publié, pas quand un brouillon est sauvegardé : un brouillon qui en viole une se sauvegarde, puis la publication échoue avec une erreur nommant le paramètre à changer.
- Récupérez l'agent et confirmez que
conversation_config.realtime_modelcontient le modèle choisi. Si la poussée, la mise à jour, ou la publication par l'utilisateur dans le dashboard échouent, comparez l'erreur ci-dessous. - Trouvez tous les agents qui transfèrent vers celui-ci et confirmez qu'ils sont aussi en mode Realtime. Un transfert d'un agent en mode Custom vers un agent Realtime n'est détecté que quand cet agent est publié à nouveau ; jusqu'alors le transfert est rejeté au milieu de la conversation et l'appelant reste avec l'agent actuel.
- Faites tenir à l'utilisateur une conversation de test.
Errors
| Error | Cause and fix |
|---|---|
Realtime models are not available for this workspace. |
L'espace de travail n'a pas encore accès. Rien à fixer dans la configuration. |
Transfers between default and Realtime model modes are not supported. |
Un transfert vers ou depuis un agent en mode Custom (« default » signifie Custom). Mettez les deux agents dans le même mode. |
| Une erreur nommant le modèle Realtime | Le modèle n'est pas disponible sous les paramètres de conformité ou de résidence des données de l'agent. Voir étape 2. |
| La publication échoue en nommant un paramètre | L'un des blockers de l'étape 1 ou la limite de tokens de Max. Changez ce paramètre, ou gardez l'agent en Custom. |
Pricing
Un agent Realtime est facturé au tarif standard par minute d'ElevenAgents plus ses jetons d'entrée, d'entrée en cache et de sortie aux tarifs du modèle Realtime ; Max coûte plus cher par token que Mini. Pointez l'utilisateur vers https://elevenlabs.io/pricing plutôt que de citer les tarifs.
Migrate an app from OpenAI Realtime
ElevenLabs Realtime parle le même protocole filaire que l'API Realtime GA d'OpenAI : les mêmes événements client et serveur sur WebSocket. Une application construite sur le Realtime SDK d'OpenAI garde ce SDK ; la migration change où les credentials sont créés, l'URL à laquelle le transport se connecte, et la configuration du modèle, de la voix et de la session.
Le seul changement structurel : ElevenLabs Realtime est WebSocket uniquement. Dans un navigateur, RealtimeSession utilise par défaut WebRTC, qui câble le microphone et le haut-parleur pour vous. Après basculage au transport WebSocket, l'application doit capturer et lire l'audio elle-même.
Ceci couvre les applications où le navigateur ouvre la connexion realtime. Cela ne couvre pas les applications où un serveur ouvre la connexion et diffuse l'audio à ses clients sur son propre protocole, comme un relais WebSocket personnalisé ou un pont téléphonique. La connexion à ElevenLabs Realtime depuis un serveur devrait fonctionner, mais cette skill n'a pas d'étapes pour cela. Dites-le à l'utilisateur, et suggérez-lui d'ouvrir un problème ou une pull request à https://github.com/elevenlabs/skills décrivant leur configuration, plutôt que de deviner la migration côté serveur.
Step 0: Inventory the app
Trouvez chaque place où l'application touche OpenAI Realtime avant d'éditer quoi que ce soit :
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}' .
Classez ce que vous trouvez, car chaque partie se migre différemment :
- Credential minting : une route serveur qui appelle
/v1/realtime/client_secrets(GA) ou/v1/realtime/sessions(beta). Migrez à l'étape 1. - Browser session :
RealtimeSession,OpenAIRealtimeWebRTC,OpenAIRealtimeWebSocket, ou unWebSocket/RTCPeerConnectionfait à la main. Migrez aux étapes 2 à 4. - Server-side realtime connections : un processus Node ou Python qui ouvre lui-même le socket realtime, par exemple un relais qui diffuse l'audio aux clients sur son propre protocole WebSocket, un pont téléphonique,
openaiPython'sclient.realtime.connect(), ou unRealtimeSessionfonctionnant dans Node avec une clé API complète. Non couvert ; voir la portée ci-dessus. Si l'application a aussi une session navigateur, migrez uniquement cette partie, et seulement avec l'accord de l'utilisateur. - Fonctionnalités au-delà d'une conversation vocale : function tools, handoffs, guardrails, serveurs MCP, image input, SIP. ElevenLabs documente uniquement le flux de conversation vocale. Laissez ce code en place, listez-le pour l'utilisateur comme non vérifié par rapport à ElevenLabs, et faites-le tester.
OPENAI_API_KEY sert souvent aussi d'autres appels OpenAI. Ne le supprimez que si rien d'autre ne l'utilise.
Step 1: Mint the client secret from ElevenLabs
Le navigateur ne voit jamais la clé API ElevenLabs. Une route serveur crée un client secret à courte durée de vie et retourne uniquement sa value.
| What | OpenAI | ElevenLabs |
|---|---|---|
| URL | POST https://api.openai.com/v1/realtime/client_secrets |
POST https://api.elevenlabs.io/v1/convai/realtime/client_secrets |
| Auth header | Authorization: Bearer $OPENAI_API_KEY |
xi-api-key: $ELEVENLABS_API_KEY |
session.model |
gpt-realtime, … |
eleven_realtime_v1_mini ou eleven_realtime_v1_max |
| Response | { value, expires_at, session } |
Même structure |
Le corps de la requête garde la structure GA, { session, expires_after }. La configuration de session envoyée ici est la session initiale autorisée pour cette credential. La chaîne model sélectionne directement le comportement de l'agent ; il n'y a pas d'agent_id.
Créez avec le SDK ElevenLabs (npm install @elevenlabs/elevenlabs-js ou pip install elevenlabs), qui envoie l'en-tête xi-api-key pour vous :
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),
),
)
Retournez uniquement clientSecret.value (client_secret.value en Python) au navigateur.
Conservez le framework, le chemin et le contrat de réponse existants de la route ; seul l'appel en amont change. Si l'application a créé avec l'endpoint beta /v1/realtime/sessions, son frontend lit client_secret.value. Soit mettez à jour le frontend pour lire le value de niveau supérieur, soit faites la route retourner { client_secret: { value } } pour que le frontend reste inchangé.
Step 2: Convert the session config to the GA shape
Envoyez la structure de session GA. Les applications écrites contre l'API beta d'OpenAI utilisent des champs plats (modalities, voice, input_audio_format, turn_detection, …) qui doivent être convertis, et ElevenLabs rejette purement et simplement le champ déprécié modalities. Cela importe surtout pour le corps de la requête de mint et tout session.update fait à la main : l'option config du SDK convertit les champs camelCase dépréciés à la structure filaire GA pour vous, bien que le déplacer à la forme GA aussi supprime les avertissements de dépréciation.
Lisez Session config mapping pour la table complète des champs beta-to-GA, la gestion des voix, et la forme camelCase que l'option config du SDK utilise.
Step 3: Point the browser session at ElevenLabs
Remplacez le transport par OpenAIRealtimeWebSocket visé sur l'URL ElevenLabs, réglez le modèle sur la session, et passez le value créé comme clé 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 });
Conservez le nom RealtimeAgent existant de l'application, les instructions et les gestionnaires d'événements. Supprimez les options WebRTC uniquement (audioElement, mediaStream, changePeerConnection) et tout paramètre transport: "webrtc" ; ils n'ont pas d'équivalent WebSocket.
Step 4: Wire up audio (when the app was on WebRTC)
Si l'application utilisait auparavant WebRTC (un OpenAIRealtimeWebRTC explicite, transport: "webrtc", ou pas de transport du tout dans un navigateur), elle doit maintenant :
- Capturer l'audio du microphone en PCM16 à 24 kHz et le diffuser avec
session.sendAudio(...). - Lire les chunks PCM16 depuis l'événement
audiode la session. - Arrêter la lecture sur
audio_interrupted. Sans cela, l'assistant continue à parler par-dessus l'utilisateur après une interruption, car l'audio déjà mis en buffer continue à jouer. - Libérer le microphone et fermer la session au démontage.
Lisez Browser audio over WebSocket pour une implémentation qui fonctionne avec wavtools, l'assistant qu'OpenAI utilise dans ses propres exemples WebSocket, et ses pièges.
Les applications déjà sur OpenAIRealtimeWebSocket ont ce câblage ; vérifiez que le taux d'échantillonnage est 24 kHz et conservez-le.
Step 5: Verify
-
Trouvez où le serveur charge
OPENAI_API_KEY(.env,.env.local, secrets de déploiement) et demandez à l'utilisateur de stockerELEVENLABS_API_KEYlà. Ne demandez pas la clé dans la conversation et ne l'écrivez pas vous-même dans un fichier. Ajoutez unELEVENLABS_API_KEY=vide à.env.examplesi le projet en a un. -
Une fois que l'utilisateur confirme que la clé est en place, exécutez l'application, démarrez une conversation et parlez.
-
Confirmez que l'événement de transport
session.createdrapporte le modèleeleven_realtime_*et la voix choisie :session.on("transport_event", (event) => { if (event.type === "session.created") console.log(event); }); -
Interrompez l'assistant au milieu d'une phrase et confirmez que la lecture s'arrête.
-
Dites à l'utilisateur quelles fonctionnalités de l'étape 0 restent non vérifiées (outils, handoffs, guardrails, …).
Troubleshooting
| Symptom | Cause and fix |
|---|---|
WebSocket ferme avec le code 4003 |
Realtime n'est pas activé pour cet espace de travail ElevenLabs. Contactez ElevenLabs ; le code ne peut pas le fixer. |
WebSocket ferme avec le code 4001 |
Client secret rejeté : expiré, ou pas le value créé passé comme apiKey à session.connect(). |
| Mint retourne 401 | Toujours envoyer Authorization: Bearer ; ElevenLabs utilise l'en-tête xi-api-key. |
Mint ou session.update est rejeté |
Champs en forme beta comme modalities. Convertissez avec le mapping. |
| Se connecte, mais pas d'audio de part et d'autre | L'application était sur WebRTC et l'audio n'est pas encore câblé. Voir étape 4. |
| L'audio est du bruit, chipmunk-rapide, ou ralenti | Mésappariement du taux d'échantillonnage ou du buffer. Capturez et jouez à 24 kHz ; voir les pièges dans la référence audio. |
| L'assistant parle par-dessus l'utilisateur après une interruption | La lecture n'est pas arrêtée sur audio_interrupted. |