Passer au contenu

Optimisation de la latence des agents vocaux : guide étape par étape

Publié

ÉcouterÉcouter cet article

La réactivité d’un agent vocal dépend du délai total entre le moment où un utilisateur termine de parler et celui où l’agent commence à répondre. Ce délai n’est presque jamais causé par un seul composant lent. Il s’accumule sur plusieurs étapes indépendantes, chacune ajoutant quelques dizaines ou centaines de millisecondes, et le réduire demande de savoir combien de temps chaque étape prend.

L’optimisation de la latence d’un agent vocal consiste à identifier où ce temps se cache et à le récupérer étape par étape.

Cet article complète le résumé conceptuel de la latence. Là où cette page explique ce qu’est la latence, celle-ci aborde l’architecture et la mesure, pour que vous repartiez avec un budget de latence mesurable et des actions concrètes à mettre en place.

À retenir

  • Le temps jusqu’au premier audio (time-to-first-audio) concerne tout le pipeline, pas seulement le temps d’inférence d’un modèle.
  • Le temps jusqu’au premier token du LLM et l’endpointing sont les deux plus gros postes de latence.
  • Faire se chevaucher les étapes, plutôt que de les exécuter en série, permet de récupérer la majeure partie du budget.
  • Le streaming, le choix du codec et l’ajustement du buffer du lecteur permettent chacun de gagner des millisecondes mesurables.
  • Vous devez mesurer par région selon votre propre déploiement, en reportant les P50 et P95.

Définir le budget de latence d’un agent vocal

Un budget de latence est un objectif de temps total jusqu’au premier audio, réparti sur les étapes du pipeline, chaque étape ayant une allocation qui doit rester sous votre cible globale. Le définir est la première étape, et c’est aussi là que l’on se trompe le plus souvent, car les ingénieurs confondent parfois deux chiffres qui se ressemblent mais n’ont pas le même sens.

Le premier est la latence d’inférence du modèle : le temps que met un modèle à générer une sortie. Pour nos modèles Flash, cela représente environ 75 ms pour des entrées courtes typiques, hors réseau et surcharge applicative. C’est une donnée interne, utile pour comparer les modèles entre eux. Ce n’est pas le chiffre ressenti par l’utilisateur.

Du point de vue de l’utilisateur, vous vous concentrez sur le time-to-first-audio (TTFA) : le temps écoulé entre la fin de la prise de parole de l’utilisateur et l’écoute du premier échantillon de la réponse de l’agent. Le TTFA est toujours supérieur à la latence d’inférence d’un modèle, car il additionne tout le pipeline.

Un agent vocal en cascade est une chaîne de cinq étapes :

  • capture (micro) -> STT -> LLM -> TTS -> lecture

L’audio est capté par le micro, transcrit en texte, envoyé à un modèle de langage, le texte du modèle est synthétisé en voix, puis ce son est mis en mémoire tampon et joué. Chaque étape ajoute de la latence, et dans plusieurs cas, le coût principal n’est pas celui auquel on s’attend.

Voici un exemple pour un agent en anglais avec des serveurs proches de l’utilisateur. Les chiffres sont des fourchettes indicatives, pas des garanties.

What it covers
Capture + endpointing
Mic capture, VAD/turn-detection delay before the turn is considered finished
STT finalization
Last partial to committed transcript after end-of-speech
Network (client to your server to our API)
Round-trips across the pipeline
LLM time-to-first-token
Prompt processing until the first usable token
TTS time-to-first-audio
First TTS request until first audio chunk leaves the model
Player buffering
Client-side buffer before playback begins
End-to-end TTFA
The total latency of the end-to-end pipeline
P50
Capture + endpointing
120 ms
STT finalization
60 ms
Network (client to your server to our API)
60 ms
LLM time-to-first-token
250 ms
TTS time-to-first-audio
110 ms
Player buffering
80 ms
End-to-end TTFA
~680 ms
P95
Capture + endpointing
280 ms
STT finalization
150 ms
Network (client to your server to our API)
160 ms
LLM time-to-first-token
600 ms
TTS time-to-first-audio
220 ms
Player buffering
150 ms
End-to-end TTFA
~1560 ms

