Passer au contenu principal
OpenAI

Comment nous avons créé en six mois un système en temps réel pour une IA vocale réactive

Par Justin Uberti et Zahan Malkani, membres du personnel technique

Chargement...

Pour l’IA vocale, savoir quand parler est plus difficile qu’il n’y paraît. Les humains se passent naturellement la parole en une fraction de seconde, mais les systèmes d’IA vocale antérieurs ne parvenaient pas à suivre ce rythme. Leur architecture à tours de parole reposait sur de minuscules modèles appelés détecteurs de tour, confrontés à une tâche peu enviable : décider trop tôt coupait l’utilisateur, mais décider trop tard rendait la réponse poussive. Ce n’est qu’après la décision du détecteur que le LLM, bien plus volumineux, pouvait commencer à travailler.

GPT‑Live, notre système vocal de troisième génération, retire le détecteur de tour de la voie audio. Son modèle vocal est en duplex intégral, ce qui signifie qu’il peut écouter et parler en même temps. Cela élimine le besoin d’un détecteur distinct et rend la conversation plus immédiate et naturelle. Lorsqu’un raisonnement approfondi ou l’utilisation d’outils est nécessaire, GPT‑Live peut aussi consulter nos modèles de pointe, comme GPT‑5.5, sans interrompre le fil de la conversation. Ensemble, ces capacités offrent à GPT‑Live une combinaison sans précédent de réactivité conversationnelle et d’intelligence.

Proposer cette expérience à grande échelle a nécessité une nouvelle architecture système optimisée pour une faible latence. Contrairement à l’inférence classique par requête-réponse, notre système diffuse l’audio entrant vers le modèle vocal et renvoie la parole produite à l’utilisateur, tout en gérant la délégation sur une voie asynchrone distincte. Ces six derniers mois, nous avons remanié l’inférence des modèles, la gestion du contexte et le transport multimédia afin d’assurer une circulation fluide de la parole de bout en bout.

L’architecture crée également une frontière claire entre la voie vocale principale et la logique applicative. Il est ainsi facile de personnaliser le comportement de l’application sans nuire à la réactivité. Cette base alimente un éventail croissant de fonctionnalités de ChatGPT Voice, notamment la nouvelle possibilité de contrôler votre ordinateur et de coordonner vos agents dans l’application de bureau ChatGPT.

Dans cet article, nous expliquerons pourquoi les anciens systèmes à tours de parole ne répondaient pas à nos besoins et comment nous avons conçu le nouveau système pour assurer sa réactivité à chaque couche. Nous aborderons l’inférence avec état, la gestion dynamique du contexte, la délégation asynchrone et l’optimisation au niveau du protocole, qui concourent toutes à faire de GPT‑Live un système véritablement temps réel.

Passer des tours de parole à la diffusion en continu

Les anciennes architectures vocales avaient hérité du fonctionnement par tours des LLM textuels, chaque tour étant toutefois représenté par un bloc audio distinct plutôt que par du texte. Dans les systèmes en cascade, la transcription de la parole, le LLM et la synthèse vocale s’exécutaient successivement. Cet enchaînement ajoutait de la latence et ignorait des indices tels que le ton et le rythme.

Les modèles parole à parole ont amélioré cette approche en traitant directement l’audio. Entraîner le modèle à comprendre et à générer nativement la parole lui a permis de préserver des détails perdus lors de la transcription et de répondre plus rapidement. Mais le système dépendait toujours du détecteur de tour pour décider quand l’inférence pouvait commencer. Le modèle prenait en charge une plus grande partie de l’interaction, mais elle restait fondée sur des tours de parole.

GPT‑Live confie au modèle vocal le contrôle de la conversation : l’audio entre dans le modèle et en ressort, tandis que le raisonnement approfondi et l’utilisation d’outils s’effectuent de manière asynchrone. La tâche principale du système consiste à maintenir une boucle multimédia ininterrompue. Les autres tâches, comme l’appel aux modèles de pointe et la persistance de la conversation, s’effectuent hors de la voie temps réel.

Schéma montrant le modèle vocal frontend en temps réel de GPT-Live, la délégation asynchrone à un modèle de raisonnement backend, l’utilisation d’outils et l’audio bidirectionnel avec l’utilisateur.

Permettre l’inférence continue

