Créez un agent vocal en 20 minutes avec ElevenLabs et Twilio
- Publié
- Dernière mise à jour
ÉcouterÉcouter cet article
Un agent vocal peut répondre aux appels téléphoniques entrants, transcrire les interlocuteurs en temps réel avec le Speech to Text (STT), générer une réponse avec un grand modèle de langage (LLM) et répondre oralement avec un module de Text to Speech (TTS). Avec ElevenLabs et Twilio, vous pouvez mettre en service un agent sur un véritable numéro de téléphone en environ 20 minutes.
Pour les développeurs, la stack complète utilise ElevenLabs pour la synthèse vocale (Flash v2.5) et la transcription (Scribe v2 Realtime), Twilio pour la téléphonie, et OpenAI ou un autre fournisseur pour le LLM. Ces composants sont interchangeables : choisissez ceux que vous maîtrisez le mieux.
Cet article explique comment créer un agent vocal en 20 minutes avec Node.js et TypeScript. Si vous préférez une solution managée qui gère les tours de parole, les interruptions et la téléphonie sans que vous ayez à maintenir la cascade, découvrez ElevenAgents.
Fonctionnement de l’architecture d’un agent vocal
Avant d’écrire du code, il est utile de comprendre comment les trois services de votre stack technique s’articulent.
- Twilio : gère l’appel téléphonique et le transport audio.
- ElevenLabs : gère le STT avec Scribe v2 Realtime et le TTS avec Flash v2.5.
- LLM : gère l’appel d’outils et la rédaction de la réponse.
Chaque étape est un adaptateur léger. Vous pouvez donc remplacer un service sans modifier le reste. Vous pouvez par exemple remplacer le LLM OpenAI par un autre fournisseur sans réécrire les autres composants.
Un appel téléphonique atteint votre serveur via Twilio. Twilio répond à l’appel PSTN, ouvre un WebSocket vers votre serveur et transfère l’audio de l’appelant sous forme de flux de trames mu-law encodées en base64. Votre serveur exécute la cascade et renvoie l’audio synthétisé via ce même WebSocket ; Twilio le lit à l’appelant.