En général, les deux plus gros postes de latence sont le temps jusqu’au premier token du LLM et le délai d’endpointing au début de la chaîne.

Le tableau permet de visualiser le pipeline, mais il laisse penser que les étapes s’enchaînent strictement, ce qui n’est pas le cas. Plusieurs optimisations majeures de la latence des agents vocaux viennent du chevauchement des étapes, et c’est là que la majeure partie du budget ci-dessous est récupérée.

Speech to Text : optimisation de la latence de transcription et d’endpointing

La transcription est la deuxième étape du pipeline, et son vrai coût n’est pas la transcription elle-même mais la décision du moment où l’utilisateur a fini de parler. Cette section couvre les deux aspects pour vous aider à optimiser la latence de votre agent vocal.

La transcription intervient avant d’atteindre le LLM.Scribe v2 Realtime (scribe_v2_realtime) retourne des transcriptions partielles en environ 150 ms et fonctionne en streaming par morceaux audio, donc la transcription se construit pendant que l’utilisateur parle encore. Il prend en charge le PCM de 8 kHz à 48 kHz et l’encodage mu-law, ce qui est important pour la section codec ci-dessous. Les transcriptions partielles à 150 ms sont peu coûteuses.

Le coût de latence le plus important est l’endpointing : le moment où votre système décide que l’utilisateur a vraiment terminé son tour.

La détection d’activité vocale (VAD) segmente la parole sur les silences, et c’est là que le temps s’accumule. Si vous attendez, par exemple, 700 ms de silence avant de déclarer la fin du tour, vous ajoutez 700 ms à chaque tour, en plus de la transcription elle-même. Ce délai est invisible dans un benchmark de précision de transcription mais très présent dans une vraie conversation. C’est souvent la plus grande latence contrôlable du pipeline, et comme elle est contrôlable, c’est un bon point de départ.

L’endpointing est un compromis entre réactivité et interruption. Un seuil de silence court permet à l’agent de répondre vite mais risque de couper l’utilisateur sur une pause naturelle. Un seuil long est plus sûr mais moins réactif. En pratique, trois changements optimisent la latence du speech to text :

  1. Ajustez finement le seuil de silence :Réduisez le seuil de silence au minimum sans couper les pauses naturelles de vos utilisateurs, puis mesurez le taux d’interruption en production au lieu de deviner.
  2. Ajoutez un contrôle physique : Utilisez un contrôle manuel quand votre application sait que le tour est terminé grâce à un autre signal (relâchement push-to-talk, événement UI), au lieu d’attendre le timer VAD.
  3. Chevauchez avec le LLM :Envoyez les transcriptions partielles stables au LLM dès qu’elles sont prêtes et révisez si la transcription finale diffère, une forme d’exécution spéculative qui masque le délai d’endpointing derrière le traitement du prompt LLM.

Pour plus d’informations, Scribe v2 Realtime est détaillé sur la page fonctionnalités speech to text et la page produit reconnaissance vocale en temps réel.

La contribution du LLM à la latence

Le modèle de langage est généralement le plus gros contributeur unique au TTFA, donc c’est aussi là que le chevauchement rapporte le plus en optimisation de la latence des agents vocaux. L’idée clé ici est que l’agent n’a pas besoin de toute la réponse avant de commencer à parler.

La méthode la plus efficace consiste à streamer les tokens du LLM vers le TTS dès qu’ils arrivent, par morceaux à la fin de chaque phrase ou proposition. L’idée est de mettre en mémoire tampon les tokens jusqu’à une frontière de phrase, puis de synthétiser cette phrase pendant que la suivante est encore générée :

const SENTENCE_END = /(?<=[.!?])\s+/;

async function* speakLlmStream(tokens: AsyncIterable<string>) {
  let buffer = "";
  for await (const token of tokens) {
    buffer += token;
    const parts = buffer.split(SENTENCE_END);
    buffer = parts.pop() ?? ""; // keep the incomplete fragment
    for (const sentence of parts) {
      if (sentence.trim()) yield* synthesize(sentence.trim());
    }
  }
  if (buffer.trim()) yield* synthesize(buffer.trim());
}

