À la fin de ce guide, vous serez en mesure de définir un outil, de l'envoyer à OpenAI, de lire l'appel d'outil renvoyé par le modèle, et d'exécuter votre propre fonction avec les arguments structurés qu'il vous transmet. Vous activerez également le mode strict et les appels parallèles, puis vous validerez et simulerez le côté de l'outil avec Apidog afin de faire confiance au résultat avant qu'il n'atteigne la production. Gardez la documentation d'appel de fonction d'OpenAI ouverte dans un autre onglet pour la source de vérité, et consultez notre introduction sur la création d'agents avec le SDK OpenAI Agents pour une vue d'ensemble plus générale.
Ce dont vous avez besoin avant de commencer
L'appel de fonction (souvent appelé appel d'outil) est la manière dont un modèle se connecte à votre code et à des systèmes externes. Vous décrivez les fonctions que votre application expose, le modèle lit la requête de l'utilisateur, et lorsqu'une fonction correspond, il retourne le nom de la fonction ainsi qu'un objet JSON d'arguments. Le modèle n'exécute jamais rien lui-même. Il vous transmet une requête structurée, et votre code effectue le travail.
Cette séparation est la chose à garder à l'esprit pendant que vous construisez. Le modèle choisit l'intention et remplit les paramètres. Vous gardez le contrôle de l'exécution. Un message "quel temps fait-il à Paris" se transforme en un appel clair get_weather({"location": "Paris, France"}) au lieu d'un paragraphe que vous auriez dû analyser manuellement.
Pour suivre, vous avez besoin d'une clé API OpenAI et d'une fonction dans votre propre code que vous souhaitez que le modèle puisse déclencher. Une chose de plus à décider dès le départ : sur quel point de terminaison vous vous trouvez. La même fonctionnalité fonctionne à deux endroits. L'ancienne API Chat Completions la prend en charge, ainsi que la nouvelle API Responses, qui unifie ce qui était auparavant divisé entre Chat Completions et l'API Assistants. Les formes diffèrent légèrement, et les étapes ci-dessous couvrent les deux.
Étape 1 : Définissez votre outil
Un outil est une définition de fonction que le modèle peut lire. Vous lui donnez un nom, une description et un schéma JSON pour les arguments. La description fait un vrai travail ici. Elle indique au modèle quand utiliser la fonction, alors écrivez-la comme une instruction, pas comme une étiquette.
Voici une définition d'outil dans la forme Chat Completions, où la fonction se trouve sous un wrapper function :
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city. Use when the user asks about temperature or conditions.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City and country, e.g. Bogotá, Colombia"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"],
"additionalProperties": false
}
}
}
L'API Responses simplifie cela. Les champs name, description, parameters et strict se trouvent au niveau supérieur de l'objet outil, sans clé function imbriquée. Même information, moins de couches.
Si vous maintenez déjà une spécification OpenAPI pour le service sous-jacent, les formes des paramètres se reportent presque directement. Notre guide sur la génération de collections de tests à partir de spécifications OpenAPI montre comment ce travail de schéma est doublement rentable.
Étape 2 : Effectuez votre première requête
Envoyez votre outil au modèle avec le message de l'utilisateur. Une requête Chat Completions complète qui fait cela ressemble à ceci :
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4.1",
"messages": [
{"role": "user", "content": "What is the weather in Paris right now?"}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"}
},
"required": ["location"],
"additionalProperties": false
}
}
}
]
}'
Le tableau tools contient toutes les fonctions que vous souhaitez exposer pour cette interaction. Le modèle lit le message de l'utilisateur, décide si un outil correspond, et répond. Lorsqu'il en choisit un, vous obtenez un appel d'outil en retour au lieu d'un texte en prose, ce que vous lisez à l'étape suivante.
Étape 3 : Lisez l'appel d'outil renvoyé par le modèle
Lorsque le modèle décide d'appeler une fonction, il ne renvoie pas de texte. Il renvoie un appel d'outil que vous lisez dans la réponse.
Dans Chat Completions, le message de l'assistant contient un tableau tool_calls. Chaque entrée a un id, un type de function, et un objet function avec le name et une chaîne arguments :
{
"id": "call_12345xyz",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Paris, France\"}"
}
}
Dans l'API Responses, l'appel apparaît dans le tableau output avec une forme plus plate : un type de function_call, un call_id, un name et des arguments :
{
"type": "function_call",
"call_id": "call_12345xyz",
"name": "get_weather",
"arguments": "{\"location\":\"Paris, France\"}"
}
Un détail déroute les gens : arguments est une chaîne encodée en JSON, pas un objet analysé. Vous l'analysez vous-même, exécutez votre fonction, puis renvoyez le résultat afin que le modèle puisse terminer sa réponse.
Étape 4 : Retournez le résultat au modèle
Après avoir exécuté votre fonction, renvoyez le résultat afin que le modèle puisse produire une réponse finale. Dans Chat Completions, vous ajoutez un message de rôle tool indexé par l'id de l'appel. Dans l'API Responses, vous envoyez un élément function_call_output indexé par le call_id. Dans tous les cas, la boucle est la même : le modèle demande, vous exécutez, vous renvoyez le résultat, le modèle répond.
Étape 5 : Ajoutez les appels parallèles et le mode strict
Deux réglages modifient la fiabilité et la rapidité de ce processus, et vous les ajoutez une fois que la boucle de base fonctionne.
Appels d'outils parallèles. Par défaut, le modèle peut renvoyer plus d'un appel d'outil en une seule fois. Si un utilisateur demande la météo dans trois villes, vous pourriez obtenir trois appels simultanément et les exécuter ensemble. Lorsque vous préférez forcer au maximum un appel par tour, définissez parallel_tool_calls sur false.
Mode strict. Définissez strict: true sur la définition de la fonction et les arguments du modèle sont garantis de correspondre à votre schéma JSON au lieu d'être un "meilleur effort". OpenAI recommande de toujours l'activer. Le mode strict a des règles : chaque objet nécessite additionalProperties: false, et chaque champ dans properties doit apparaître dans required. Pour rendre un champ facultatif, vous ne le supprimez pas de required ; vous ajoutez null à sa liste de types autorisés.
| Paramètre | Ce qu'il contrôle | Valeur par défaut | Quand le modifier |
|---|---|---|---|
parallel_tool_calls |
Si plusieurs appels d'outils peuvent être renvoyés en une seule fois | true |
Définir sur false lorsque les appels dépendent les uns des autres ou doivent s'exécuter dans un ordre spécifique |
strict |
Si les arguments sont forcés de correspondre au schéma | meilleur effort sauf si défini ; recommandé | Activer pour tout appel que vous analysez sans code défensif |
tool_choice |
Si et quelle fonction le modèle peut appeler | auto |
required pour forcer un appel, none pour désactiver, ou nommer une fonction pour la fixer |
La règle des champs optionnels prend les gens au dépourvu. Supposons que unit soit optionnel dans get_weather. En mode strict, vous le listez toujours dans required, puis vous le marquez comme nullable dans le schéma, comme "unit": {"type": ["string", "null"], "enum": ["celsius", "fahrenheit"]}. Le modèle peut maintenant passer une unité réelle ou un null explicite, mais il ne peut jamais omettre la clé. Cette prévisibilité est tout l'intérêt : votre code d'analyse sait exactement quelles clés attendre à chaque fois.
Le mode strict réduit les JSON mal formés, mais il ne vérifie pas que les valeurs ont un sens commercial. Un emplacement peut être valide selon le schéma et toujours être une ville que vous ne desservez pas. C'est là qu'intervient le test.
Comment le tester dans Apidog
Le modèle vous donne un appel d'outil. Avant de le connecter à une fonction réelle, vous voulez deux garanties : les arguments correspondent à la forme attendue, et l'API en aval que votre fonction appellerait se comporte comme vous le supposez. Apidog couvre les deux côtés de cela, et il est important d'être précis sur ce point.

