Function calling vocal
Exécuter des fonctions depuis la voix
Le function calling vocal permet à votre agent de déclencher des actions concrètes pendant une conversation : consulter une base de données, passer une commande, envoyer un email ou interroger une API externe. L’agent décide quand appeler une fonction en fonction de ce que l’utilisateur dit.
L'agent identifie le besoin
L'utilisateur dit quelque chose qui nécessite un appel de fonction. L'agent génère les arguments.
Votre application exécute la fonction
Vous recevez les arguments via l'événement function_call_arguments.done et exécutez la logique métier.
Vous renvoyez le résultat
Envoyez conversation.item.create avec le type function_call_output et le call_id.
L'agent continue la conversation
Envoyez response.create pour que l'agent formule sa réponse vocale avec le résultat.
Déclarer une fonction
Les fonctions se déclarent dans le tableau tools de session.update :
{
"type": "session.update",
"session": {
"tools": [
{
"type": "function",
"name": "consulter_solde",
"description": "Consulte le solde du compte bancaire d'un client",
"parameters": {
"type": "object",
"properties": {
"client_id": {
"type": "string",
"description": "Identifiant du client"
}
},
"required": ["client_id"]
}
}
]
}
}
Recevoir et traiter un appel de fonction
Quand l’agent décide d’appeler une fonction, vous recevez les arguments en streaming puis en bloc :
let functionArgs = "";
ws.on("message", (data) => {
const event = JSON.parse(data);
switch (event.type) {
case "response.function_call_arguments.delta":
functionArgs += event.delta;
break;
case "response.function_call_arguments.done":
const args = JSON.parse(event.arguments);
const callId = event.call_id;
const functionName = event.name;
// Exécuter la fonction
handleFunctionCall(functionName, args, callId);
break;
}
});
async function handleFunctionCall(name, args, callId) {
let result;
switch (name) {
case "consulter_solde":
result = await getSolde(args.client_id);
break;
default:
result = { error: "Fonction inconnue" };
}
// Renvoyer le résultat
ws.send(JSON.stringify({
type: "conversation.item.create",
item: {
type: "function_call_output",
call_id: callId,
output: JSON.stringify(result)
}
}));
// Demander à l'agent de continuer
ws.send(JSON.stringify({
type: "response.create"
}));
}
Appels de fonctions parallèles
L’agent peut décider d’appeler plusieurs fonctions simultanément. Dans ce cas, vous recevez plusieurs événements function_call_arguments.done. La règle est :
- Résoudre toutes les fonctions avant de répondre
- Soumettre tous les résultats avec autant de
conversation.item.create - Envoyer un seul
response.createà la fin
const pendingCalls = new Map();
let expectedCalls = 0;
case "response.function_call_arguments.done":
const result = await executeFunction(event.name, event.arguments);
pendingCalls.set(event.call_id, result);
if (pendingCalls.size === expectedCalls) {
// Toutes les fonctions sont résolues
for (const [callId, output] of pendingCalls) {
ws.send(JSON.stringify({
type: "conversation.item.create",
item: {
type: "function_call_output",
call_id: callId,
output: JSON.stringify(output)
}
}));
}
// Un seul response.create pour toutes les sorties
ws.send(JSON.stringify({ type: "response.create" }));
pendingCalls.clear();
}
break;
Bonnes pratiques
- Descriptions claires : la qualité des descriptions de fonctions détermine quand l’agent les utilise
- Exécution rapide : une fonction qui prend plus de 2-3 secondes crée un silence gênant
- Gestion des erreurs : renvoyez un message d’erreur lisible plutôt qu’une exception technique
- Confirmation vocale : pour les actions sensibles (paiement, suppression), faites confirmer par l’utilisateur avant d’exécuter
Points clés à retenir
- Le function calling vocal suit un cycle en 4 étapes : détection, exécution, retour du résultat, continuation
- Les fonctions se déclarent dans
session.updateavec un schéma JSON de paramètres - Le résultat doit être renvoyé via
conversation.item.createavectype: "function_call_output" - Envoyez toujours
response.createaprès avoir soumis les résultats - Pour les appels parallèles, attendez tous les résultats avant d’envoyer un seul
response.create