Maintenir cette boucle média sans interruption n’est pas toujours simple. Tout retard dans le transport, le traitement ou l’inférence peut produire une pause audible ou un artefact. Un ancien système à tours de parole pouvait tolérer une certaine variation dans l’instant d’arrivée d’un bloc audio. Un système multimédia en direct doit toutefois livrer chaque trame audio au moment prévu.

Nos travaux antérieurs sur ChatGPT Voice et la Realtime API nous ont fourni une base importante. Nous avions déjà reconstruit notre infrastructure vocale afin de diffuser directement l’audio et la vidéo vers et depuis nos systèmes, avec une latence plus faible et plus prévisible. GPT‑Live a poussé cette conception plus loin en diffusant les médias jusqu’au modèle grâce à un nouveau système d’inférence avec état, conçu pour la conversation continue.

L’inférence en continu ne constituait toutefois qu’une partie de la solution. Pour assurer son bon fonctionnement en production, nous devions aussi garantir une livraison fiable de l’audio entre le client et la pile d’inférence, et relever les défis liés à la gestion d’état.

Accélérer le flux multimédia

Nous avons décidé très tôt de séparer expressément le flux multimédia de la logique applicative et métier. L’audio circule entre le client et le modèle vocal par une voie rapide dédiée. La délégation, l’utilisation d’outils et les autres tâches applicatives s’effectuent derrière une frontière RPC asynchrone. Un appel d’outil ou un service backend lent peut retarder son propre résultat, mais ne peut pas bloquer le flux multimédia.

Cette séparation fournit également au système une frontière claire pour la personnalisation. Les applications peuvent modifier leurs outils, leurs politiques et le comportement de leur système backend sans affecter le frontend multimédia chargé de maintenir la circulation de l’audio. La voie temps réel reste compacte, prévisible et centrée sur les tâches qui exigent une exécution immédiate.

Nous avons écrit le frontend multimédia et la logique d’inférence en Go, en remplacement d’une précédente implémentation Python fondée sur asyncio. Cela a nettement amélioré la fluidité de livraison des trames, le p95 du nouveau système égalant le p50 de l’ancien.

WebRTC fournit la base du transport. Il est conçu pour les médias à faible latence et peut continuer à fonctionner malgré les pertes de paquets, la dérive d’horloge et les changements de connexion du client. Si des paquets arrivent en retard, WebRTC peut étirer subtilement l’audio pour éviter les interruptions, puis accélérer brièvement la lecture afin de rattraper le temps réel.

En réduisant au minimum la mise en mémoire tampon et les blocages dans tout le système, nous pouvons offrir la réactivité inférieure à une seconde que les humains attendent d’une conversation.

Maintenir la conversation (avec état)

L’inférence avec état implique ses propres compromis opérationnels. Une session vocale peut rester active longtemps, mais son contexte ne cesse de croître, tandis que les instances de modèle démarrent et s’arrêtent en fonction de la demande.

Pour répondre à ces enjeux, nous avons créé un mécanisme de transfert fluide entre les instances de modèle. Lorsqu’une transition est nécessaire, nous pouvons préparer une instance de modèle de remplacement parallèlement à l’instance existante, la préremplir avec le contexte actuel de la session, exécuter l’inférence sur les deux en parallèle, puis basculer lorsque la nouvelle instance est entièrement prête.

Le même mécanisme de base prend également en charge le compactage dynamique du contexte. Au fil d’une conversation, le contexte accumulé peut finir par dépasser la limite contextuelle du modèle. Le compactage peut réduire la taille du contexte pour respecter cette limite, mais l’opération prend du temps. Comme il modifie le contexte antérieur, il invalide également le cache clé-valeur (KV) du modèle, qui stocke les clés et valeurs d’attention des tokens précédemment traités. La reconstruction de cet état nécessite un nouveau préremplissage, ce qui ajoute un délai.

Nous traitons plutôt le compactage comme une autre transition gérée. Pendant que l’instance de modèle d’origine poursuit la conversation, le système compacte le contexte et prépare une instance de remplacement avec le nouveau contexte. Une fois cette instance prête, nous pouvons basculer sans interrompre les médias. Le système peut ainsi prendre en charge les appels prolongés et compacter le contexte chaque fois que nécessaire.