Voici le flux que vous utiliserez pour créer un agent vocal :
Un appelant compose votre numéro Twilio. Twilio récupère un document TwiML depuis votre webhook. Le TwiML indique à Twilio d’ouvrir un Media Stream vers votre endpoint WebSocket. Twilio transmet l’audio entrant sous forme d’événements JSON contenant des payloads mu-law (ulaw_8000) encodés en base64.
Votre serveur transfère les fragments audio vers Scribe v2 Realtime pour une transcription en continu. Lorsqu’un tour de parole de l’appelant est finalisé, vous envoyez la transcription au LLM, puis synthétisez la réponse avec Flash v2.5 en ulaw_8000. Vous renvoyez les trames mu-law synthétisées à Twilio via le WebSocket, encodées en base64, puis Twilio les lit à l’appelant.
Scribe v2 Realtime produit des transcriptions partielles avec une latence d’environ 150 ms, et Flash v2.5 effectue l’inférence du modèle en environ 75 ms, hors latence réseau et applicative. Le LLM contribue le plus au délai avant le premier audio, et de la manière la moins prévisible. Pour réduire ce délai, nous diffusons la sortie du LLM jeton par jeton et lançons la synthèse avant que le modèle ait terminé sa phrase.
Pour comprendre les compromis entre modèles qui motivent ces choix, consultez la vue d’ensemble des modèles et l’explication pour comprendre la latence.
Ce dont vous avez besoin avant de créer un agent vocal
Ce guide suppose que vous disposez de quatre éléments. Ils sont rapides à configurer, mais l’absence de l’un d’eux empêchera le serveur de fonctionner.
Voici les prérequis à vérifier :
- Un numéro Twilio compatible Voice : notez ce numéro, ainsi que votre Account SID et votre Auth Token dans la console Twilio.
- Clé API ElevenLabs : créez-la dans votre Dashboard ElevenLabs. Elle est transmise dans l’en-tête xi-api-key et est secrète ; conservez-la uniquement côté serveur. Consultez l’authentification API.
- Clé API LLM : ce tutoriel considère OpenAI et un autre fournisseur comme des backends interchangeables ; choisissez-en un.
- Ngrok (ou tout autre tunnel) pour le développement local : Twilio doit atteindre votre serveur via une URL HTTPS et WSS publique, ce que ngrok permet sans déploiement.
Définissez vos secrets comme variables d’environnement et ne les validez jamais dans votre dépôt.
Démarrez ensuite un tunnel vers le port utilisé par votre serveur :
Comprendre le protocole Twilio Media Streams
Twilio ne vous fournit pas de socket audio brut. Il encapsule tout dans un protocole JSON structuré via WebSocket. Comprendre les quatre types d’événements et le format d’envoi vous permettra de saisir pleinement le gestionnaire WebSocket de l’étape 2 avant de l’écrire.
Une fois Twilio connecté à votre WebSocket, il envoie une suite de messages texte JSON pouvant appartenir à quatre types d’événements.
L’événement connected arrive en premier et confirme que le WebSocket est actif. L’événement start est envoyé une seule fois au début du flux média ; il contient un streamSid que vous devez stocker pour renvoyer l’audio, ainsi que des métadonnées d’appel dans start.customParameters et start.callSid.
L’événement media est récurrent : media.payload est un fragment d’audio mu-law à 8 kHz encodé en base64, de 20 ms par trame, et media.track vaut inbound pour l’audio de l’appelant. Enfin, stop est envoyé lorsque le flux se termine, généralement parce que l’appel a raccroché.
Pour lire de l’audio en retour, envoyez un message de type media avec le même streamSid et un payload mu-law encodé en base64. Pour interrompre de l’audio déjà mis en file d’attente, envoyez un message clear avec le streamSid, ce qui vide le tampon sortant de Twilio.
Les encodages entrant et sortant sont identiques (ulaw_8000). Nous demandons ulaw_8000 à ElevenLabs Text to Speech et transférons les octets directement à Twilio, sans rééchantillonnage intermédiaire.
Étape 1 : Servir le webhook TwiML
Lorsqu’un appel arrive, Twilio envoie une requête HTTP à votre webhook, auquel vous répondez avec du TwiML connectant l’appel à votre Media Stream. Le verbe <Connect><Stream> ouvre un WebSocket bidirectionnel. Utilisez ici <Connect> plutôt que <Start> : il maintient l’appel pendant toute la durée du flux et vous permet de renvoyer de l’audio, ce qui est l’objectif de cette configuration.
Le TwiML renvoyé par le webhook est :
Dans Express, il suffit d’un gestionnaire POST qui renseigne l’hôte et renvoie le document :
Dans la console Twilio, configurez le webhook « A call comes in » du numéro sur https://your-subdomain.ngrok.app/incoming-call avec la méthode HTTP POST.
Étape 2 : Accepter le WebSocket Media Stream
Le gestionnaire WebSocket lit les événements Twilio, exécute la cascade et renvoie l’audio.
Nous conservons un petit état par appel : le streamSid, une connexion STT et un indicateur précisant si l’agent parle actuellement. Le gestionnaire décode chaque trame média entrante depuis le base64 et transfère les octets mu-law bruts au STT :
Étape 3 : Transcrire avec Scribe v2 Realtime
Scribe v2 Realtime accepte des fragments audio en continu et renvoie des transcriptions partielles et finales. Il prend directement en charge l’encodage mu-law ; nous lui transmettons donc les trames Twilio sans les modifier.
Il propose aussi la détection d’activité vocale pour la segmentation fondée sur le silence, ainsi qu’un contrôle de validation manuelle pour finaliser un segment. Pour un agent téléphonique, la segmentation pilotée par VAD est généralement le bon choix : une pause naturelle est le signal le plus fiable indiquant qu’un tour de parole est terminé.
Voici les étapes : ouvrez un flux STT au début de l’appel. Envoyez chaque fragment mu-law entrant. Réagissez aux transcriptions finalisées en appelant le LLM.
L’interface client du STT en temps réel évolue encore. La forme ci-dessous est donc isolée derrière un petit adaptateur TypeScript (openRealtimeStt), que vous implémentez avec l’API active plutôt qu’avec un ensemble figé de noms de champs. Considérez onFinal comme le hook qui transmet un tour de parole terminé à l’étape suivante.
La latence de reconnaissance en temps réel est d’environ 150 ms pour les résultats partiels, ce qui réduit le délai perçu entre la fin de parole de l’appelant et le début de réponse de l’agent. Pour l’équivalent par lot et l’ensemble complet des fonctionnalités, consultez la documentation Speech to Text et la page produit Speech to Text en temps réel.
Étape 4 : Générer une réponse avec un LLM
C’est l’étape qui produit la réponse. Le LLM reçoit l’historique de conversation et renvoie le texte de l’assistant. Diffusez la réponse en continu pour pouvoir commencer la synthèse dès la première phrase.
Ici, elle s’appuie sur OpenAI :
L’ID de modèle ci-dessus, gpt-4.1-mini, est un exemple de choix à faible latence ; une autre option de fournisseur offre des performances comparables. Chaque fournisseur peut respecter le même contrat llmReply : remplacez le corps de la fonction, et le reste de l’agent reste inchangé.
Le prompt système limite la longueur des réponses, ce qui est important au téléphone : les réponses longues semblent lentes et sont difficiles à interrompre naturellement.
Étape 5 : Synthétiser avec Flash TTS en ulaw_8000
Le texte doit maintenant devenir un audio que Twilio peut lire. Demandez Flash v2.5 avec outputFormat: "ulaw_8000" afin que les octets correspondent à l’encodage attendu par Twilio, puis diffusez l’audio et renvoyez chaque fragment par le WebSocket sous forme d’événement media.
Accumulez les jetons du LLM en fragments de la taille d’une phrase et synthétisez chaque fragment dès qu’il est terminé, au lieu d’attendre la réponse entière. Cela réduit le délai avant le premier audio : l’appelant entend la première phrase pendant que le modèle produit encore la seconde. Pour contrôler plus finement la synthèse incrémentale, le guide WebSocket TTS en temps réel explique comment envoyer du texte vers un unique socket de synthèse ouvert ; l’approche HTTP en continu ci-dessous est plus simple et suffisante pour de courts tours conversationnels.
Renforcer votre agent vocal IA pour la production
Après les cinq étapes ci-dessus, vous disposez d’un agent fonctionnel. Cela ne correspond pas encore à un déploiement en production.
Plusieurs aspects doivent être pris en compte avant de mettre l’agent sur une véritable ligne téléphonique.
Valider les signatures des webhooks Twilio
Toute personne connaissant l’URL de votre webhook peut lui envoyer une requête POST. La première étape consiste donc à vérifier que la requête vient bien de Twilio. Twilio signe chaque requête avec votre Auth Token dans l’en-tête X-Twilio-Signature ; rejetez toute requête dont la validation échoue. La signature est calculée sur l’URL complète et les paramètres POST : vous devez donc la calculer de la même manière que Twilio.
L’utilitaire Twilio s’en charge pour vous :
Gérer correctement les secrets
Conservez ELEVENLABS_API_KEY, la clé du LLM et TWILIO_AUTH_TOKEN dans un gestionnaire de secrets, et non dans le code source ni dans des fichiers d’environnement en texte brut validés dans un dépôt. Limitez la clé ElevenLabs aux seuls endpoints requis par ce service et attribuez-lui un quota de crédits afin de limiter l’impact d’une fuite.
Les offres Enterprise peuvent également limiter une clé à des plages d’adresses IP précises via une liste blanche d’IP. Ce serveur utilise directement la clé API, car elle ne quitte jamais votre backend ; si une logique audio était déplacée vers un navigateur ou un client mobile, utilisez des jetons à usage unique afin que la clé ne soit jamais exposée côté client.
Comprendre la limite de requêtes simultanées
Chaque offre possède une limite de requêtes simultanées, différente selon la famille de modèles. Elle comptabilise le nombre de requêtes qui génèrent activement de l’audio au même moment.
Pour un agent téléphonique, ce mode de calcul joue en votre faveur. La génération audio est plus rapide que la lecture : chaque appel ne consomme donc des requêtes simultanées TTS que pendant les courtes périodes de synthèse d’une réponse, et non pendant toute la durée de l’appel. À titre indicatif, une limite d’environ cinq requêtes simultanées peut prendre en charge de l’ordre de 100 appels conversationnels simultanés, car la génération se termine bien avant la lecture.
Surveillez néanmoins la marge disponible au lieu de l’estimer. Les réponses ElevenLabs exposent les en-têtes current-concurrent-requests et maximum-concurrent-requests ; consignez-les et déclenchez une alerte à l’approche du maximum. Lorsque vous dépassez la limite, les requêtes sont mises en file d’attente par priorité, ce qui ajoute généralement environ 50 ms ; une surcharge persistante renvoie une erreur HTTP 429.
Gérez les réponses HTTP 429 avec un court délai d’attente. Si elles persistent, augmentez les limites en effectuant un upgrade sur la page des tarifs ou, pour les clients Enterprise, en passant par votre gestionnaire de compte.
Gérer les interruptions et la prise de parole
Un appelant qui commence à parler pendant que l’agent parle s’attend à ce que l’agent s’arrête. Il s’agit d’une interruption, et sa bonne gestion est essentielle pour que l’agent paraisse naturel plutôt que scripté.
Détectez la parole de l’appelant pendant la lecture de l’agent avec le signal VAD du STT. Lorsque vous la détectez, effectuez deux actions. D’abord, arrêtez de transmettre les fragments TTS : l’indicateur agentSpeaking dans speak le fait déjà en interrompant la boucle. Ensuite, envoyez à Twilio un message clear pour vider l’audio déjà mis en file d’attente de son côté.
Sans clear, Twilio continue à lire l’audio mis en mémoire tampon après l’arrêt de l’envoi ; l’agent semble alors parler par-dessus l’appelant.
Journaliser, surveiller et échouer proprement
Instrumentez chaque étape pour pouvoir attribuer la latence lorsqu’un appel semble lent. Mesurez le délai entre la transcription finale et le premier jeton du LLM, entre le premier jeton du LLM et le premier octet TTS, puis entre le premier octet TTS et la trame envoyée à Twilio. La majeure partie de la latence variable se situe dans l’étape LLM ; les étapes STT et TTS sont comparativement stables.
Prévoyez ensuite les défaillances partielles. Le LLM peut expirer, le flux STT peut être interrompu, et l’aller-retour réseau vers ElevenLabs varie d’environ 20 à 200 ms sur l’Internet public selon la région. Hébergez votre serveur près de vos appelants, pas uniquement près d’ElevenLabs, car ElevenLabs achemine déjà les requêtes vers le plus proche de ses clusters d’Amérique du Nord, d’Europe et d’Asie du Sud-Est.
Lorsqu’une étape échoue, ne laissez pas l’appelant dans le silence : synthétisez une courte phrase de secours (« Désolé, pouvez-vous répéter ? ») et maintenez l’appel actif. Encapsulez chaque étape dans un délai d’expiration et un try/catch afin qu’un tour de parole échoué ne ferme pas tout le WebSocket.
Quelques paramètres par défaut supplémentaires méritent d’être définis avant le déploiement :
- Limitez la longueur des réponses dans le prompt système, comme indiqué, afin que les tours restent courts et interruptibles.
- Limitez l’historique de conversation pour que les appels longs n’augmentent pas indéfiniment le contexte du LLM.
- Définissez une durée maximale d’appel pour éviter que des sessions bloquées ne consomment silencieusement des requêtes simultanées.
Pour continuer à optimiser les éléments que vous contrôlez, la documentation sur la latence explique l’origine du délai avant le premier audio, la vue d’ensemble des modèles couvre les compromis entre vitesse et qualité, et le guide WebSocket TTS en temps réel montre comment réduire davantage la latence de synthèse grâce à une entrée de texte incrémentale.
Créer des agents vocaux prêts pour la production avec ElevenAPI
Après ces 20 minutes, vous disposez de chaque couche d’un agent vocal prêt pour la production. Twilio gère la téléphonie, Scribe v2 Realtime transcrit, un LLM génère les réponses et Flash v2.5 répond via le même WebSocket.
Si vous préférez ne pas maintenir vous-même la cascade, ElevenAgents offre, sous forme de service managé, la gestion des tours de parole, des interruptions et l’intégration téléphonique, sur les mêmes modèles que vous venez d’assembler manuellement.
Pour continuer à optimiser une stack que vous contrôlez, consultez la page produit ElevenAPI pour les offres, les limites de requêtes simultanées et la Voice Library. Vous pouvez aussi vous inscrire et commencer dès aujourd’hui à effectuer votre premier appel.



