Choisissez l’API utilisée par votre application. Chaque API possède ses propres mécanismes d’authentification et de création de sessions, ainsi que son propre contrat d’événements.
Contrôlez une session GPT-Live depuis votre serveur
Connectez votre serveur d’application à une session GPT-Live WebRTC ou SIP existante lorsque le serveur doit recevoir les événements de conversation, exécuter des outils privés ou mettre à jour la conversation. Cette seconde connexion est appelée WebSocket auxiliaire. Les deux connexions partagent une même session, tandis que WebRTC ou SIP transporte le flux audio principal.
Le canal auxiliaire transporte les événements et les commandes. Votre application assure l’exécution des outils, les vérifications d’autorisation et l’application des règles métier. Conservez les clés API et les identifiants d’accès aux outils sur votre serveur.
Déterminez si vous avez besoin d’un canal auxiliaire
Pour les applications dans le navigateur, utilisez le canal de données WebRTC pour les sous-titres et les mises à jour de l’interface locale. Utilisez un canal auxiliaire lorsque le traitement des transcriptions s’effectue sur votre serveur, par exemple pour les vérifications des garde-fous, l’analyse des sentiments ou les appels d’outils spéculatifs. Votre serveur peut recevoir les événements et piloter directement la même session, tandis que l’audio du navigateur continue de transiter par WebRTC. Consultez Réagissez aux fragments de transcription pour voir des exemples.
Si votre backend gère déjà la connexion WebSocket principale, il reçoit déjà les événements de la session et peut envoyer des commandes.
La délégation à Responses fonctionne également sans canal auxiliaire. Le navigateur peut transmettre les événements d’appel de fonction depuis son canal de données à un backend authentifié pour les exécuter. Les outils hébergés par OpenAI s’exécutent via le backend auquel le travail est délégué, sans nécessiter de composant d’exécution d’outils dans l’application.
Connectez-vous à la session existante
-
Enregistrez l’identifiant de la session que votre backend contrôlera. Pour WebRTC, utilisez
session.iddans la réponse JSON àPOST /v1/live/sessions. Pour SIP, acceptez d’abord l’appel entrant, puis utilisezdata.session_iddans son webhook. Conservez cet identifiant avec les données de l’utilisateur et de la conversation dans votre application. -
Ouvrez une connexion WebSocket depuis votre serveur à l’URL suivante, en y insérant l’identifiant enregistré sans le modifier. Authentifiez-vous avec
Authorization: Bearer $OPENAI_API_KEYen utilisant les informations d’authentification du projet qui a créé ou accepté la session. Incluez les mêmes en-têtes de connexion que ceux requis lors de la création de la session.wss://api.openai.com/v1/live/sessions/{session_id}/attach -
Recevez les événements et envoyez les commandes sur le socket connecté à la session. La session est déjà en cours d’exécution ; n’envoyez pas à nouveau
session.start.
Traitez l’identifiant de session comme une valeur opaque. Préservez son préfixe et utilisez-le uniquement pour la session à laquelle votre application est autorisée à accéder. Lisez l’identifiant dans la réponse JSON de Live, plutôt que dans un en-tête Location ou un paramètre d’URL call_id de Realtime.
Observez les événements et envoyez des commandes
| Tâche | Événements ou commandes |
|---|---|
| Suivez la conversation | Recevez les deltas de transcription de l’utilisateur et de l’assistant, les événements de délégation et les événements Responses imbriqués. |
| Mettez à jour la configuration du backend | Utilisez session.update pour modifier les paramètres pris en charge dans le mode de délégation existant. Les paramètres de démarrage, tels que le modèle frontend et la configuration audio, restent fixes. |
| Fournissez du contexte | Utilisez session.instructions.append pour les instructions, session.thinking.append pour le contexte à ne pas énoncer et session.commentary.append pour les mises à jour pouvant être énoncées. |
| Renvoyez les résultats des outils | Avec la délégation à Responses, envoyez response.item.create, puis response.create pour poursuivre le travail du backend. |
| Contrôlez l’entrée du microphone | Utilisez session.input_audio.mute et session.input_audio.unmute. Couper l’entrée audio n’arrête pas la sortie de l’assistant. |
| Terminez la session | Envoyez session.close et attendez de recevoir session.closed avant de vous déconnecter. |
Les commandes suivent les mêmes règles de validation et de délégation que sur la connexion principale. Pour les ajouts de contexte, utilisez delegation_id: null pour le contexte général de la session ; un identifiant non nul doit désigner une délégation client existante. Consultez Délégation et outils pour la configuration, l’exécution des fonctions et les exemples d’ajout de contexte.
Pour les sessions dans le navigateur, conservez l’entrée du microphone et la sortie des haut-parleurs sur la piste multimédia WebRTC négociée. Utilisez le canal auxiliaire pour les événements de conversation et le contrôle. Un événement de transcription ou un accusé de réception de commande ne prouve pas que l’audio a été diffusé ni que l’utilisateur l’a entendu.
Recevez des copies des flux audio
Un canal auxiliaire reçoit également des copies des flux audio d’entrée et de sortie qui suivent, tandis que la connexion principale transporte les médias en direct :
| Événement | Champ audio | Repères temporels |
|---|---|---|
session.input_audio.append | audio | Aucun horodatage. |
session.output_audio.delta | delta | start_ms et end_ms décrivent l’intervalle occupé par la sortie sur la chronologie de la session. |
Les deux charges utiles contiennent de l’audio brut mono PCM16LE à 24 kHz encodé en base64, quel que soit le format audio du transport principal. Aucun des deux événements ne possède de event_id. La copie du flux d’entrée contient l’audio reçu avant l’application de la coupure de l’entrée ; elle ne confirme pas que le modèle a traité ces échantillons. Les intervalles du flux de sortie copié peuvent présenter des lacunes dues à des trames supprimées et n’indiquent pas à quel moment l’appelant a entendu l’audio.
Il s’agit d’événements serveur, qui n’autorisent pas l’envoi d’audio par le canal auxiliaire. Envoyez l’audio du microphone via le transport principal ; n’envoyez pas session.input_audio.append sur le socket connecté à la session.
Attribuez chaque action à un seul responsable
Choisissez, pour chaque action, si elle est prise en charge par le navigateur ou le backend. Si les deux connexions reçoivent un événement d’appel de fonction, exécutez la fonction une seule fois. Appliquez la même règle de responsabilité aux mises à jour du contexte et aux demandes de poursuite du travail du backend.
Stockez les transcriptions et l’état des outils dans votre application. Établissez la connexion tôt si le backend doit observer la conversation dès le début, et conservez tout historique recueilli avant la connexion. Ne comptez pas sur cette connexion pour reconstituer les transcriptions ou les résultats d’outils antérieurs.
Un canal auxiliaire ne rend pas, à lui seul, les événements de session inaccessibles au navigateur. Conservez les identifiants sensibles d’accès aux outils et les décisions d’autorisation dans votre backend, et ne renvoyez que le contexte nécessaire à la conversation.
Appliquez des garde-fous à la conversation
Utilisez la connexion de votre serveur pour surveiller la conversation, vérifier que les demandes respectent les politiques de votre application et intervenir lorsqu’une vérification détecte un problème. Un canal auxiliaire donne à votre serveur accès aux événements et aux commandes de la session ; votre application effectue les vérifications et applique les mesures qui en découlent. Le même workflow s’applique lorsque votre serveur gère déjà la connexion WebSocket principale.
Effectuez les vérifications en parallèle de la conversation
Les garde-fous sont l’un des usages du traitement des fragments de transcription à mesure qu’ils arrivent. Le même flux peut déclencher une recherche spéculative ou mettre à jour l’interface en parallèle de ces vérifications.
- Surveillez les transcriptions. Accumulez les fragments
session.input_transcript.deltapour détecter dans les demandes des utilisateurs les tentatives de jailbreak, les informations sensibles ou les violations des politiques. Utilisezsession.output_transcript.deltapour repérer dans les propos de l’assistant les affirmations non étayées ou les réponses hors du périmètre de votre application. Gardez chaque vérification associée à la transcription et à la demande de l’application qu’elle a évaluées. - Effectuez les vérifications en parallèle. Un modèle rapide et léger peut évaluer les demandes pendant que la conversation se poursuit. Renvoyez un résultat structuré compact, tel que
{"triggered": true}, que votre application peut exploiter. Maintenez le blocage des actions nécessitant une approbation jusqu’à ce qu’elles aient passé leurs vérifications avec succès ; un délai dépassé ou une vérification échouée ne vaut pas approbation. - Bloquez les actions concernées. Lorsqu’une vérification détecte un problème, marquez la demande comme bloquée dans l’état de l’application. Vérifiez cet état avant d’exécuter un outil ou de valider une modification, y compris pour le travail déjà en file d’attente. Un refus exprimé oralement n’empêche pas un outil de s’exécuter.
- Arrêtez le travail associé. Annulez les tâches gérées par l’application lorsque votre backend prend en charge l’annulation, et ignorez les résultats tardifs des demandes bloquées ou remplacées. Avec la délégation à Responses, cessez d’exécuter les fonctions personnalisées concernées et n’envoyez pas
response.createpour poursuivre un travail bloqué. Cela n’annule pas une réponse hébergée déjà en cours d’exécution et n’arrête pas la parole du frontend. - Consignez la décision et réorientez la conversation. Journalisez la décision avec les identifiants des demandes et des délégations concernées, puis envoyez une instruction corrective. Un nom d’événement tel que
guardrail.triggeredrelève de la télémétrie de votre application ; ce n’est pas un événement de l’API GPT-Live.
Consultez Deltas de transcription pour recueillir les fragments et Délégation et outils pour que les résultats du backend restent cohérents avec la tâche en cours.
Réorientez la conversation
Utilisez session.instructions.append pour réorienter la conversation en fonction des garde-fous. Cette commande peut interrompre une prise de parole en cours et appliquer une nouvelle instruction. Par exemple, après le blocage d’une demande par votre application, envoyez :
export function sendUpdate(connection) {
connection.send({
type: "session.instructions.append",
event_id: "guardrail_block_17",
delegation_id: null,
content:
"Stop speaking immediately. Do not continue or act on the last request. Refuse briefly, then wait.",
});
}Veillez à ce que l’instruction soit rédigée par l’application. N’y copiez pas de texte utilisateur non fiable en tant qu’instruction. Utilisez delegation_id: null pour cette correction à l’échelle de la session, et limitez content à 500 tokens.
Associez session.instructions.appended à votre commande à l’aide de client_event_id. L’accusé de réception arrive après le moment estimé de l’injection du contexte ; il ne prouve pas que l’assistant a cessé de parler ni que la lecture de l’audio en attente s’est arrêtée. Les instructions correctives ne peuvent pas retirer ce que l’utilisateur a déjà entendu.
Pour les annonces qui demandent une formulation orale précise, utilisez également des instructions. Consultez Diffuser une annonce pour obtenir un exemple et connaître les points à prendre en compte pour la lecture audio.
Contrôlez la lecture si nécessaire
Testez d’abord les instructions correctives et le blocage des actions. Si votre application doit aussi bloquer l’audio du modèle, contrôlez la sortie au niveau du client ou du relais multimédia : coupez temporairement le son ou supprimez la sortie, supprimez l’audio en attente dans la file locale, envoyez l’instruction corrective, puis reprenez la lecture conformément à la politique de reprise de votre application. Supprimez l’audio obsolète avant de reprendre. Un canal auxiliaire ne contrôle pas à lui seul le cheminement des flux multimédias, et l’accusé de réception d’une instruction ne constitue pas un signal de reprise de la lecture.
session.input_audio.mute contrôle l’entrée microphone de l’appelant. Cette commande ne coupe pas la sortie du modèle et n’annule pas le travail délégué.
GPT-Live transmet des fragments de transcription en continu pendant qu’il parle. Si une vérification doit se terminer avant que l’utilisateur entende l’audio, votre application doit mettre l’audio en mémoire tampon et en approuver la lecture au préalable. Cela ajoute de la latence. La suppression de l’audio peut aussi laisser le contexte de conversation du modèle en avance sur ce que l’utilisateur a entendu ; testez donc la reprise de la conversation.
Testez l’intervention
Testez les requêtes autorisées et bloquées, les faux positifs, les vérifications lentes ou en échec, le déclenchement d’une intervention pendant la prise de parole ou l’exécution d’un outil, ainsi que les résultats tardifs de travaux annulés. Vérifiez séparément le blocage des actions, l’état de l’application, les paroles correctives et la lecture effective de l’audio. Si vous contrôlez la sortie, incluez l’audio en attente et la reprise dans le test. Utilisez le Cookbook sur l’évaluation des agents vocaux pour comparer la réussite des tâches et le temps de réponse vocale.
Terminez proprement
Continuez à recevoir les événements tant que le backend prend en charge l’exécution des outils ou la collecte des données finales d’utilisation. Enregistrez le gestionnaire de session.closed avant d’envoyer session.close, et gardez la connexion WebRTC, le canal de données et le canal auxiliaire ouverts jusqu’à la fin des travaux en attente. Enregistrez les données finales d’utilisation de la session et toutes les données d’utilisation du backend reçues dans les événements Responses avant le nettoyage. Si la connexion échoue avant l’arrivée de l’événement final, consignez la finalisation comme incomplète. Consultez Gestion des sessions pour connaître la séquence de fermeture.
La Realtime API permet aux clients de se connecter directement au serveur de l’API via WebRTC ou SIP. Vous souhaiterez toutefois probablement conserver l’utilisation des outils et le reste de la logique métier sur votre serveur d’application, afin que cette logique reste privée et indépendante du client.
Gardez l’utilisation des outils, la logique métier et les autres détails à l’abri côté serveur en vous connectant via un canal de contrôle auxiliaire. Des options de canal auxiliaire sont désormais disponibles pour les connexions SIP et WebRTC.
Avec un canal auxiliaire, deux connexions à la même session Realtime sont actives : l’une depuis le client de l’utilisateur et l’autre depuis votre serveur d’application. La connexion du serveur permet de surveiller la session, de mettre à jour les instructions et de répondre aux appels d’outils.
Avec WebRTC
- Lorsque vous établissez une connexion entre pairs, vous envoyez une requête à la Realtime API et recevez une réponse SDP pour configurer la connexion. Si vous avez utilisé l’exemple de code du guide WebRTC, cela ressemble à ceci :
const baseUrl = "https://api.openai.com/v1/realtime/calls";
const sdpResponse = await fetch(baseUrl, {
method: "POST",
body: offer.sdp,
headers: {
Authorization: `Bearer ${EPHEMERAL_KEY}`,
"Content-Type": "application/sdp",
},
});- La réponse à la requête fetch contiendra un en-tête
Locationcomportant un identifiant d’appel unique, que le serveur pourra utiliser pour établir une connexion WebSocket à cette même session Realtime.
// Location: /v1/realtime/calls/rtc_123456
const location = sdpResponse.headers.get("Location");
const callId = location?.split("/").pop();
console.log(callId);- Sur un serveur, vous pouvez ensuite écouter les événements et configurer la session comme avec une connexion WebSocket classique à la Realtime API, en utilisant cet identifiant d’appel dans l’URL
wss://api.openai.com/v1/realtime?call_id=rtc_xxxxx, comme illustré ci-dessous :
import WebSocket from "ws";
const callId = "rtc_u1_9c6574da8b8a41a18da9308f4ad974ce";
// Connect to a WebSocket for the in-progress call
const url = "wss://api.openai.com/v1/realtime?call_id=" + callId;
const ws = new WebSocket(url, {
headers: {
Authorization: "Bearer " + process.env.OPENAI_API_KEY,
},
});
ws.on("open", function open() {
console.log("Connected to server.");
// Send client events over the WebSocket once connected
ws.send(
JSON.stringify({
type: "session.update",
session: {
type: "realtime",
instructions: "Be extra nice today!",
},
})
);
});
// Listen for and parse server events
ws.on("message", function incoming(message) {
console.log(JSON.parse(message.toString()));
});Vous pouvez ainsi ajouter des outils, surveiller les sessions et exécuter la logique métier sur le serveur, sans avoir à configurer ces actions sur le client.
Avec SIP
- Un utilisateur se connecte à OpenAI par téléphone via SIP.
- OpenAI envoie un webhook à l’URL de webhook du serveur de votre application pour l’informer de l’état de la session. Le webhook ressemble à ceci :
POST https://my_website.com/webhook_endpoint
user-agent: OpenAI/1.0 (+https://platform.openai.com/docs/webhooks)
content-type: application/json
webhook-id: wh_685342e6c53c8190a1be43f081506c52 # unique id for idempotency
webhook-timestamp: 1750287078 # timestamp of delivery attempt
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4= # signature to verify authenticity from OpenAI
{
"object": "event",
"id": "evt_685343a1381c819085d44c354e1b330e",
"type": "realtime.call.incoming",
"created_at": 1750287018, // Unix timestamp
"data": {
"call_id": "some_unique_id",
"sip_headers": [
{ "name": "From", "value": "sip:+142555512112@sip.example.com" },
{ "name": "To", "value": "sip:+18005551212@sip.example.com" },
{ "name": "Call-ID", "value": "03782086-4ce9-44bf-8b0d-4e303d2cc590"}
]
}
}
- Le serveur d’application ouvre une connexion WebSocket à la Realtime API en utilisant la valeur
call_idfournie dans le webhook, via une URL comme celle-ci :wss://api.openai.com/v1/realtime?call_id={callId}. La connexion WebSocket reste active pendant toute la durée de l’appel SIP.
La connexion WebSocket peut ensuite servir à envoyer et recevoir des événements pour contrôler l’appel, comme si la session avait été lancée avec une connexion WebSocket. Cela permet notamment de surveiller l’appel, de mettre à jour les instructions de manière dynamique et de répondre aux appels d’outils.