Choisissez votre API pour afficher les étapes de connexion et les événements de session correspondants.
Contrôlez une session GPT-Live depuis votre serveur
Connectez votre serveur d’application à une session GPT-Live existante sur WebRTC ou SIP lorsqu’il doit recevoir des événements de conversation, exécuter des outils privés ou mettre à jour la conversation. Cette seconde connexion est appelée connexion WebSocket auxiliaire. Les deux connexions partagent la même session, et le flux audio principal passe par WebRTC ou SIP.
La connexion auxiliaire transmet les événements et les commandes. Votre application exécute les outils, vérifie les autorisations et applique les 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’une connexion auxiliaire
Pour les applications qui s’exécutent dans un navigateur, utilisez le canal de données WebRTC pour afficher les sous-titres et mettre à jour l’interface locale. Utilisez une connexion auxiliaire lorsque votre serveur traite les transcriptions, par exemple pour appliquer des garde-fous, analyser les sentiments ou lancer des appels d’outils par anticipation. Votre serveur peut recevoir les événements et piloter directement la même session pendant que le navigateur continue de transmettre l’audio via WebRTC. Vous trouverez des exemples dans la section Réagissez aux fragments de transcription.
Si votre backend transmet l’audio via la connexion WebSocket principale, utilisez cette connexion pour recevoir les événements et envoyer les commandes.
La délégation à Responses fonctionne aussi sans connexion auxiliaire. Le navigateur peut transmettre les événements d’appel de fonction de son canal de données à un backend authentifié qui exécutera les fonctions. Les outils hébergés par OpenAI s’exécutent via le backend chargé de la délégation, sans nécessiter de mécanisme d’exécution des outils dans votre application.
Connectez votre serveur à la session existante
-
Enregistrez l’identifiant de la session que votre backend doit contrôler. Pour WebRTC ou un appel SIP sortant, utilisez
session.iddans la réponse JSON àPOST /v1/live/sessions. Pour un appel SIP entrant, acceptez d’abord l’appel, puis utilisezdata.session_iddans le webhook associé. Conservez l’identifiant avec les données que votre application enregistre sur l’utilisateur et la conversation. -
Depuis votre serveur, ouvrez une connexion WebSocket à l’URL suivante en remplaçant le paramètre par l’identifiant enregistré, sans le modifier. Authentifiez-vous avec
Authorization: Bearer $OPENAI_API_KEYen utilisant les identifiants du projet qui a créé ou accepté la session. Incluez les mêmes en-têtes de connexion que ceux requis à 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 la connexion ainsi établie. La session est déjà en cours. N’envoyez pas de nouveau
session.start.
Utilisez l’identifiant de session tel quel, préfixe compris, et vérifiez que votre application est autorisée à accéder à cette session.
Observez les événements et envoyez des commandes
| Tâche | Événements ou commandes |
|---|---|
| Suivre la conversation | Recevez les fragments successifs de transcription de l’utilisateur et de l’assistant, les événements de délégation et les événements Responses imbriqués. |
| Mettre à jour la configuration du backend | Utilisez session.update pour modifier les paramètres pris en charge dans le mode de délégation en cours. Les paramètres de démarrage, comme le modèle du frontend et la configuration audio, restent fixes. |
| Fournir du contexte | Utilisez session.instructions.append pour les instructions, session.thinking.append pour le contexte à prendre en compte sans le prononcer et session.commentary.append pour les mises à jour que l’assistant peut communiquer à voix haute. |
| Renvoyer les résultats des outils | Avec la délégation à Responses, envoyez response.item.create, puis response.create pour poursuivre le traitement côté backend. |
| Contrôler l’entrée du microphone | Utilisez session.input_audio.mute et session.input_audio.unmute. Couper le microphone n’interrompt pas la sortie audio de l’assistant. |
| Terminer 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 ajouter du contexte général à la session, utilisez delegation_id: null. Si vous fournissez un identifiant non nul, il doit correspondre à une délégation cliente existante. Consultez la section Délégation et outils pour la configuration, l’exécution des fonctions et des exemples d’ajout de contexte.
Pour les sessions dans un navigateur, utilisez la piste multimédia WebRTC négociée pour l’entrée du microphone et la sortie vers les haut-parleurs. Utilisez la connexion auxiliaire pour recevoir les événements et contrôler la conversation, et suivez la lecture dans votre lecteur audio.
Recevez une copie des flux audio
Une fois établie, la connexion auxiliaire reçoit aussi une copie de l’audio entrant et sortant, tandis que la connexion principale transporte le flux multimédia 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 indiquent le début et la fin de l’extrait audio sur la chronologie de la session. |
Dans les deux cas, les données sont au format PCM16LE brut, en mono à 24 kHz, et encodées en base64, quel que soit le format audio du transport principal. Aucun des deux événements ne comporte d’event_id. La copie du flux entrant contient l’audio reçu en amont de la coupure du son en entrée. Elle ne confirme pas que le modèle a traité ces échantillons. Des trames perdues peuvent laisser des intervalles vides dans la copie du flux sortant. Les plages temporelles de ce flux n’indiquent pas quand l’appelant a entendu l’audio.
Envoyez l’audio du microphone uniquement sur la connexion principale. Utilisez la connexion auxiliaire pour recevoir une copie des flux audio.
Attribuez chaque action à un seul responsable
Pour chaque action, choisissez qui la prend en charge, 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 aux mises à jour du contexte et aux demandes de poursuite du traitement côté backend.
Établissez la connexion auxiliaire dès le début si le backend doit suivre toute la conversation. Enregistrez les transcriptions et l’état des outils dans votre application, y compris l’historique recueilli avant la connexion.
Le navigateur peut toujours recevoir les événements de session lorsque la connexion auxiliaire est établie. Conservez les identifiants d’accès sensibles des outils et les décisions d’autorisation dans votre backend. Renvoyez uniquement le contexte nécessaire à la conversation.
Appliquez des garde-fous à la conversation
Utilisez la connexion WebSocket principale ou la connexion auxiliaire de votre serveur pour suivre la conversation et vérifier que les demandes respectent les règles de votre application. Votre application effectue les vérifications, bloque les actions concernées et envoie des instructions correctives lorsqu’un contrôle déclenche une alerte.
Effectuez les vérifications en parallèle de la conversation
L’application de garde-fous est l’un des usages du traitement des fragments de transcription à mesure qu’ils arrivent. En parallèle des vérifications, ce même flux peut servir à lancer une recherche par anticipation ou à mettre à jour l’interface.
- Surveillez les transcriptions. Assemblez les fragments
session.input_transcript.deltapour détecter les tentatives de jailbreak, les informations sensibles ou les infractions aux règles dans les demandes de l’utilisateur. Utilisezsession.output_transcript.deltapour repérer dans les propos de l’assistant les affirmations non étayées ou les réponses qui sortent du périmètre de votre application. Gardez une trace de la transcription et de la demande applicative sur lesquelles portait chaque vérification. - Exécutez les vérifications en parallèle. Un modèle léger et rapide peut évaluer les demandes pendant que la conversation se poursuit. Renvoyez un résultat structuré et concis, par exemple
{"triggered": true}, sur lequel votre application pourra s’appuyer pour agir. N’exécutez les actions soumises à approbation qu’une fois leurs vérifications réussies. Maintenez le blocage si une vérification échoue ou dépasse le délai imparti. - Bloquez les actions concernées. Lorsqu’un contrôle déclenche une alerte, marquez la demande comme bloquée dans l’état de l’application. Consultez cet état avant d’exécuter un outil ou de valider une modification, y compris pour les tâches déjà en file d’attente.
- Arrêtez les tâches concernées. Annulez les tâches gérées par votre application lorsque votre backend permet leur annulation. Écartez 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 traitement bloqué. Ces mesures n’annulent pas une réponse hébergée déjà en cours et n’interrompent pas la parole côté frontend. - Consignez la décision et réorientez la conversation. Enregistrez la décision dans les journaux avec les identifiants de demande et de délégation concernés, puis envoyez une instruction corrective.
Consultez la section Fragments successifs de transcription pour recueillir les fragments, et la section Délégation et outils pour veiller à ce que les résultats du backend correspondent à la tâche en cours.
Réorientez la conversation
Utilisez session.instructions.append pour réorienter la conversation lorsqu’un garde-fou se déclenche. Cette commande peut interrompre la prise de parole en cours et appliquer une nouvelle instruction. Par exemple, après avoir bloqué une demande dans votre application, envoyez la commande suivante.
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.",
});
}Définissez l’instruction dans votre application. N’y recopiez pas de texte utilisateur non fiable en le présentant comme une instruction. Utilisez delegation_id: null pour appliquer cette correction à l’ensemble 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. Pour empêcher l’appelant d’entendre l’audio, utilisez les commandes de lecture décrites ci-dessous.
Utilisez aussi des instructions lorsqu’une mention doit être prononcée dans des termes précis. Consultez la section Énoncez une mention d’information pour un exemple et des précisions sur la lecture audio.
Contrôlez la lecture si nécessaire
Si votre application doit bloquer l’audio du modèle, contrôlez la lecture au niveau du client ou du relais multimédia. Coupez temporairement le son en sortie ou écartez le flux sortant, videz la file d’attente audio locale et envoyez l’instruction corrective. Une fois les données audio obsolètes supprimées, reprenez la lecture selon les règles de reprise de votre application. L’accusé de réception de l’instruction ne constitue pas un signal de reprise. La connexion auxiliaire ne permet pas à elle seule de contrôler la lecture, et une instruction corrective ne peut pas effacer ce que l’appelant a déjà entendu.
session.input_audio.mute contrôle l’entrée du microphone de l’appelant. Cette commande ne coupe pas la sortie audio du modèle et n’annule pas les tâches déléguées.
Vérifiez les propos de l’assistant avant la lecture
Pour la plupart des applications, surveillez les transcriptions de l’utilisateur et de l’assistant pendant que la conversation se poursuit. Lorsqu’un garde-fou se déclenche, votre application peut bloquer les actions concernées ou envoyer des instructions correctives.
Si votre application doit vérifier les propos de l’assistant avant leur lecture, mettez l’audio en mémoire tampon dans votre lecteur ou votre passerelle multimédia avant de le transmettre à l’appelant. Continuez à recevoir les événements audio et de transcription pendant la vérification. Lisez les transcriptions indépendamment de la lecture audio.
- Recueillez l’audio et sa transcription. Pour repérer les segments de parole à vérifier, implémentez la détection d’activité vocale (VAD) en sortie dans votre application ou utilisez un filtre à seuil de bruit fourni par votre framework multimédia. GPT-Live ne fournit ni VAD en sortie ni filtre à seuil de bruit pour ce workflow. Pour chaque segment, attendez la transcription nécessaire à la vérification.
- Transmettez l’audio approuvé. Lorsqu’un segment passe la vérification, ajoutez l’audio original conservé en mémoire tampon à la file de lecture. Si la vérification échoue, si la transcription manque ou si le délai imparti est dépassé, écartez le segment et utilisez une solution de repli sûre définie par votre application.
- Gérez les interruptions. Associez l’audio, la transcription, le résultat de la vérification et l’état de la lecture à un identifiant généré par votre application. Si une interruption annule cette prise de parole, supprimez les données audio correspondantes de la mémoire tampon et de la file de lecture. Ignorez toute approbation ultérieure de cet audio.
Une pause peut délimiter un segment à vérifier alors que le modèle prépare encore sa réponse. Si vos règles exigent de vérifier la réponse dans son intégralité, définissez comment votre application en détermine la fin. La détection d’activité vocale ne suffit pas à établir que la réponse est terminée.
La mise en mémoire tampon augmente la latence. Les propos écartés restent dans le contexte de conversation du modèle. Testez donc la suite de la conversation lorsque vous retenez un segment audio ou utilisez une solution de repli.
Testez l’intervention
Testez les demandes autorisées et bloquées, les faux positifs, les vérifications lentes ou en échec, les alertes déclenchées pendant une prise de parole ou l’exécution d’un outil, ainsi que les résultats tardifs des tâches annulées. Vérifiez séparément le blocage des actions, l’état de l’application, le message correctif prononcé et l’audio effectivement diffusé. Si vous contrôlez la sortie audio, testez aussi la gestion de la file de lecture et la reprise. Utilisez le guide du Cookbook sur l’évaluation des agents vocaux pour comparer le taux de réussite des tâches et le temps de réponse à l’oral.
Terminez la session proprement
Continuez à recevoir les événements pendant que les outils terminent leur exécution et que la session transmet ses données d’utilisation finales. Enregistrez le gestionnaire de session.closed avant d’envoyer session.close. Maintenez la connexion WebRTC, le canal de données et la connexion auxiliaire ouverts jusqu’à la fin des traitements en attente. Avant de libérer les ressources, enregistrez les données d’utilisation finales de la session ainsi que les données d’utilisation du backend reçues dans les événements Responses. Si la connexion échoue avant l’arrivée du dernier événement, consignez que la clôture est incomplète. Consultez la section Gestion des sessions pour connaître les étapes de fermeture.
Realtime API permet aux clients de se connecter directement au serveur de l’API via WebRTC ou SIP. Vous aurez cependant tout intérêt à gérer les 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.
Pour protéger l’utilisation des outils, la logique métier et les autres détails d’implémentation côté serveur, connectez-vous via un canal de contrôle « auxiliaire ». Ce canal est désormais disponible pour les connexions SIP et WebRTC.
Avec un canal auxiliaire, deux connexions à la même session Realtime sont actives simultanément. L’une provient du client de l’utilisateur et l’autre de 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 pair à pair, vous envoyez une requête à Realtime API et recevez une réponse SDP qui sert à configurer la connexion. Si vous avez repris l’exemple de code du guide WebRTC, cette étape 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 contient un en-tête
Locationqui indique un identifiant d’appel unique. Cet identifiant permet au serveur d’établir une connexion WebSocket à la 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 le serveur, vous pouvez ensuite écouter les événements et configurer la session comme avec une connexion WebSocket classique à Realtime API. Utilisez l’identifiant d’appel dans l’URL
wss://api.openai.com/v1/realtime?call_id=rtc_xxxxx, comme dans l’exemple 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()));
});En Go, passez l’identifiant d’appel à votre fonction de mise à jour de session côté serveur.
func updateSession(ctx context.Context, client openai.Client, callID string) error {
conn, err := client.Realtime.Connect(ctx, realtime.RealtimeConnectionOptions{}, option.WithQuery("call_id", callID))
if err != nil {
return err
}
defer conn.Close()
if err := conn.Send(ctx, realtime.RealtimeClientEventParamOfSessionUpdate(realtime.RealtimeSessionCreateRequestParam{
Instructions: openai.String("Be extra nice today!"),
})); err != nil {
return err
}
for {
event, err := conn.Recv(ctx)
if err != nil {
return err
}
if event.Type == "error" {
return fmt.Errorf("Realtime API error: %s", event.OfRealtimeErrorEvent.Error.Message)
}
if event.Type == "session.updated" {
if event.OfSessionUpdatedEvent.Session.OfRealtimeSessionCreateRequest.Instructions != "Be extra nice today!" {
return fmt.Errorf("session update was not applied")
}
fmt.Println("session.updated")
return nil
}
}
}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 prévue à cet effet sur votre serveur d’application pour informer votre application de l’état de la session. Voici un exemple de webhook.
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 à Realtime API en utilisant la valeur
call_idfournie dans le webhook, dans une URL de la formewss://api.openai.com/v1/realtime?call_id={callId}. La connexion WebSocket reste ouverte pendant toute la durée de l’appel SIP.
Vous pouvez ensuite envoyer et recevoir des événements sur la connexion WebSocket pour contrôler l’appel, comme pour une session ouverte via WebSocket. Vous pouvez notamment suivre l’appel, mettre à jour les instructions en cours de conversation et répondre aux appels d’outils.