async function* synthesize(text: string) {
  const stream = await elevenlabs.textToSpeech.stream("JBFqnCBsd6RMkjVDRZzb", {
    text,
    modelId: "eleven_flash_v2_5",
    outputFormat: "mp3_44100_128",
  });
  yield* stream;
}

Pour les conversations longues, privilégiez le WebSocket TTS afin qu’une connexion ouverte puisse recevoir le texte au fur et à mesure, sans devoir rouvrir la connexion à chaque phrase. Seul le temps où le modèle génère activement de l’audio compte dans votre limite de concurrence, donc un WebSocket ouvert mais inactif ne coûte presque rien.

Text to Speech : streaming et choix de la voix

Le text to speech est l’étape où vous pouvez maîtriser la latence le plus précisément. Deux leviers principaux : la façon dont vous streamez l’audio et la voix choisie.

Flash v2.5 (eleven_flash_v2_5) est le modèle à utiliser pour un agent. Il offre environ 75 ms d’inférence pour des entrées courtes, prend en charge 32 langues et accepte jusqu’à 40 000 caractères par requête.

Les 75 ms concernent uniquement l’inférence. La ligne TTFA du TTS dans le budget ci-dessus est plus élevée car elle inclut l’aller-retour réseau et la planification serveur en plus de l’inférence.

Le plus gros levier ici est le streaming. Si vous demandez tout l’audio et attendez, l’utilisateur attend que tout le clip soit synthétisé avant d’entendre quoi que ce soit. Si vous streamez, l’utilisateur entend le premier morceau dès qu’il est généré, et le reste arrive pendant l’écoute. Le streaming ne rend pas le modèle plus rapide ; il commence simplement à envoyer le son à l’utilisateur pendant la génération.

Le guide pratique du streaming explique le streaming HTTP, et le guide WebSocket en temps réel détaille la méthode WebSocket à privilégier pour envoyer les tokens d’un LLM.

Initialisez le client une fois et réutilisez-le pour chaque appel ci-dessous :

import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";

const elevenlabs = new ElevenLabsClient({ apiKey: process.env.ELEVENLABS_API_KEY });

Ensuite, mettez en place un flux et transférez-le au fur et à mesure :

const stream = await elevenlabs.textToSpeech.stream("JBFqnCBsd6RMkjVDRZzb", {
  text: "Your call is connected. How can I help today?",
  modelId: "eleven_flash_v2_5",
  outputFormat: "mp3_44100_128",
});

for await (const chunk of stream) {
  // forward each chunk to your audio sink as it arrives
}

L’autre levier est le choix de la voix, qui a aussi un impact sur la latence. Les voix par défaut, synthétiques et les Instant Voice Clones (IVC) sont plus rapides à synthétiser que les Professional Voice Clones (PVC), car les PVC sont plus complexes et ajoutent du temps à chaque génération. Pour un agent avec des exigences strictes de latence, la combinaison Flash + IVC ou voix par défaut est l’option la plus rapide.

Choix de la taille des morceaux en streaming

Avec les tokens qui arrivent dans le TTS et l’audio qui revient, la prochaine décision est la taille des morceaux et la quantité de buffer du lecteur avant de démarrer.

Des morceaux plus petits arrivent plus vite au lecteur, réduisant la latence du premier octet, au prix de plus de messages et d’un léger surcoût par morceau. Les morceaux plus gros sont plus efficaces à transporter mais font attendre l’utilisateur plus longtemps pour le premier. Pour les agents interactifs, privilégiez les petits morceaux au début de l’énoncé, car c’est le premier que l’utilisateur attend ; les suivants arrivent pendant la lecture et leur taille compte moins.

Le lecteur représente une part importante de la latence restante. La plupart des lecteurs audio ne démarrent pas à la réception du premier octet. Ils mettent en mémoire tampon une petite quantité pour éviter les coupures si le flux ralentit. Un buffer de 500 ms est courant, et il s’ajoute directement à la latence perçue. Le réduire augmente légèrement le risque de coupure mais diminue le TTFA, et la bonne valeur dépend de la gigue réseau entre votre serveur et le client :

  • Sur une connexion stable (lecture côté serveur, client co-localisé), un buffer de 50 à 150 ms est généralement sûr et permet de gagner du temps sur le TTFA.
  • Sur une connexion mobile instable ou inter-région, un buffer plus grand évite les coupures audibles, qui sont pires que la latence qu’elles ajoutent.