Schéma montrant un instantané compact transféré du serveur d’inférence A au serveur d’inférence B, où il est préchargé et actualisé avant le basculement.

Les tâches lourdes restent hors de la voie temps réel : même pendant un transfert, la conversation se poursuit sans le moindre accroc.

Déléguer sans bloquer la conversation

La capacité de GPT‑Live à faire appel aux modèles de pointe existants lui confère une grande puissance, en dissociant concrètement la « parole » de la « réflexion » approfondie. Mais pour que cette architecture à deux modèles donne l’impression d’un système unique, il a fallu résoudre deux problèmes d’ingénierie connexes.

Délégation pour les tâches plus approfondies

GPT-Live fournit des réponses rapides et naturelles, tandis que GPT-5.5 effectue les recherches en arrière-plan

Transcription
Exemple de conversation avec GPT-Live-1, en utilisant GPT-5.5 Instant

Premièrement, les résultats doivent revenir assez vite pour être utiles dans l’échange en cours. Nous avons donc dû réduire la latence sur l’ensemble de la voie de délégation, de l’acheminement et du traitement des prompts jusqu’à l’inférence et aux appels d’outils. En parallèle, d’autres systèmes du produit ont toujours besoin de messages distincts. Nous avons donc dû représenter la conversation en cours sous une forme qu’ils pouvaient comprendre.

Rendre la délégation assez rapide pour paraître naturelle

Lorsqu’une délégation est envoyée, nous optimisons le délai nécessaire pour que le modèle de pointe produise un élément utile à la conversation. Le modèle vocal peut brièvement faire avancer l’échange pendant qu’un modèle de pointe raisonne ou utilise des outils, mais il ne peut pas masquer une réponse arbitrairement lente. Nous avons donc intégré toute la boucle de délégation — acheminement, traitement du prompt, inférence et appels d’outils — au budget de réactivité.

La première optimisation consiste à préparer le modèle de pointe et tous les outils nécessaires avant la demande de délégation. Au démarrage d’une session vocale, le serveur d’applications crée une session d’inférence pour le modèle de pointe et la préremplit avec le contexte initial de la conversation, garantissant ainsi que le prompt est entièrement traité avant la première requête déléguée.

Nous maintenons ensuite cette session d’inférence disponible pendant toute la conversation vocale et utilisons une affinité de session stable pour les requêtes successives. Associées à la mise en cache du prompt, ces techniques améliorent la latence tout en permettant de récupérer facilement après la défaillance d’un processus de travail.

L’effort de raisonnement, les limites de sortie, les schémas d’outils et les allers-retours entre modèle et outils influencent aussi le moment où la conversation reçoit un résultat utile ; nous avons ajusté ces paramètres pour accélérer les réponses. En réduisant au minimum le travail nécessaire sur le parcours de délégation, nous avons permis au modèle vocal d’intégrer rapidement les résultats de nos modèles de pointe.

Déduire des tours distincts à partir d’une parole continue

Même si le modèle vocal traite des flux de parole continus, de nombreux systèmes qui l’entourent fonctionnent toujours par tours de l’utilisateur et de l’assistant, notamment l’interface de conversation de ChatGPT et certaines parties de notre infrastructure d’analyse et de sécurité. Le serveur d’applications démêle donc la conversation, parfois simultanée et ambiguë, pour en tirer des messages distincts.

À mesure que l’audio arrive, le serveur utilise des transcriptions partielles et des signaux temporels pour déterminer qui a la parole et constituer une file de messages. Le message le plus récent reste provisoire : son texte, sa chronologie et l’identité du locuteur peuvent tous changer à mesure que de nouvelles paroles arrivent. Lorsqu’un locuteur a gardé la parole assez longtemps pour que l’attribution soit fiable, le serveur finalise le message correspondant.

Le chevauchement des locuteurs complique les choses. Une brève marque d’écoute de l’assistant pendant que l’utilisateur parle (par exemple « hum hum » ou « d’accord ») ne doit pas nécessairement devenir un message à part entière. En revanche, une intervention substantielle de l’assistant doit souvent le devenir. De même, nous privilégions la cohérence des réponses affichées de l’assistant, même lorsque l’utilisateur intervient au milieu.

