Introduction
La conversation en temps réel établit une connexion persistante via WebSocket (un protocole qui maintient une connexion durable et bidirectionnelle entre le client et le serveur), envoie votre audio ou votre texte au modèle de conversation en temps réel, et le modèle renvoie progressivement du texte et de la voix. Elle convient aux assistants vocaux, aux questions-réponses en temps réel, à la pratique orale et aux autres scénarios qui exigent des échanges successifs. Comme la transcription en temps réel, elle passe par WebSocket, mais les deux ont des usages différents :
Modèle disponible :
- gpt-realtime-2.1 : modèle de conversation vocale, prend en charge l’audio et le texte en entrée et produit du texte et de la voix en temps réel.
Démarrage rapide
Point de terminaison
model=gpt-realtime-2.1: obligatoire, le modèle est fixé au moment de la connexion par le paramètre d’URL et ne peut plus être modifié pendant la session (voir les contraintes ci-dessous).- Attention à la différence avec la transcription : le point de terminaison de conversation ne prend pas
intent=transcription.
Authentification
Transmettez la clé dans un en-tête HTTP standard lors de la poignée de main :Format audio requis
L’audio en entrée et en sortie ne prend actuellement en charge qu’un seul format. Convertissez votre audio avant l’envoi :- Encodage : PCM16 (entier signé 16 bits, petit-boutiste)
- Fréquence d’échantillonnage : 24000 Hz
- Canaux : mono
audio/pcm@24000. Déclarer un autre format (comme G.711/µ-law) en entrée ou en sortie est refusé et entraîne la fermeture de la session.
Contrairement à la transcription, les sessions de conversation prennent en charge la détection d’activité vocale (turn_detection / VAD). Lorsqu’elle est activée, le modèle détermine automatiquement la fin d’une prise de parole et déclenche une réponse ; lorsqu’elle est désactivée (valeur
null), vous contrôlez vous-même le moment de valider l’audio et de demander une réponse. Choisissez selon vos besoins.Configuration de session (session.update)
Une fois la connexion établie, le client peut envoyer une tramesession.update pour configurer les paramètres de conversation (voix, instructions système, activation du VAD). Le modèle de la session de conversation est déjà ancré par l’URL de connexion, donc vous pouvez converser sans envoyer session.update ; envoyez-la lorsque vous avez besoin d’une voix ou d’instructions personnalisées.
Paramètres de configuration
string
requis
Type de session,
realtime pour le scénario de conversation.string
Instructions système qui définissent le rôle, le ton et les contraintes de réponse du modèle.
string[]
Modalités de sortie,
["audio"] ou ["text"] : avec ["audio"] (par défaut), le modèle produit de la voix et le texte de la réponse arrive via l’événement response.output_audio_transcript.delta ; avec ["text"], il ne produit que du texte, transmis via response.output_text.delta. Toute autre combinaison (par exemple ["audio", "text"]) est refusée et renvoie un événement error.object
requis
Format audio d’entrée, fixé à
{ "type": "audio/pcm", "rate": 24000 }.object | null
Détection d’activité vocale. Transmettez
{ "type": "server_vad" } pour activer la détection automatique des tours ; transmettez null pour la désactiver et valider l’audio et demander les réponses manuellement depuis le client.object
requis
Format audio de sortie, fixé à
{ "type": "audio/pcm", "rate": 24000 }.string
Voix de la réponse audio. Elle ne peut plus être modifiée une fois la première réponse commencée : une fois la session en état de génération, un
voice renvoyé est ignoré (les autres réglages restent appliqués). Définissez donc la voix avant de demander la première réponse.Les capacités suivantes ne sont pas prises en charge dans cette version et ferment la session lorsqu’elles sont configurées (code de fermeture
1008) : activer la transcription intégrée dans une session de conversation (audio.input.transcription, raison input_transcription_not_supported), injecter de l’audio (raison item_audio_not_supported) ou des images (raison image_input_not_supported) via les items de conversation, et tout type d’item de contenu autre que le texte (raison unsupported_content_part). Envoyez tout l’audio via le canal input_audio_buffer.append.Envoi de l’entrée
Envoi d’audio
Découpez l’audio PCM16 en petits fragments (par exemple un fragment toutes les 100 ms), encodez-les en base64 et envoyez-les en continu avec l’événementinput_audio_buffer.append :
Envoi de texte
Vous pouvez aussi injecter directement un message texte puis demander une réponse :Réception des réponses
Le serveur continue de pousser des événements. Types d’événements clés :event
Confirmation de la création de la session ou de la mise à jour de sa configuration. Vous pouvez commencer à envoyer de l’audio et du texte dès réception de
session.created.event
Un item de conversation a été écrit : chaque entrée utilisateur et chaque réponse du modèle ajoute un item.
event
Lorsque la VAD est activée, le serveur a détecté que l’utilisateur commence ou arrête de parler. Un événement
speech_started signifie généralement que l’utilisateur interrompt le modèle ; voir Interruption et troncature.event
Une réponse a commencé à être générée.
event
L’item de sortie de la réponse a commencé et s’est terminé. Le champ
item.id de l’événement added est l’ID d’item de conversation à référencer pour tronquer l’audio ensuite.event
Un fragment incrémental de l’audio de la réponse (PCM16 encodé en base64) et son marqueur de fin, que vous pouvez lire au fil de l’arrivée.
event
La transcription incrémentale correspondant à l’audio de la réponse, phrase par phrase, et son marqueur de fin ; le champ
delta contient le texte ajouté. Lorsque la sortie audio est activée, prenez le texte de la réponse dans cet événement, par exemple pour afficher des sous-titres pendant la lecture.event
Un fragment incrémental d’une réponse en texte seul et son marqueur de fin, émis uniquement lorsque la modalité de sortie est le texte seul (
output_modalities: ["text"]).event
Une réponse est terminée. Cet événement porte l’usage de tokens du tour (
usage), sur lequel repose la facturation.event
Confirmation que la demande de troncature a pris effet ; voir Interruption et troncature.
event
Événement d’erreur, avec un code et une description. Un problème lié à la requête elle-même (par exemple une valeur
output_modalities invalide) renvoie un seul événement error et la session reste utilisable ; les questions de politique (changement de modèle, solde épuisé) ferment la session.Choisissez le bon événement pour le texte de la réponse. Par défaut (sortie incluant l’audio), le modèle ne pousse que
response.output_audio_transcript.delta et ne pousse pas response.output_text.delta ; définissez la modalité de sortie sur texte seul et le texte passe à response.output_text.delta. Écoutez les deux dans chaque mode pour ne jamais perdre de texte (voir la sortie mesurée ci-dessous).Interruption et troncature
Lorsque l’utilisateur se met à parler pendant que le modèle parle, le contenu déjà généré mais pas encore lu entre en conflit avec la phrase suivante de l’utilisateur. Sur une connexion WebSocket, la lecture est gérée par le client : c’est donc au client de terminer le nettoyage après une interruption. Lorsque la VAD est activée, le serveur envoieinput_audio_buffer.speech_started dès qu’il détecte que l’utilisateur a commencé à parler. À réception de cet événement, le client doit :
- Arrêter immédiatement la lecture locale et noter jusqu’où la réponse avait été lue (en millisecondes).
- Envoyer
conversation.item.truncatepour retirer de la conversation l’audio non lu, afin que le modèle ne le considère pas comme prononcé au tour suivant.
item_id: l’ID d’item de conversation de cette réponse, repris deitem.iddans l’événementresponse.output_item.added.content_index: l’index de la partie de contenu audio, toujours0.audio_end_ms: la longueur d’audio à conserver, en millisecondes, selon la position réellement lue par le client.
conversation.item.truncated une fois la demande traitée. La troncature n’affecte que l’audio de cette réponse et sa transcription ; la session n’est pas modifiée et vous pouvez enchaîner le tour suivant. Avec le SDK OpenAI, appelez conn.conversation.item.truncate(item_id=..., content_index=0, audio_end_ms=...).
Lorsque la VAD est désactivée (par exemple en push-to-talk), l’appui sur le bouton constitue l’interruption : envoyez response.cancel pour annuler la réponse en cours, puis tronquez comme décrit ci-dessus ; au relâchement, envoyez input_audio_buffer.append, input_audio_buffer.commit, puis response.create dans cet ordre.
Exemples complets
Trois approches sont présentées ci-dessous ; choisissez-en une :- SDK OpenAI officiel (recommandé) : pas besoin d’écrire les trames WebSocket à la main ; pointez
websocket_base_url(le paramètre d’URL de base WebSocket du SDK) vers la passerelle et réutilisez la bibliothèque officielle. - SDK OpenAI Agents : la forme vocale temps réel du framework d’agents officiel ; remplacez l’
urldemodel_configpar l’adresse de la passerelle. - websockets brut : sans SDK, échangez les trames directement selon le protocole. Le moins de dépendances et le plus simple à déboguer.
Pourquoi transmettre le nom du modèle à la connexion ? La passerelle AiHubMix a besoin du
model au moment de la poignée de main WebSocket pour sélectionner le fournisseur de modèles, authentifier et réserver le quota, alors que session.update n’arrive qu’après la fin de la poignée de main. Avec un SDK, vous devez donc passer model explicitement à connect() (le SDK l’insère dans la requête URL) ; sans lui, la passerelle refuse pendant la poignée de main et aucune connexion ne s’établit. Contrairement à la transcription, le point de terminaison de conversation n’a pas besoin de intent=transcription.Réutiliser les exemples officiels
La plupart des exemples de conversation en temps réel publiés par OpenAI ne dépendent que du paramètre d’URL de base du SDK : il suffit de pointer l’adresse vers le point de terminaison AiHubMix pour les réutiliser :Sortie mesurée (en production)
Voici le résultat réel de l’exemple du SDK OpenAI sur l’environnement de productionaihubmix.com avec le modèle gpt-realtime-2.1. La session active server_vad, et les prompts comme l’audio sont en anglais.
Entrée texte
Confirmation mesurée : par défaut (sortie incluant l’audio), le texte de la réponse n’arrive caractère par caractère que via
response.output_audio_transcript.delta, et response.output_text.delta n’apparaît jamais ; response.done porte l’usage du tour ; la poignée de main prend environ 2 à 4 secondes, soit le coût de la réservation de quota à l’établissement de la session.Facturation
- Facturation au token : une session de conversation renvoie l’usage de tokens de chaque tour (
usage) avec l’événementresponse.done, et la facturation s’appuie dessus. L’usage est mesuré séparément par composant, notamment entrée audio, sortie audio, entrée texte et sortie texte. Le prix unitaire de chaque composant suit le prix affiché en direct sur la page de détail du modèle. - Règlement à l’usage : il s’agit d’une connexion durable, et les frais sont déduits en temps réel à chaque tour pendant la session, sans règlement unique à la fin. L’établissement d’une session effectue d’abord une réservation de quota d’environ une minute d’usage (un contrôle d’admission uniquement, pas une facturation réelle), et la réservation restante est libérée à la fin de la session. Le solde disponible de votre compte doit donc couvrir au moins environ une minute d’usage pour qu’une session puisse s’établir.
- Chaque enregistrement de facturation de conversation en temps réel est consultable ligne par ligne dans Usage et facturation.
Limites et contraintes
- Durée d’une session : une connexion WebSocket dure au maximum 62 minutes, après quoi le serveur la ferme (code de fermeture
1000, raisonsession_duration_limit) ; découpez en segments si vous avez besoin de plus longtemps. - Déconnexion pour inactivité : lorsque ni le client ni le modèle n’a d’activité pendant 5 minutes, le serveur ferme la session (code de fermeture
1008, raisonidle_timeout). L’activité d’un côté ou de l’autre réinitialise le minuteur : une longue réponse diffusée en continu n’est donc pas interrompue. - Solde insuffisant : à l’établissement de la session, si le solde disponible ne couvre pas la réservation d’environ une minute, la poignée de main est refusée d’emblée (HTTP 403) et aucune session ne s’établit ; pendant la session, si le solde s’épuise, la connexion établie est fermée immédiatement.
- Côté serveur uniquement : les connexions directes depuis un navigateur ne sont pas prises en charge (l’en-tête
Originest vérifié) ; intégrez depuis votre serveur. - Modèle verrouillé : le modèle est fixé dans l’URL de connexion, et le changer avec
session.updatependant la session est refusé et ferme la session. - Format verrouillé : l’audio en entrée et en sortie ne prend en charge que
audio/pcm@24000mono ; les autres formats sont refusés. - Voix verrouillée :
voicene peut pas être modifié après le début de la première réponse ; définissez-le avant de demander la première réponse. - Pas encore pris en charge : la transcription intégrée dans une session de conversation, l’injection d’audio ou d’images via les items de conversation, et tout type d’item de contenu autre que le texte.
- Une réponse à la fois : une session n’autorise qu’une seule réponse en cours ; envoyer un autre
response.createavant la fin du tour en cours est refusé et ferme la session (code de fermeture1008, raisonresponse_already_active).
Erreurs courantes
Dernière mise à jour : 2026-09-21