Lab 059 : Agents vocaux avec GPT Realtime API¶
Ce que vous apprendrez¶
- Comment le GPT-4o Realtime API permet des conversations vocales en duplex intégral avec une latence d'environ 100 ms
- Connecter des clients via WebRTC pour un streaming audio natif au navigateur à faible latence
- Gérer les interruptions (barge-in) — permettre aux utilisateurs d'intervenir pendant que l'agent parle encore
- Intégrer le RAG avec l'audio en temps réel pour que l'agent récupère des données produit en cours de conversation
- Analyser les métriques des sessions vocales : percentiles de latence, sentiment et distribution linguistique
- Évaluer le support multilingue (en, es, fr) dans un déploiement unique d'agent vocal
Introduction¶
Les agents vocaux passent du mode traditionnel de prise de parole alternée — où l'utilisateur parle, attend, puis l'agent répond — à la conversation en temps réel. Le GPT-4o Realtime API traite l'entrée vocale et génère une sortie vocale simultanément, permettant un dialogue naturel en va-et-vient avec une latence inférieure à 100 ms.
OutdoorGear souhaite un assistant vocal pour les demandes de renseignements sur les produits. Les clients appellent, posent des questions sur l'équipement, et l'agent répond avec les détails du produit — le tout en temps réel. Le système doit gérer les interruptions avec élégance (un client peut dire « attendez, en fait… » en pleine réponse), prendre en charge plusieurs langues et récupérer les informations produit depuis un pipeline RAG à la volée.
Vue d'ensemble de l'architecture¶
┌──────────┐ WebRTC ┌────────────────────┐ REST/WS ┌───────────┐
│ Browser │◄──────────►│ Realtime API │◄───────────►│ RAG │
│ (mic + │ audio │ (GPT-4o-realtime) │ tool calls │ (product │
│ speaker) │ stream │ • VAD │ │ search) │
└──────────┘ │ • Barge-in │ └───────────┘
│ • Turn detection │
└────────────────────┘
Concepts clés :
| Concept | Description |
|---|---|
| Realtime API | Point de terminaison voix-vers-voix en duplex intégral — pas de pipeline STT/TTS séparé |
| WebRTC | Protocole natif au navigateur pour le streaming audio/vidéo à faible latence |
| VAD (Voice Activity Detection) | Détecte quand l'utilisateur commence/arrête de parler |
| Barge-in | L'utilisateur peut interrompre l'agent en pleine réponse ; l'agent s'arrête et écoute |
| Détection de tour côté serveur | L'API décide quand le tour de parole de l'utilisateur est terminé |
Prérequis¶
Ce lab analyse des données de session pré-enregistrées — aucune clé API ni abonnement Azure requis. Pour construire un agent vocal en direct, vous auriez besoin d'une ressource Azure OpenAI avec le modèle gpt-4o-realtime-preview déployé.
Démarrage rapide avec GitHub Codespaces
Toutes les dépendances sont pré-installées dans le devcontainer.
📦 Fichiers de support¶
Téléchargez ces fichiers avant de commencer le lab
Enregistrez tous les fichiers dans un dossier lab-059/ dans votre répertoire de travail.
| Fichier | Description | Télécharger |
|---|---|---|
broken_voice.py |
Exercice de correction de bugs (3 bugs + auto-tests) | 📥 Télécharger |
voice_sessions.csv |
Jeu de données | 📥 Télécharger |
Partie 1 : Comprendre l'architecture du Realtime API¶
Étape 1 : En quoi le Realtime API diffère de Chat Completions¶
L'API Chat Completions standard suit un modèle requête-réponse : envoyer du texte, recevoir du texte. Le Realtime API est fondamentalement différent :
| Fonctionnalité | Chat Completions | Realtime API |
|---|---|---|
| Entrée | Texte (JSON) | Flux audio (PCM/WebRTC) |
| Sortie | Texte (JSON) | Flux audio + transcription textuelle |
| Latence | 500–2000 ms | ~100 ms (P50) |
| Duplex | Semi-duplex (requête → réponse) | Duplex intégral (simultané) |
| Interruption | Non supportée | Barge-in supporté |
| Protocole | HTTP REST | WebSocket / WebRTC |
La latence cible d'environ 100 ms rend les conversations vocales naturelles — comparable aux appels téléphoniques entre humains.
Partie 2 : Charger et explorer les données des sessions vocales¶
Étape 2 : Charger 📥 voice_sessions.csv¶
OutdoorGear a enregistré 15 sessions vocales lors d'un test pilote de leur intégration du Realtime API. Chaque session capture une interaction client :
# voice_analysis.py
import pandas as pd
sessions = pd.read_csv("lab-059/voice_sessions.csv")
print(f"Total sessions: {len(sessions)}")
print(f"Columns: {list(sessions.columns)}")
print(sessions.head())
Sortie attendue :
Total sessions: 15
Columns: ['session_id', 'scenario', 'duration_sec', 'latency_p50_ms',
'latency_p95_ms', 'interruptions', 'turns', 'sentiment',
'model', 'rag_used', 'language']
Le jeu de données inclut :
| Colonne | Description |
|---|---|
session_id |
Identifiant unique de session (S01–S15) |
scenario |
Type d'interaction : product_inquiry, order_status, complaint, return_request, faq |
duration_sec |
Durée totale de la session en secondes |
latency_p50_ms |
Latence médiane de réponse en millisecondes |
latency_p95_ms |
95e percentile de latence de réponse |
interruptions |
Nombre de fois où l'utilisateur a interrompu l'agent |
turns |
Nombre total de tours de conversation |
sentiment |
Sentiment global de la session : positive, neutral, negative |
model |
Modèle utilisé (gpt-4o-realtime) |
rag_used |
Si le RAG a été invoqué pendant la session |
language |
Langue de la session : en, es, fr |
Partie 3 : Analyse de la latence¶
Étape 3 : Mesurer la latence de réponse à travers les sessions¶
La latence est la métrique la plus critique pour les agents vocaux — tout ce qui dépasse 200 ms donne une impression de lenteur.
# Latency statistics
avg_p50 = sessions["latency_p50_ms"].mean()
avg_p95 = sessions["latency_p95_ms"].mean()
print(f"Average P50 latency: {avg_p50:.1f} ms")
print(f"Average P95 latency: {avg_p95:.1f} ms")
print(f"Min P50: {sessions['latency_p50_ms'].min()} ms")
print(f"Max P50: {sessions['latency_p50_ms'].max()} ms")
# Sessions exceeding 200ms at P95
slow = sessions[sessions["latency_p95_ms"] > 200]
print(f"\nSessions with P95 > 200ms: {len(slow)}")
print(slow[["session_id", "scenario", "latency_p95_ms"]])
Sortie attendue :
Average P50 latency: 89.3 ms
Average P95 latency: 187.5 ms
Min P50: 75 ms
Max P50: 110 ms
Sessions with P95 > 200ms: 4
session_id scenario latency_p95_ms
S06 return_request 210
S09 complaint 240
S12 return_request 215
S14 complaint 255
Observation sur la latence
Le P50 moyen de 89,3 ms est bien en dessous de la cible de 100 ms. Cependant, les sessions de réclamation et de retour ont systématiquement une latence plus élevée — probablement parce qu'elles déclenchent des recherches RAG plus longues et un raisonnement plus complexe.
Partie 4 : Analyse du sentiment¶
Étape 4 : Analyser la distribution du sentiment des sessions¶
# Sentiment breakdown
sentiment_counts = sessions["sentiment"].value_counts()
print("Sentiment Distribution:")
print(sentiment_counts)
print(f"\nPositive: {sentiment_counts.get('positive', 0)} sessions")
print(f"Neutral: {sentiment_counts.get('neutral', 0)} sessions")
print(f"Negative: {sentiment_counts.get('negative', 0)} sessions")
# Which sessions are negative?
negative = sessions[sessions["sentiment"] == "negative"]
print(f"\nNegative sessions:")
print(negative[["session_id", "scenario", "duration_sec", "interruptions"]])
Sortie attendue :
Sentiment Distribution:
positive 8
negative 4
neutral 3
Positive: 8 sessions (S01, S04, S05, S07, S10, S11, S13, S15)
Neutral: 3 sessions (S02, S08, S12)
Negative: 4 sessions (S03, S06, S09, S14)
Negative sessions:
session_id scenario duration_sec interruptions
S03 complaint 120 3
S06 return_request 65 1
S09 complaint 90 4
S14 complaint 105 5
Tendance observée
Les 4 sessions négatives sont toutes des réclamations ou des demandes de retour. Trois des quatre ont 3+ interruptions — les clients frustrés interrompent plus fréquemment.
Partie 5 : Modèles d'utilisation du RAG¶
Étape 5 : Analyser quelles sessions utilisent le RAG¶
# RAG usage
rag_used = sessions[sessions["rag_used"] == True]
rag_not_used = sessions[sessions["rag_used"] == False]
print(f"RAG used: {len(rag_used)}/{len(sessions)} sessions ({len(rag_used)/len(sessions)*100:.0f}%)")
print(f"RAG not used: {len(rag_not_used)} sessions")
print(f"\nSessions without RAG:")
print(rag_not_used[["session_id", "scenario", "sentiment"]])
# Compare latency: RAG vs no-RAG
print(f"\nAvg P50 with RAG: {rag_used['latency_p50_ms'].mean():.1f} ms")
print(f"Avg P50 without RAG: {rag_not_used['latency_p50_ms'].mean():.1f} ms")
Sortie attendue :
RAG used: 12/15 sessions (80%)
RAG not used: 3 sessions
Sessions without RAG:
session_id scenario sentiment
S05 faq positive
S10 faq positive
S15 faq positive
Avg P50 with RAG: 92.6 ms
Avg P50 without RAG: 76.3 ms
Observation sur le RAG
Les 3 sessions sans RAG sont toutes des scénarios FAQ — des questions simples qui ne nécessitent pas de recherche dans la base de données produit. Les sessions FAQ sont aussi les plus courtes (15–20 secondes) et ont la latence la plus faible.
Partie 6 : Modèles d'interruption¶
Étape 6 : Analyser le comportement de barge-in¶
Le barge-in désigne le moment où un utilisateur interrompt l'agent en pleine réponse. C'est une capacité clé du Realtime API — sans elle, les agents vocaux semblent robotiques.
# Interruption analysis
print("Interruptions per session:")
print(sessions[["session_id", "scenario", "interruptions", "sentiment"]].to_string(index=False))
# Correlation between interruptions and sentiment
avg_interruptions = sessions.groupby("sentiment")["interruptions"].mean()
print(f"\nAvg interruptions by sentiment:")
print(avg_interruptions)
# Sessions with most interruptions
high_interrupt = sessions[sessions["interruptions"] >= 3]
print(f"\nHigh-interruption sessions (≥3):")
print(high_interrupt[["session_id", "scenario", "interruptions", "sentiment"]])
Sortie attendue :
Avg interruptions by sentiment:
negative 3.25
neutral 0.67
positive 0.63
High-interruption sessions (≥3):
session_id scenario interruptions sentiment
S03 complaint 3 negative
S09 complaint 4 negative
S14 complaint 5 negative
Observation sur le barge-in
Les sessions négatives ont en moyenne 3,25 interruptions contre 0,63 pour les sessions positives. Un nombre élevé d'interruptions est un signal fort de frustration du client — un agent pourrait détecter cela en temps réel et escalader vers un agent humain.
Partie 7 : Support multilingue¶
Étape 7 : Analyser la distribution linguistique¶
# Language breakdown
lang_counts = sessions["language"].value_counts()
print("Language Distribution:")
print(lang_counts)
# Performance by language
for lang in sessions["language"].unique():
lang_sessions = sessions[sessions["language"] == lang]
print(f"\n{lang.upper()}: {len(lang_sessions)} sessions, "
f"avg P50={lang_sessions['latency_p50_ms'].mean():.1f}ms, "
f"avg sentiment: {lang_sessions['sentiment'].mode().iloc[0]}")
Sortie attendue :
Language Distribution:
en 13
es 1
fr 1
EN: 13 sessions, avg P50=90.2ms, avg sentiment: positive
ES: 1 sessions, avg P50=82.0ms, avg sentiment: positive
FR: 1 sessions, avg P50=87.0ms, avg sentiment: positive
Le Realtime API prend en charge plusieurs langues nativement — le même modèle gère l'anglais, l'espagnol et le français sans déploiements séparés.
🐛 Exercice de correction de bugs¶
Le fichier lab-059/broken_voice.py contient 3 bugs dans les fonctions d'analyse des sessions vocales. Exécutez les auto-tests :
Vous devriez voir 3 tests échoués :
| Test | Ce qu'il vérifie | Indice |
|---|---|---|
| Test 1 | Calcul de la latence P95 moyenne | Quelle colonne de latence devriez-vous utiliser ? |
| Test 2 | Nombre de sessions à sentiment négatif | Filtrez-vous la bonne valeur de sentiment ? |
| Test 3 | Taux d'utilisation du RAG en pourcentage | Quel devrait être le dénominateur ? |
Corrigez les 3 bugs et relancez jusqu'à voir 🎉 All 3 tests passed.
🧠 Vérification des connaissances¶
Q1 (Choix multiple) : Quelle est la latence de réponse cible du GPT-4o Realtime API ?
- A) ~500 ms — suffisamment rapide pour la plupart des applications vocales
- B) ~100 ms — comparable à la latence de conversation entre humains
- C) ~10 ms — quasi instantané pour le jeu en temps réel
- D) ~1000 ms — acceptable pour le traitement vocal par lots
✅ Révéler la réponse
Correct : B) ~100 ms
Le Realtime API cible une latence P50 d'environ 100 ms, comparable aux pauses naturelles dans la conversation humaine. À cette vitesse, les interactions vocales semblent fluides et naturelles. Les données de session confirment cela — le P50 moyen sur 15 sessions est de 89,3 ms.
Q2 (Choix multiple) : Que signifie « barge-in » dans le contexte des agents vocaux ?
- A) L'agent interrompt l'utilisateur pour fournir des informations urgentes
- B) L'utilisateur peut interrompre l'agent en pleine réponse et l'agent s'arrête pour écouter
- C) Plusieurs utilisateurs peuvent rejoindre la même session vocale simultanément
- D) L'agent change de langue en cours de conversation
✅ Révéler la réponse
Correct : B) L'utilisateur peut interrompre l'agent en pleine réponse et l'agent s'arrête pour écouter
Le barge-in est une fonctionnalité essentielle de la conversation vocale naturelle. Quand un utilisateur dit « attendez, en fait… » pendant que l'agent parle encore, l'agent arrête immédiatement sa réponse en cours et traite la nouvelle entrée. Sans le barge-in, les utilisateurs doivent attendre que l'agent finisse — créant une expérience frustrante et robotique.
Q3 (Exécuter le lab) : Quelle est la latence P95 moyenne sur l'ensemble des 15 sessions vocales ?
Calculez sessions["latency_p95_ms"].mean().
✅ Révéler la réponse
187,5 ms
Les valeurs P95 vont de 150 ms (S10, une session FAQ) à 255 ms (S14, une réclamation). La moyenne sur les 15 sessions est (170+185+195+180+155+210+165+175+240+150+178+215+188+255+152) / 15 = 187,5 ms. Quatre sessions dépassent le seuil de 200 ms — toutes sont des réclamations ou des demandes de retour.
Q4 (Exécuter le lab) : Combien de sessions ont un sentiment négatif ?
Filtrez sessions[sessions["sentiment"] == "negative"] et comptez.
✅ Révéler la réponse
4 sessions
Les sessions S03, S06, S09 et S14 ont un sentiment négatif. Les quatre sont soit des réclamations (S03, S09, S14) soit des demandes de retour (S06). Ces sessions ont aussi la latence et le nombre d'interruptions les plus élevés, suggérant une corrélation entre la frustration du client et les performances du système dans les scénarios complexes.
Q5 (Exécuter le lab) : Quel pourcentage de sessions utilise le RAG ?
Calculez (sessions avec rag_used == True) / nombre total de sessions * 100.
✅ Révéler la réponse
80% (12 sur 15)
12 des 15 sessions utilisent le RAG. Les 3 sessions sans RAG (S05, S10, S15) sont toutes des scénarios FAQ — des questions simples auxquelles le modèle répond à partir de ses données d'entraînement sans avoir besoin de recherches dans la base de données produit. Les sessions FAQ ont aussi la latence la plus faible, confirmant que le RAG ajoute un surcoût de latence mesurable (mais faible).
Résumé¶
| Sujet | Ce que vous avez appris |
|---|---|
| Realtime API | Voix-vers-voix en duplex intégral avec une latence d'environ 100 ms |
| WebRTC | Protocole natif au navigateur pour le streaming audio à faible latence |
| Barge-in | Les utilisateurs peuvent interrompre en pleine réponse pour un flux de conversation naturel |
| RAG + Voix | 80% des sessions utilisent le RAG ; les sessions FAQ le contournent pour une latence plus faible |
| Sentiment | Les sessions négatives corrèlent avec les réclamations, la latence élevée et les interruptions |
| Multilingue | Le même modèle gère en, es, fr sans déploiements séparés |