Toute politique de segmentation établit un compromis entre fraîcheur et certitude. Valider trop tôt produit un historique fragmenté et un ordre instable ; attendre trop longtemps retarde les transcriptions et les fonctionnalités qui en dépendent. Le système conserve donc deux vues connexes de la conversation : une vue spéculative de l’état actuel et un enregistrement faisant autorité de ce qui a été dit. La vue de la conversation dans l’interface de l’application peut gérer les mises à jour ; elle utilise donc la vue spéculative. En revanche, la journalisation dans le pipeline d’analyse exige une transcription définitive.

Le reste de ChatGPT bénéficie ainsi d’une vue stable de l’échange, sans imposer de tours de parole à la voie temps réel de la voix.

Démarrer les sessions avec un protocole plus rapide

La réactivité commence dès que l’utilisateur clique sur le bouton. Avec GPT‑Live, le système doit établir la voie multimédia et commencer à transmettre l’audio au modèle avant que la conversation puisse débuter. Chaque étape de la séquence de démarrage fait donc partie du chemin critique.

Comme indiqué plus haut, WebRTC fournit une base solide pour le temps réel, mais le démarrage d’une session WebRTC classique exige un nombre étonnant de négociations de protocoles et d’allers-retours réseau. WebRTC est antérieur à l’attention portée à la réduction des allers-retours qui a façonné des protocoles ultérieurs comme QUIC. Par conséquent, ses protocoles sous-jacents répètent parfois certaines opérations lorsqu’ils sont utilisés ensemble. Par exemple, chaque protocole intégrait son propre mécanisme anti-DDoS, même lorsqu’il n’était pas nécessaire dans le contexte de la pile WebRTC complète.

Nous avons analysé la pile et développé le WebRTC Abridged Roundtrip Protocol (WARP(ouverture dans une nouvelle fenêtre)), qui réduit le démarrage des médias et des données de six allers-retours réseau à un seul. WARP y parvient grâce à un ensemble d’améliorations de protocole rétrocompatibles : incorporation de la négociation DTLS dans ICE (SPED(ouverture dans une nouvelle fenêtre)), utilisation de la négociation DTLS 1.3(ouverture dans une nouvelle fenêtre) plus rapide, prénégociation de la négociation SCTP (SNAP(ouverture dans une nouvelle fenêtre)) et prénégociation des canaux de données au lieu d’utiliser DCEP(ouverture dans une nouvelle fenêtre).

Nous avons conçu WARP comme un ensemble de spécifications ouvertes, en collaboration avec des membres de la communauté WebRTC, afin que l’ensemble de l’écosystème puisse bénéficier de ces travaux. Nous faisons progresser ces propositions au sein du groupe de travail TSVWG de l’IETF. La prise en charge de WARP a déjà été ajoutée à libwebrtc et Pion, et des travaux sont en cours dans d’autres implémentations de WebRTC.

Comparaison entre la négociation WebRTC classique et WebRTC avec WARP, montrant que WARP rend les médias et les données disponibles en moins d’allers-retours.

Après l’optimisation de la négociation multimédia, un dernier délai se démarquait : l’échange de signalisation servant à partager les paramètres SDP avant que WebRTC puisse se connecter. Pour retirer cet échange du chemin critique, nous avons développé ce que nous appelons Instant Connect. Il négocie ces paramètres à l’avance, sans réserver de capacité serveur ni modifier les implémentations WebRTC existantes.

Instant Connect fonctionne parallèlement au flux de signalisation standard. Si les paramètres prénégociés sont valides, le serveur peut matérialiser la session à l’arrivée du premier paquet multimédia. S’ils sont obsolètes ou non valides, le flux de signalisation est déjà en cours. Le client peut donc s’y rabattre sans latence supplémentaire.

Ensemble, Instant Connect et WARP réduisent considérablement le délai entre l’intention de l’utilisateur et le démarrage du flux multimédia temps réel. L’échange SDP étant retiré du chemin critique et WARP condensant la négociation du transport, le client peut désormais démarrer une session avec un seul paquet UDP. Le serveur peut répondre immédiatement, permettant au reste du système de commencer ce qui compte vraiment pour l’utilisateur : écouter et répondre.

Tester GPT‑Live en production, en toute sécurité, avec des données réelles