La configuration exacte dépend de votre cas d’usage et de vos priorités.

Choix du codec

La destination de l’audio doit dicter le codec à demander. Nous proposons des formats comme mp3_44100_128, mp3_22050_32, pcm_16000, pcm_24000 et ulaw_8000. Utiliser le format natif du transport évite une étape de transcodage, ce qui aide à optimiser la latence de l’agent vocal.

Pour la téléphonie, comme Twilio ou d’autres, utilisez ulaw_8000. Le réseau téléphonique fonctionne en mu-law 8 kHz de bout en bout, donc le demander directement évite une conversion dans votre pipeline et correspond à ce qu’attend l’opérateur. Il n’y a aucun intérêt à synthétiser un son de meilleure qualité que le réseau téléphonique va immédiatement dégrader ; cela ne ferait qu’ajouter de la latence sans rien gagner d’audible.

Pour WebRTC et la lecture dans un navigateur, utilisez PCM (pcm_24000 ou pcm_16000) ou un format MP3. PCM est non compressé, donc il n’y a pas de décodage côté client, ce qui enlève un peu de latence par morceau et est pratique si vous alimentez directement une pipeline Web Audio. MP3 est plus compact sur le réseau, ce qui aide sur les connexions limitées, au prix d’un léger décodage côté client.

Géographie et distances réseau

Toutes les optimisations ci-dessus supposent que les données voyagent sur une courte distance. La géographie fixe le plancher de votre budget de latence, donc il vaut la peine de l’examiner avant d’optimiser le reste.

Nous traitons les requêtes depuis des clusters en Amérique du Nord, Europe et Asie du Sud-Est, et chaque requête est automatiquement routée vers le cluster le plus proche. L’aller-retour réseau sur Internet public est généralement de 20 à 200 ms selon la proximité géographique, et il est incompressible sans changer l’emplacement de votre infrastructure.

Un agent qui paraît instantané à San Francisco, proche d’un cluster nord-américain, peut sembler lent à un utilisateur en Asie du Sud dont le trafic traverse l’océan deux fois à chaque tour.

La solution est de co-localiser vos serveurs applicatifs avec vos utilisateurs, pas seulement avec nous. Si vos utilisateurs sont en Europe, faites tourner votre backend agent en Europe pour que la liaison utilisateur-serveur soit courte ; notre routage gère ensuite la liaison serveur-modèle depuis un cluster proche.

Mesurer vous-même la latence de votre agent vocal

Les chiffres du tableau de budget de latence ci-dessus sont des fourchettes pour planifier. Les chiffres à viser doivent venir d’un script comme celui-ci, exécuté sur votre propre déploiement.

L’instrumentation ci-dessous mesure le TTFA pour l’étape TTS seule, du moment de la requête à la réception du premier morceau audio, sur de nombreux essais, et affiche les percentiles. Lancez-le depuis la même région que vos serveurs, pas depuis votre machine de développement. Il suppose le client elevenlabs vu plus haut :

const VOICE_ID = "JBFqnCBsd6RMkjVDRZzb";
const TEXT = "Thanks for waiting. I have pulled up your account and I can help with that now.";
const TRIALS = 50;

async function measureTtfa(): Promise<number | null> {
  const start = performance.now();
  const stream = await elevenlabs.textToSpeech.stream(VOICE_ID, {
    text: TEXT,
    modelId: "eleven_flash_v2_5",
    outputFormat: "mp3_44100_128",
  });
  for await (const _chunk of stream) {
    return performance.now() - start; // first chunk -> stop the clock
  }
  return null;
}

function percentile(values: number[], p: number): number {
  const v = [...values].sort((a, b) => a - b);
  const k = (v.length - 1) * (p / 100);
  const lo = Math.floor(k);
  const hi = Math.min(lo + 1, v.length - 1);
  return v[lo] + (v[hi] - v[lo]) * (k - lo);
}

