Intégration LLM personnalisée
Intégration LLM personnalisée
Alimentez un agent téléphonique Twilio avec votre propre LLM grâce au SDK Speech Engine.
Vue d’ensemble
L’intégration Twilio native d’ElevenAgents couvre le cas où ElevenLabs héberge le LLM. Consultez ce guide lorsque vous avez besoin de contrôler entièrement le moteur LLM sur votre propre serveur, avec votre modèle, pipeline RAG, routage des appels de fonction ou autre logique côté serveur, tout en conservant l’agent sur un numéro de téléphone Twilio.
La partie LLM personnalisé est assurée par le SDK Speech Engine, qui ouvre un WebSocket entre ElevenLabs et votre serveur afin que votre LLM puisse diffuser les réponses à mesure que l’appel se déroule. La partie Twilio utilise Media Streams pour relayer l’audio des appels vers l’agent.
Architecture
Le SDK Speech Engine expose deux points de terminaison WebSocket dans le système de conversation de l’agent :
- Le WebSocket du moteur s’exécute sur votre serveur. ElevenLabs s’y connecte pour transmettre les transcriptions et recevoir le texte généré par le LLM.
- Le WebSocket de conversation s’exécute chez ElevenLabs. Les clients s’y connectent pour envoyer de l’audio et recevoir l’audio synthétisé en retour. Le pont Twilio se connecte via une URL signée et relaie l’audio μ-law dans les deux sens.
Comme Twilio Media Streams et Speech Engine utilisent tous deux ulaw_8000, le pont relaie l’audio encodé en base64 sans transcodage.
Le pont et le serveur du moteur peuvent s’exécuter dans le même processus si cela vous convient. L’exemple ci-dessous les combine.
Quand utiliser ce modèle
Ce guide comme l’intégration Twilio native placent un agent sur un numéro de téléphone Twilio. La différence réside dans l’hébergement du LLM :
- Intégration native : ElevenLabs héberge le LLM, que vous configurez via l’agent. Plus simple.
- LLM personnalisé via le SDK Speech Engine (ce guide) : vous hébergez le LLM sur votre propre serveur. Contrôle total du modèle, du RAG, des appels de fonction et de la logique métier. Plus d’éléments à gérer.
Si votre logique LLM correspond à la configuration standard d’un agent, privilégiez l’intégration native. Consultez ce guide lorsque votre moteur doit exécuter du code sur votre propre infrastructure.
Ce modèle utilise le SDK Speech Engine, qui s’appuie sur une connexion WebSocket pour communiquer entre votre serveur et l’API ElevenLabs. Vous pouvez également utiliser le guide LLM personnalisé, qui emploie un point de terminaison HTTP compatible avec OpenAI à la place du SDK Speech Engine.
La principale différence entre les deux réside dans les WebSockets et les requêtes HTTP. Les WebSockets maintiennent une connexion unique plutôt que d’établir une nouvelle connexion HTTP à chaque tour, ce qui peut réduire la latence.
Prérequis
- Un compte Twilio et un numéro de téléphone compatible avec les appels vocaux.
- Une ressource Speech Engine. Suivez le guide de démarrage rapide Speech Engine pour en créer une et découvrir le modèle de serveur du moteur.
- Un tunnel HTTPS public (par exemple, ngrok). Twilio contacte votre pont via l’internet public.
- Python 3.9+ ou Node.js 18+.
Configurer l’agent pour l’audio μ-law
Twilio Media Streams utilise un audio μ-law à 8 kHz. Configurez Speech Engine pour accepter et émettre ce même format afin que le pont n’ait pas à effectuer de transcodage.
eleven_flash_v2 maintient une faible latence de synthèse vocale, un point essentiel lors d’un appel téléphonique. Le bloc request_headers indique à ElevenLabs d’inclure x-api-key: <shared-secret> sur chaque connexion WebSocket du moteur. Le serveur du moteur vérifie cet en-tête afin de s’assurer que seul votre Speech Engine peut s’y connecter.
Créer le serveur de pont
Le pont fournit trois routes :
POST /incoming-call: webhook Twilio. Renvoie du TwiML demandant à Twilio d’ouvrir un Media Stream vers/media-stream.GET /media-stream: WebSocket Twilio Media Streams. Relaye l’audio vers et depuis le WebSocket de conversation Speech Engine.GET /ws: WebSocket du moteur. ElevenLabs s’y connecte lorsqu’une conversation démarre. Exécute le serveur standardengine.serve()/engine.attach().
Générez une URL signée pour Speech Engine
Le pont demande une URL signée à chaque nouvel appel. L’URL intègre l’ID Speech Engine et une signature à usage unique, afin que le pont n’ait jamais besoin de la clé API brute.
Renvoyez la réponse TwiML
Lorsqu’un appel arrive, Twilio envoie une requête POST à /incoming-call. La réponse est du TwiML qui ouvre un Media Stream vers le WebSocket /media-stream du pont.
RequestValidator (Python) et twilio.webhook({ validate: true }) (Node) vérifient l’en-tête X-Twilio-Signature par rapport à TWILIO_AUTH_TOKEN. Sans validation, toute personne sur l’internet public pourrait envoyer une requête POST à /incoming-call et facturer des appels sur votre compte.
Reliez le Media Stream
Le Media Stream est un WebSocket qui envoie une séquence d’événements JSON : connected, start, media (la charge utile audio) et stop. Le pont ouvre un WebSocket de conversation Speech Engine à start et relaie l’audio dans les deux sens jusqu’à la fermeture du flux.
L’événement interruption de Speech Engine déclenche un événement clear sur le flux Twilio, qui supprime tout audio mis en mémoire tampon afin que l’interruption fonctionne correctement. L’événement ping reçoit une réponse pong pour maintenir le WebSocket de conversation actif.
Exécutez le serveur du moteur en parallèle
Le serveur du moteur est le serveur Speech Engine standard présenté dans le guide de démarrage rapide. Le seul ajout est la vérification du secret partagé lors de la mise à niveau WebSocket. Acceptez la connexion uniquement si x-api-key correspond à la valeur définie sur Speech Engine.
Consultez le guide de démarrage rapide Speech Engine pour découvrir l’implémentation complète de on_transcript, y compris un appel au LLM et une réponse diffusée en continu.
Diriger Twilio vers le pont
Démarrez le pont et un tunnel public
Notez l’URL https:// affichée par ngrok. Twilio y enverra une requête POST.
Mettez à jour ws_url de Speech Engine
Définissez speech_engine.ws_url sur l’URL WebSocket publique de votre point de terminaison du moteur afin qu’ElevenLabs sache où se connecter.
Configurez le numéro Twilio
Dans la console Twilio, ouvrez la configuration vocale de votre numéro de téléphone :
- Un appel arrive : Webhook
- URL :
https://abc123.ngrok.io/incoming-call - Méthode HTTP : POST
Si le numéro est associé à un Elastic SIP Trunk, dissociez-le d’abord. Un numéro Twilio est acheminé soit vers un trunk, soit vers un webhook, mais pas vers les deux.
Appelez le numéro
Composez le numéro depuis n’importe quel téléphone. L’agent répond. Parlez pendant l’appel et vous devriez entendre la réponse de l’agent. Lorsque la journalisation de débogage est activée, le pont consigne le SID de l’appel, l’ID de conversation et le format audio pour chaque tour.
Considérations pour la production
- Validation des webhooks : validez systématiquement
X-Twilio-Signaturesur/incoming-call. L’exemple ci-dessus utilise la bibliothèque d’assistance Twilio, ne sautez pas cette étape. - Secret partagé : appliquez le secret partagé sur le WebSocket du moteur. Sans cela, toute personne qui devine votre URL ngrok peut se connecter et se faire passer pour ElevenLabs.
- Hôte stable : les URL du forfait gratuit ngrok changent à chaque redémarrage. Utilisez un domaine ngrok réservé ou un véritable nom d’hôte afin de ne pas avoir à mettre à jour le
ws_urlde Speech Engine et le webhook Twilio après chaque redémarrage. - Latence : chaque appel ajoute deux sauts réseau au délai avant le premier jeton du LLM. Utilisez un modèle à faible latence et diffusez les réponses pour maintenir une faible latence perçue.
- Un ou deux processus : l’exemple place le pont et le moteur sur le même port, de sorte qu’un seul tunnel ngrok couvre l’ensemble. En production, vous pouvez les répartir sur deux services, à condition que chacun dispose d’une URL publique.
- Injection de prompt : l’entrée vocale d’un appel téléphonique est une entrée utilisateur non fiable. Validez les transcriptions avant qu’elles n’influencent les appels d’outils ou les écritures en base de données.