Apidog valide et simule le côté API. Il n'exécute pas les fonctions de votre application. Ce qu'il fait bien, c'est le contrat autour d'elles.
Affirmer la structure des arguments. Prenez la chaîne arguments d'un véritable appel d'outil, traitez-la comme un corps de requête, et exécutez des assertions dessus dans Apidog. Vérifiez que location existe et est une chaîne, qu'un champ d'énumération ne contient jamais qu'une valeur autorisée, que les champs requis sont présents. Extraire des champs spécifiques de la charge utile est facile avec les expressions JSONPath, et pour les vérifications structurelles plus profondes, il y a la validation par rapport à un schéma JSON, qui reflète le même schéma que vous avez donné à OpenAI en mode strict. Si la sortie du modèle passe le même schéma que votre fonction attend, vous avez bouclé la boucle.
Simulez l'API en aval que la fonction appellerait. Votre fonction get_weather appelle probablement un fournisseur de météo. Pendant le développement, ce fournisseur peut être soumis à des limites de débit, payant, ou pas encore construit. Mettez en place une API de simulation dans Apidog qui renvoie une charge utile météo réaliste, pointez votre fonction vers la simulation, et exercez tout le chemin d'appel sans dépenser une requête sur le service réel. Vous contrôlez la réponse, y compris les cas d'erreur que l'API en direct produit rarement à la demande, afin de pouvoir confirmer que votre code gère un délai d'attente ou une erreur 429 avant qu'un utilisateur ne la rencontre.
Ensemble, le flux de travail est le suivant : capturez un appel d'outil d'OpenAI, validez ses arguments par rapport à votre schéma dans Apidog, puis exécutez votre fonction par rapport à une simulation Apidog de l'API réelle. Vous vérifiez le contrat aux deux extrémités sans brûler d'appels en direct ni deviner les cas limites.
Questions fréquemment posées
L'appel de fonction fonctionne-t-il à la fois dans Chat Completions et l'API Responses ? Oui. Les deux points de terminaison le prennent en charge. L'API Responses unifie les capacités qui étaient auparavant réparties entre Chat Completions et l'API Assistants. La principale différence est la forme : Chat Completions imbrique la fonction sous une clé function et renvoie tool_calls, tandis que l'API Responses utilise une définition d'outil plate et renvoie des éléments function_call dans le tableau output.
Pourquoi le modèle renvoie-t-il les arguments sous forme de chaîne au lieu d'un objet ? Le champ arguments est un texte encodé en JSON. Vous devez l'analyser dans votre code avant de l'utiliser. Cela est cohérent entre les deux API, alors passez-le toujours par votre analyseur JSON et validez le résultat plutôt que de lui faire confiance aveuglément. L'exécution de ces arguments via la validation de schéma JSON intercepte une charge utile mal formée avant qu'elle n'atteigne votre fonction.
Le mode strict garantit-il que la fonction réussira ? Non. Le mode strict garantit que les arguments correspondent à votre schéma JSON, de sorte que la structure est fiable. Il ne vérifie pas que les valeurs sont correctes pour votre logique métier, et il n'exécute pas votre fonction. Vous devez toujours valider les valeurs et gérer vous-même les échecs de l'appel en aval.
Apidog peut-il exécuter ma fonction réelle ? Non, et il n'essaie pas de le faire. Apidog valide les arguments produits par le modèle et simule l'API dont dépend votre fonction. Votre application exécute toujours ses propres fonctions. Apidog couvre le contrat des deux côtés afin que vous fassiez confiance aux entrées et aux dépendances avant la mise en production.
Conclusion
Vous avez maintenant la boucle complète : définissez clairement vos outils, envoyez-les avec la requête, lisez la sortie tool_calls ou function_call, renvoyez le résultat, puis activez le mode strict et décidez si les appels parallèles aident ou nuisent. Terminez par des tests en vérifiant que les arguments correspondent à votre schéma et en simulant l'API en aval pour être confiant avant la production.
Vous voulez essayer le côté test ? Téléchargez Apidog pour valider les arguments d'appel d'outil par rapport à votre schéma et simuler les API dont vos fonctions dépendent, le tout au même endroit.
