Aller au contenu principal

Outils et Function Calling en Vocal

Mis à jour le 29 juillet 2026

Un agent qui agit, pas seulement qui parle

Un assistant vocal capable uniquement de discuter atteint vite sa limite : il répond aimablement à « où en est ma commande ? » qu’il n’en sait rien. Toute la valeur du Voice Agent tient dans sa capacité à exécuter des actions au milieu de la conversation — consulter une base de données, lancer une recherche web, appeler une API métier, solliciter un serveur MCP — et à restituer le résultat à voix haute comme si de rien n’était.

Les cinq familles d’outils

La recherche web s’active dans sa forme la plus simple, sans paramètre :

{ "type": "web_search" }

L’agent interroge alors le web en direct, ce qui couvre les questions factuelles, l’actualité et toute donnée trop changeante pour vivre dans un prompt.

La recherche sur X suit la même logique, avec la possibilité de restreindre le périmètre à certains comptes :

{
  "type": "x_search",
  "allowed_x_handles": ["corsen_ai"]
}

Le paramètre allowed_x_handles est optionnel, mais il change la nature de l’outil : sans lui, l’agent fouille la plateforme entière ; avec lui, il devient un porte-parole qui ne cite que vos publications officielles.

La recherche de fichiers interroge des collections de documents vectorisés — vos manuels, vos procédures, votre documentation produit :

{
  "type": "file_search",
  "vector_store_ids": ["vs_abc123"],
  "max_num_results": 10
}

Les fonctions personnalisées, elles, ouvrent la porte de vos propres systèmes. C’est le type d’outil que vous utiliserez le plus, et sa déclaration mérite du soin :

{
  "type": "function",
  "name": "verifier_commande",
  "description": "Vérifie le statut d'une commande client",
  "parameters": {
    "type": "object",
    "properties": {
      "numero_commande": {
        "type": "string",
        "description": "Le numéro de commande au format CMD-XXXX"
      }
    },
    "required": ["numero_commande"]
  }
}

Rien n’interdit de brancher ainsi un CRM, un ERP, un calendrier ou une base interne. Enfin, les serveurs MCP donnent accès à des outils standardisés via le Model Context Protocol, sans avoir à réécrire une intégration par service :

{
  "type": "mcp",
  "server_url": "https://mcp.example.com/sse",
  "server_label": "Mon serveur MCP"
}

Le cycle complet d’un appel de fonction

Quand l’agent décide d’appeler une fonction, il ne l’exécute pas : il vous la commande, et c’est votre application qui travaille. Les arguments vous parviennent d’abord en streaming par response.function_call_arguments.delta, puis l’événement response.function_call_arguments.done marque la fin de la commande et vous livre le call_id accompagné des arguments complets. À vous d’exécuter la fonction, puis de rendre le résultat sous la forme d’un conversation.item.create de type function_call_output :

{
  "type": "conversation.item.create",
  "item": {
    "type": "function_call_output",
    "call_id": "call_abc123",
    "output": "{\"statut\": \"expediee\", \"date_livraison\": \"2026-04-05\"}"
  }
}

Une dernière étape est indispensable et c’est celle qu’on oublie : envoyer response.create pour que l’agent intègre ce résultat dans sa réponse vocale. Sans elle, le résultat est bien arrivé dans la conversation mais rien ne se passe, l’utilisateur entend un silence, et vous cherchez le bug du mauvais côté.

Quand plusieurs fonctions partent en même temps

Le modèle peut très bien décider d’appeler deux ou trois fonctions d’un coup — vérifier une commande et consulter le calendrier de livraison, par exemple. Vous recevez alors plusieurs function_call_arguments.done porteurs de call_id distincts. Exécutez tout, si possible en parallèle pour ne pas additionner les latences, soumettez chaque résultat dans son propre conversation.item.create, puis n’envoyez qu’un seul response.create à la toute fin. Un response.create par fonction déclencherait autant de réponses vocales concurrentes, et l’agent se mettrait à parler par-dessus lui-même.

// Recevoir et executer toutes les fonctions
const results = await Promise.all(
  pendingCalls.map(call => executeFunction(call))
);

// Soumettre tous les resultats
for (const result of results) {
  ws.send(JSON.stringify({
    type: "conversation.item.create",
    item: {
      type: "function_call_output",
      call_id: result.callId,
      output: JSON.stringify(result.data)
    }
  }));
}

// Declencher la reponse
ws.send(JSON.stringify({ type: "response.create" }));

Les contraintes propres au vocal

Ce qui passe inaperçu dans une interface écrite devient criant à l’oral, à commencer par le temps. Personne ne patiente plus de trois à cinq secondes en pleine conversation : au-delà, l’utilisateur croit que la ligne a coupé et se met à parler. Si votre fonction interroge un système lent, faites dire à l’agent une phrase d’attente pendant l’appel plutôt que de laisser un blanc.

Le volume des résultats compte tout autant. L’agent doit synthétiser vocalement ce que vous lui rendez ; une liste de quarante commandes produira soit une énumération interminable, soit un résumé approximatif. Renvoyez des données structurées mais resserrées sur l’essentiel. Soignez également la description de chaque fonction, puisque c’est sur elle seule que le modèle s’appuie pour choisir : une description vague comme « gère les commandes » le fera hésiter ou se tromper d’outil. Et prévoyez l’échec — quand la fonction plante, renvoyez un message d’erreur explicite dans output plutôt que rien du tout, faute de quoi l’agent improvisera une réponse sans savoir que l’appel a échoué.

Points clés à retenir

  • Le Voice Agent supporte cinq types d’outils : web search, X search, file search, fonctions et MCP
  • Le cycle d’un appel de fonction passe par la réception des arguments, l’exécution, le renvoi du résultat et le déclenchement de la réponse
  • Les appels parallèles sont possibles : exécutez tout, soumettez tout, puis un seul response.create
  • En vocal, le temps de réponse des fonctions est critique : visez moins de 3 secondes