const samples: number[] = [];
for (let i = 0; i < TRIALS; i++) {
  const ttfa = await measureTtfa();
  if (ttfa !== null) samples.push(ttfa);
  await new Promise((r) => setTimeout(r, 300)); // space requests, don't measure your own queueing
}

console.log(`trials: ${samples.length}`);
console.log(`P50:    ${percentile(samples, 50).toFixed(0)} ms`);
console.log(`P95:    ${percentile(samples, 95).toFixed(0)} ms`);

Quelques points à retenir :

  • Affichez P50 et P95 :Concentrez-vous sur ces valeurs, pas la moyenne. La moyenne masque la queue, et c’est la queue qui donne une impression d’agent peu fiable. P95 correspond à l’expérience d’un tour sur vingt.
  • Expérimentation par région : Lancez le même script depuis chaque région desservie et gardez les résultats séparés.
  • Décalez pour plus de précision :Espacez vos requêtes (le setTimeout ci-dessus). Si vous les envoyez toutes en même temps, vous mesurez votre propre file d’attente au lieu du service. Quand la limite de concurrence est dépassée, les requêtes sont mises en file d’attente par priorité, ce qui ajoute généralement environ 50 ms, et au-delà de la capacité vous recevez une erreur HTTP 429.
  • Mesurez toute la chaîne de latence :Étendez le même schéma de mesure aux autres étapes. Encadrez la finalisation STT, le premier token LLM et le démarrage du lecteur avec performance.now(), et vous pourrez remplir votre propre tableau de budget et voir quelle étape attaquer en premier.

En suivant ces conseils, vous pourrez mesurer vous-même la latence de votre agent vocal. Vous aurez alors une liste claire de priorités à traiter.

Qu’est-ce qui réduit le plus la latence d’un agent vocal ?

Si vous cherchez des actions rapides à mettre en place, voici les changements les plus efficaces.

En gros par ordre d’impact, vous pouvez utiliser les méthodes suivantes pour réduire la latence de l’agent :

  • Lancez le traitement LLM sur les transcriptions STT stables pour masquer le délai d’endpointing.
  • Streamez les tokens LLM dans le TTS à chaque fin de phrase pour que la synthèse de la première phrase chevauche la génération de la seconde.
  • Streamez l’audio TTS vers le lecteur et réduisez le buffer du lecteur au minimum toléré par la gigue réseau.
  • Utilisez Flash avec une voix par défaut ou IVC pour le TTS le plus rapide, et adaptez le codec au transport (ulaw_8000 pour la téléphonie, PCM ou MP3 pour navigateur/WebRTC).
  • Co-localisez vos serveurs avec vos utilisateurs et mesurez par région, car les trajets réseau sont réels et inégaux.

Pour des techniques plus avancées, consultez le guide pratique d’optimisation de la latence pour développeurs. Pour un point de départ complet, l’API quickstart et le guide streaming proposent des exemples prêts à l’emploi.

Vous voulez accéder plus vite à des agents en cascade optimisés ?ElevenAgents met en œuvre ce pipeline avec les optimisations de chevauchement déjà intégrées.

Créez des agents vocaux à faible latence avec ElevenAgents

L’optimisation de la latence d’un agent vocal demande de mesurer chaque étape puis de les faire se chevaucher pour que les plus lentes tournent en arrière-plan. Vous pouvez construire et ajuster cette cascade à la main en plusieurs itérations, en utilisant les schémas ci-dessus, ou démarrer avec un pipeline déjà optimisé.

ElevenAgents met en œuvre toute cette cascade, du streaming STT au passage token par token au LLM jusqu’au TTS Flash, avec les techniques de chevauchement déjà intégrées. Plutôt que de partir de zéro, vous ajustez les seuils pour obtenir la performance qui compte pour vous.

Commencez avec ElevenAgents pour créer un agent dès aujourd’hui ou contacter le service commercial pour plus d’informations.

FAQ sur l’optimisation de la latence des agents vocaux

Articles similaires

Créez avec l'audio IA de la plus haute qualité