Un système peut sembler rapide sur le papier et pourtant se bloquer face à un trafic vocal réel. Avant de laisser GPT‑Live discuter avec les utilisateurs, nous avons mené un test silencieux qui acheminait une part faible et progressivement croissante des sessions ChatGPT Voice en production à la fois vers l’expérience existante du mode vocal avancé et vers notre nouveau système. Le mode vocal avancé a continué à servir les utilisateurs comme d’habitude, tandis que la voie fantôme exécutait les inférences en lecture seule. Le système a ainsi été exposé à de vrais clients, réseaux, durées de session et répartitions géographiques, sans modifier ce que les utilisateurs entendaient.

L’une des premières leçons a été que la capacité ne pouvait pas se résumer au débit des GPU. Les sessions vocales restent ouvertes et envoient continuellement des trames. Les gestionnaires de flux côté CPU, les files d’attente et les chemins réseau doivent donc évoluer parallèlement à l’inférence. Sous une charge réelle, un composant auxiliaire a saturé plus tôt que ne le prévoyaient nos estimations issues des tests de charge, entraînant une accumulation des requêtes d’inférence et une aggravation de la latence. Nous avons reformulé la question de la capacité, passant de « Combien de requêtes un GPU peut-il traiter ? » à « Combien de sessions simultanées le système peut-il prendre en charge tout en respectant le délai de chaque trame ? ».

Le test a également fait de la géographie une préoccupation de premier ordre. Acheminer une session vers une capacité éloignée peut ajouter du délai à plusieurs étapes du démarrage et de la diffusion en continu. Nous avons commencé à valider les déploiements de modèles en même temps que la capacité régionale et la configuration d’orientation du trafic, puis à ventiler la latence selon l’origine géographique. Rapprocher l’inférence des utilisateurs a aidé, mais a aussi confirmé une leçon plus générale : la réactivité de bout en bout dépend de chaque service de la voie, et pas seulement du serveur de modèles.

D’autres défaillances ne sont apparues que sur des cycles de vie de session réalistes. Les sessions prolongées ont révélé des contraintes de mémoire et de persistance. Les reconnexions ont sollicité le compactage et la restauration de l’état. Les déconnexions ordinaires des clients ont révélé des conditions de concurrence dans la négociation d’arrêt. Ces problèmes apparaissaient rarement lors de tests de charge courts, car ils dépendaient du temps, de l’état accumulé et du comportement au-delà des frontières entre services.

Enfin, les tests en production nous ont obligés à améliorer l’observabilité et les contrôles de déploiement. Nous avons découvert des métriques qui confondaient différentes sources de latence, des tableaux de bord dont les agrégats masquaient des moteurs individuels défaillants et des divergences de configuration entre les systèmes testés et déployés. En réponse, nous avons ajouté une télémétrie plus granulaire, une validation par rapport à des configurations reconnues comme fiables, des montées en charge progressives et la possibilité d’isoler ou de désactiver rapidement des voies individuelles. Le test silencieux est devenu une répétition générale avant le lancement, non seulement pour déterminer le volume de trafic que le système pouvait accepter, mais aussi la rapidité avec laquelle nous pouvions détecter et contenir une défaillance, puis rétablir le service.

Réactif, du client au modèle

Adapter GPT‑Live à l’échelle de ChatGPT a nécessité un tout nouveau système, conçu autour d’un principe fondamental : la voix doit circuler. L’inférence en continu alimente le modèle en duplex intégral avec de l’audio. Une voie multimédia dédiée assure une livraison fiable des trames. La délégation asynchrone permet d’effectuer en parallèle une réflexion plus approfondie. Un transport optimisé préserve la réactivité de l’expérience jusqu’à l’utilisateur.

L’architecture sous-jacente de GPT‑Live devient déjà une plateforme plus vaste pour les interactions en temps réel. Elle alimente ChatGPT Voice à mesure que celui-ci évolue de la conversation vers la coordination agentique, et servira de socle à la future API GPT‑Live. À terme, elle permettra aux expériences vocales de s’étendre à davantage d’appareils, d’applications et de modalités sans sacrifier l’immédiateté qui donne aux conversations vocales leur naturel.

Si vous souhaitez résoudre ce type de problèmes d’ingénierie, venez travailler avec nous.

Auteur

Justin Uberti, Zahan Malkani