Cursus
Avec le lancement de GPT-5, OpenAI a élargi l'appel d'outils/fonctions dans l'API pour inclure des appels d'outils en format libre (texte brut, sans JSON), des contraintes grammaticales via Lark/CFG, des listes d'outils autorisés et un raisonnement amélioré sur l'utilisation des outils. Ensemble, ces éléments font de GPT-5 un modèle véritablement agentique ; vous pouvez connecter des API, des bases de données et des outils personnalisés à l'API Responses et générer des réponses fondées, voire automatiser des flux de travail.
Dans ce tutoriel, je vais aborder les outils fonctionnels. outils de fonctionet les outils personnalisés, les les contraintes grammaticales, listes d'autorisation d'outilset préambules, avec des exemples de code et des explications claires sur leur fonctionnement et leur utilisation.
Appel de fonction dans GPT-5 : Quoi et pourquoi
L'appel de fonction dans GPT-5 vous permet d'améliorer le modèle grâce aux données et aux actions de votre application. Le modèle peut déterminer quand faire appel à un outil, tandis que vous gérez la logique et renvoyez les résultats pour obtenir une réponse finale et fondée.
Types d'appels de fonction :
- Outils fonctionnels (schéma JSON) : Ces derniers offrent des entrées et sorties structurées que le modèle peut appeler avec précision.
- Outils personnalisés (forme libre) : Ces derniers offrent des entrées et sorties de texte flexibles pour les intégrations non structurées.
Qu'est-ce qu'un appel de fonction ?
GPT-5 prend en charge à la fois les outils fonctionnels structurés (utilisant JSON Schema) et les outils personnalisés qui acceptent des charges utiles de texte en format libre (telles que SQL, scripts ou configurations) pour une intégration transparente avec des environnements d'exécution externes.
Les outils fonctionnels sont définis par JSON Schema, ce qui garantit que le modèle comprend exactement quels arguments transmettre et permet une validation stricte des entrées. Pour en savoir plus, veuillez consulter notre tutoriel sur les appels de fonction OpenAI.
Pourquoi utiliser l'appel de fonction ?
- Flexibilité : Les outils de forme libre permettent au modèle de produire le texte exact dont votre système a besoin, sans les contraintes du JSON rigide, ce qui les rend idéaux pour le code, les requêtes ou les configurations.
- Fiabilité et contrôle : Les outils fonctionnels imposent des arguments structurés, ce qui améliore la prévisibilité et réduit les erreurs d'analyse.
- Flux de travail agentique : GPT-5 est conçu pour des tâches complexes d'utilisation d'outils et de codage en plusieurs étapes, faisant de l'appel d'outils une fonctionnalité principale.
Comment fonctionne l'appel de fonction ?
- Veuillez envoyer une invite incluant tous les outils disponibles.
- Le modèle émet un appel d'outil (avec des arguments ou du texte libre).
- Votre application exécute l'outil (exécute la fonction Python).
- Veuillez renvoyer la sortie de l'outil vers le modèle.
- Le modèle répond alors ou peut faire appel à des outils supplémentaires.

Source : Appel de fonction - API OpenAI
Quand utiliser la fonction par rapport à Outils personnalisés
- Utilisez les outils fonctionnels lorsque vous souhaitez une validation stricte et des arguments typés prévisibles via JSON Schema.
- Utilisez des outils personnalisés (forme libre) lorsque votre environnement d'exécution nécessite du texte brut (comme des scripts, du SQL ou des configurations) ou lorsque vous avez besoin d'itérations rapides sans schémas.
Outils fonctionnels (schéma JSON) : Envoyer des données structurées
L'utilisation des outils fonctionnels avec JSON Schema vous permet d'obtenir des résultats prévisibles et structurés à partir du modèle. Le modèle évalue les outils que vous avez déclarés, détermine quand utiliser l'un d'entre eux, propose des arguments validés JSON, puis exécute la fonction correspondante dans votre code.
Ensuite, vous pouvez demander au modèle de générer une réponse basée uniquement sur les données renvoyées par l'outil, en veillant à ce que le résultat soit fondé, lisible par machine et facile à intégrer.
Cet exemple illustre plusieurs concepts clés :
- Découverte d'outils et génération d'arguments : Le modèle sélectionne l'outil approprié et remplit automatiquement ses arguments de type JSON.
- Boucle d'exécution de l'outil : Votre application exécute le ou les outils demandés et renvoie les résultats au modèle.
- Réponse finale sous forme de schéma : La réponse finale est strictement basée sur les résultats fournis par les outils, ce qui minimise les inexactitudes et garantit la fiabilité.
1. Configuration
- Veuillez créer un compte OpenAI et générer une clé API sur le tableau de bord de la plateforme. Dans le tableau de bord, veuillez ouvrir la section API, puis « Afficher les clés API » et cliquer sur « Créer une nouvelle clé secrète ».
- Veuillez ajouter un mode de paiement ou des crédits à votre compte afin que les appels API puissent s'exécuter ; l'utilisation sera déduite de votre solde prépayé à mesure que vous effectuez des demandes.
- Veuillez enregistrer votre clé API en tant que variable d'environnement nommée OPENAI_API_KEY avant de démarrer votre application.
- Veuillez installer le SDK officiel Python d'OpenAI à l'adresse
pip install openai.
2. Définir les outils
Veuillez fournir une liste d'outils avec un nom, une description et un schéma JSON pour les paramètres. Le schéma aide le modèle à fournir des arguments bien formés.
make_coffeeattend un paramètre de type chaîne :coffee_type.random_coffee_factne prend aucun paramètre (objet vide). Ces définitions sont transmises via l'argument `tools` dans l'appel API afin que le modèle puisse identifier les éléments disponibles.
import os
from openai import OpenAI
import json
client = OpenAI(api_key = os.environ["OPENAI_API_KEY"])
tools = [
{
"type": "function",
"name": "make_coffee",
"description": "Gives a simple recipe for making a coffee drink.",
"parameters": {
"type": "object",
"properties": {
"coffee_type": {
"type": "string",
"description": "The coffee drink, e.g. espresso, cappuccino, latte"
}
},
"required": ["coffee_type"],
},
},
{
"type": "function",
"name": "random_coffee_fact",
"description": "Returns a fun fact about coffee.",
"parameters": {"type": "object","properties":{}}
}
]
3. Mettre en œuvre des outils
Vous implémentez les fonctions Python qui effectuent réellement le travail :
make_coffee(coffee_type)Renvoie une chaîne concise contenant la recette correspondant à la boisson demandée.random_coffee_fact()renvoie une petite charge utile factuelle.
Les deux renvoient des dictionnaires sérialisables en JSON, ce qui est idéal pour les renvoyer au modèle.
def make_coffee(coffee_type):
recipes = {
"espresso": "Grind fine, 18g coffee → 36g espresso in ~28s.",
"cappuccino": "Brew 1 espresso shot, steam 150ml milk, pour and top with foam.",
"latte": "Brew 1 espresso shot, steam 250ml milk, pour for silky texture.",
}
return {"coffee_type": coffee_type, "recipe": recipes.get(coffee_type.lower(), "Unknown coffee type!")}
def random_coffee_fact():
return {"fact": "Coffee is the second most traded commodity in the world, after oil."}
4. Entamer une conversation
Commencez la conversation par la question de l'utilisateur : {"role": "user", "content": "How do I make a latte?"}
Le modèle peut renvoyer des messages contenant un élément function_call, tel que make_coffee avec {"coffee_type":"latte"}. Veuillez ensuite ajouter les messages du modèle dans input_list: input_list += response.output. Cela permet de conserver l'état de la conversation pour le tour suivant.
# Track used tools
used_tools = []
input_list = [{"role": "user", "content": "How do I make a latte?"}]
response = client.responses.create(
model="gpt-5",
tools=tools,
input=input_list,
)
input_list += response.output
5. Exécutez les appels d'outils et joignez les résultats
Veuillez parcourir response.output et identifier les éléments pour lesquels item.type est égal à "function_call". Pour ces éléments, veuillez analyser item.arguments et transmettre les requêtes à vos fonctions Python.
Pour la fonction d'make_coffee, veuillez l'appeler en utilisant make_coffee(args["coffee_type"]). Pour la fonction d' random_coffee_fact, veuillez simplement appeler random_coffee_fact().
Après avoir exécuté les fonctions, veuillez ajouter un message d' function_call_output e comprenant les éléments suivants :
call_id(qui relie cette sortie à la requête du modèle)output(une chaîne JSON représentant le résultat de votre fonction).
for item in response.output:
if getattr(item, "type", "") == "function_call":
used_tools.append(item.name)
args = json.loads(item.arguments or "{}")
if item.name == "make_coffee":
result = make_coffee(args["coffee_type"])
elif item.name == "random_coffee_fact":
result = random_coffee_fact()
else:
result = {"error": f"Unknown tool {item.name}"}
input_list.append({
"type": "function_call_output",
"call_id": item.call_id,
"output": json.dumps(result)
})
6. Générer la réponse finale
Vous effectuez un deuxième appel à client.responses.create, en transmettant l'input_list mise à jour qui inclut désormais les résultats de l'outil.
La variable used_tools enregistre les noms des outils qui apparaissent dans les appels de fonction du modèle. Nous l'utiliserons pour indiquer quels outils ont été employés.
final = client.responses.create(
model="gpt-5",
tools=tools,
input=input_list,
instructions="Answer using only the tool results."
)
print("Final output:\n", final.output_text)
print("\n--- Tool Usage ---")
for t in tools:
status = "USED ✅" if t["name"] in used_tools else "NOT USED ❌"
print(f"{t['name']}: {status}")
Étant donné que l'utilisateur a demandé un café au lait, le modèle a sélectionné make_coffee avec coffee_type = "latte". Votre code l'a exécuté et la réponse finale a été générée uniquement à partir du résultat de cet outil.
Final output:
{"coffee_type":"latte","recipe":"Brew 1 espresso shot, steam 250ml milk, pour for silky texture."}
--- Tool Usage ---
make_coffee: USED ✅
random_coffee_fact: NOT USED ❌
Outils personnalisés (forme libre) : Envoyer du texte brut
Utilisez les outils personnalisés de format libre de GPT-5 pour permettre au modèle d'envoyer du texte brut directement à votre outil, tel que du code, du SQL, des commandes shell ou un simple CSV, sans nécessiter de schéma JSON.
Cette fonctionnalité va au-delà des anciens appels de fonction JSON uniquement, vous offrant une plus grande flexibilité pour l'intégration avec des exécuteurs, des moteurs de requête ou des interpréteurs de langage spécifique au domaine (DSL).
En mode libre, le modèle génère un appel d'outil personnalisé avec une charge utile de texte non structuré que vous pouvez acheminer vers votre environnement d'exécution. Vous renvoyez ensuite le résultat au modèle afin qu'il finalise la réponse destinée à l'utilisateur.
Nous allons maintenant écrire le code qui permet au modèle de sélectionner les outils appropriés et de renvoyer du texte brut non structuré comme résultat. Cette sortie sera ensuite transmise à une fonction Python afin de générer un résultat. De cette manière, l'utilisateur peut indiquer les ingrédients dont il dispose, et le modèle générera des recettes adaptées à ses besoins.
Dans cet exemple de code, nous avons :
- Initialisation du client OpenAI et définition d'un outil personnalisé unique appelé
meal_plannerqui accepte les entrées de texte brut. - Nous avons développé l'
plan_meal, un programme Python qui prend en entrée une liste d'ingrédients séparés par des virgules et propose une suggestion de repas en réponse. - La conversation a débuté par un message utilisateur répertoriant les ingrédients disponibles.
- Nous avons effectué un premier appel au modèle en demandant à GPT-5 d'utiliser l'outil en se basant uniquement sur une liste d'ingrédients propres, puis nous avons ajouté la sortie du modèle à l'historique de la conversation.
- Nous avons identifié l'appel de l'outil personnalisé émis et extrait la chaîne d'entrée brute séparée par des virgules.
- Nous avons exécuté l'outil en transmettant la liste à
plan_meal, puis renvoyé le résultat au modèle sous forme d'function_call_output, lié viacall_id. - Nous avons effectué un dernier appel au modèle afin de convertir l'idée brute de l'outil en une recette concise, étape par étape, et avons imprimé à la fois les détails de l'appel à l'outil et le résultat final.
from openai import OpenAI
import json
import random
client = OpenAI()
# --- Custom tool ---
tools = [
{
"type": "custom",
"name": "meal_planner",
"description": "Takes ONLY a comma-separated list of ingredients and suggests a meal idea."
}
]
# --- Fake meal planner ---
def plan_meal(ingredients: str) -> str:
ideas = [
f"Stir-fry: {ingredients} with garlic & soy sauce.",
f"One-pot rice: cook {ingredients} together in broth until fluffy.",
f"Soup: simmer {ingredients} in stock with herbs.",
f"Sheet-pan bake: roast {ingredients} at 200°C for ~20 min."
]
return random.choice(ideas)
# --- Start conversation ---
messages = [
{"role": "user", "content": "I only have chicken, rice, and broccoli. Any dinner ideas?"}
]
# 1) Ask model with clear instruction
resp = client.responses.create(
model="gpt-5",
tools=tools,
input=messages,
instructions="If the user mentions ingredients, call the meal_planner tool with ONLY a comma-separated list like 'chicken, rice, broccoli'."
)
messages += resp.output
# 2) Find the tool call
tool_call = next((x for x in resp.output if getattr(x, "type", "") == "custom_tool_call"), None)
assert tool_call, "No tool call found!"
# Get clean CSV input
ingredients_csv = tool_call.input.strip()
# 3) Run the tool
meal_result = plan_meal(ingredients_csv)
# 4) Send tool output back
messages.append({
"type": "function_call_output",
"call_id": tool_call.call_id,
"output": meal_result
})
# 5) Final model response
final = client.responses.create(
model="gpt-5",
tools=tools,
input=messages,
instructions="Turn the meal idea into a short recipe with 3-4 steps."
)
print("\n--- Tool Call ---")
print("Name:", tool_call.name)
print("Input:", ingredients_csv)
print("Output:", meal_result)
print("\n--- Final Output ---\n", final.output_text)
En conséquence, nous avons reçu des statistiques sur les outils utilisés, notamment l'installation, la saisie et la sortie. De plus, le résultat final fournit une recette complète sur la manière de préparer le repas.
--- Tool Call ---
Name: meal_planner
Input: chicken, rice, broccoli
Output: One-pot rice: cook chicken, rice, broccoli together in broth until fluffy.
--- Final Output ---
One-Pot Chicken, Rice & Broccoli
- Season bite-size chicken pieces with salt and pepper; sear in a little oil in a pot until lightly browned.
- Add 1 cup rinsed rice and 2 cups broth (or water + salt). Bring to a boil, then cover and simmer on low for 12 minutes.
- Scatter 2 cups small broccoli florets on top, cover, and cook 5-7 more minutes until rice is fluffy and broccoli is tender.
- Rest 5 minutes off heat, fluff, and adjust seasoning. Optional: stir in a knob of butter or a splash of soy.
Contraintes grammaticales (Lark) : Limiter les résultats de l'outil
GPT-5 prend désormais en charge la grammaire sans contexte (CFG) afin de garantir un contrôle rigoureux des formats de sortie.
En appliquant une grammaire, telle que SQL ou un langage spécifique à un domaine (DSL), à ses réponses, GPT-5 garantit que les résultats respectent systématiquement la structure requise. Le CFG revêt une importance particulière pour les processus automatisés et les flux de travail à haut risque.
GPT-5 peut utiliser des grammaires définies dans des formats tels que Lark pour limiter les résultats de l'outil lors de la génération. Cette approche du décodage contraint améliore la fiabilité en empêchant la dérive des formats et en garantissant la cohérence structurelle.
Nous allons maintenant écrire le code permettant au modèle de sélectionner un outil et de générer UNIQUEMENT une expression arithmétique grammaticalement valide ; cette expression est ensuite évaluée en Python, le résultat est renvoyé à la conversation et la réponse finale est présentée clairement en langage naturel.
Dans cet exemple de code, nous avons :
- Initialisation du client OpenAI et définition d'un outil personnalisé
math_solverqui doit produire UNIQUEMENT une expression arithmétique grammaticalement valide (Lark CFG). - La conversation a débuté par une question mathématique formulée en langage naturel par l'utilisateur.
- Nous avons effectué un premier appel de modèle en demandant à GPT-5 d'appeler
math_solveravec une expression conforme à la grammaire. - Nous avons localisé l'appel de l'outil émis et extrait la chaîne d'expression brute de la charge utile de l'outil.
- Nous avons évalué l'expression localement dans un environnement restreint afin d'obtenir un résultat concret.
- Le résultat de l'exécution de l'outil a été renvoyé à la conversation, lié via l'
call_ide d'origine. - Nous avons effectué un appel final au modèle afin de présenter clairement le résultat évalué en langage naturel.
from openai import OpenAI
import json
client = OpenAI()
# --- Local fake evaluator ---
def eval_expression(expr: str) -> str:
try:
# Evaluate safely using Python's eval on restricted globals
result = eval(expr, {"__builtins__": {}}, {})
return f"{expr} = {result}"
except Exception as e:
return f"Error evaluating expression: {e}"
# --- Custom tool with grammar constraint ---
tools = [
{
"type": "custom",
"name": "math_solver",
"description": "Solve a math problem by outputting ONLY a valid arithmetic expression.",
"format": {
"type": "grammar",
"syntax": "lark",
"definition": r"""
start: expr
?expr: term
| expr "+" term -> add
| expr "-" term -> sub
?term: factor
| term "*" factor -> mul
| term "/" factor -> div
?factor: NUMBER
| "(" expr ")"
%import common.NUMBER
%ignore " "
"""
},
}
]
# --- User asks ---
msgs = [
{"role": "user", "content": "What is (12 + 8) * 3 minus 5 divided by 5?"}
]
# 1) First model call: GPT-5 must emit a grammar-valid expression
resp = client.responses.create(
model="gpt-5",
tools=tools,
input=msgs,
instructions="Always call the math_solver tool with a grammar-valid arithmetic expression like '(12 + 8) * 3 - 5 / 5'."
)
msgs += resp.output
tool_call = next(
x for x in resp.output
if getattr(x, "type", "") in ("custom_tool_call", "tool_call", "function_call")
)
expr = getattr(tool_call, "input", "") or getattr(tool_call, "arguments", "")
print("\n=== Grammar-Constrained Expression ===")
print(expr)
# 2) Run the local evaluator
tool_result = eval_expression(expr)
print("\n=== Tool Execution Result ===")
print(tool_result)
# 3) Return tool output
msgs.append({
"type": "function_call_output",
"call_id": tool_call.call_id,
"output": tool_result
})
# 4) Final pass: GPT-5 presents answer nicely
final = client.responses.create(
model="gpt-5",
input=msgs,
tools=tools,
instructions="Present the evaluated result clearly in natural language."
)
print("\n=== Final Output ===")
print(final.output_text)
Comme vous pouvez le constater, le modèle a sélectionné l'outil, puis généré une expression conforme aux règles grammaticales. Ensuite, il est transmis à la fonction Python afin de générer la réponse. Au final, nous obtenons une réponse appropriée en langage naturel.
=== Grammar-Constrained Expression ===
(12 + 8) * 3 - 5 / 5
=== Tool Execution Result ===
(12 + 8) * 3 - 5 / 5 = 59.0
=== Final Output ===
59
Liste des outils autorisés : Limiter en toute sécurité les éléments que le modèle peut utiliser
Le paramètre « allowed_tools » vous permet de limiter le modèle à une sélection sécurisée d'outils parmi l'ensemble de vos outils. Cela améliore la prévisibilité et empêche les appels d'outils non intentionnels, tout en offrant au modèle une certaine flexibilité dans le cadre de l'ensemble autorisé.
Vous pouvez permettre au modèle de choisir parmi les outils autorisés ou exiger qu'il en utilise un, reflétant ainsi les comportements de « force tool » observés dans d'autres piles et s'alignant sur les meilleures pratiques générales en matière d'orchestration des appels d'outils.
Nous allons maintenant écrire le code qui autorise un seul outil, demande au modèle d'appeler uniquement cet outil, l'exécute, renvoie les résultats, puis génère un résumé concis destiné à l'utilisateur.
Remarque : Veuillez créer un compte gratuit compte Firecrawl, générez une clé API, enregistrez-la en tant que variable d'environnement FIRECRAWL_API_KEY et installez le SDK Python Firecrawl à l'aide de pip install firecrawl-py.
Dans cet exemple de code, nous avons :
- Définition d'un ensemble complet d'outils avec
dummy_web_searchetfirecrawl_search. - Le modèle a été limité à
firecrawl_searchuniquement viatool_choice = { type: "allowed_tools", mode: "required", tools: [...] }. - Émis le premier appel de modèle, capturé le nom et les arguments de l'appel d'outil, et les a affichés pour plus de visibilité.
- Lorsque
firecrawl_searchest invoqué, les arguments désérialisés, Firecrawl exécuté, sa réponse est convertie en un dictionnaire sérialisable JSON, et la charge utile de données sécurisée est extraite. - Les résultats de l'outil ont été réintégrés dans la conversation à l'aide de
function_call_output, lié parcall_id, puis un appel final au modèle a été effectué pour résumer le tout en 3 ou 4 points avec des liens Markdown. - Une branche de secours a été incluse pour exécuter l'outil factice (bien que la liste d'autorisation l'empêche dans cette exécution).
- Impression de la réponse finale en langage naturel.
from openai import OpenAI
from firecrawl import Firecrawl
import json
import os
client = OpenAI()
firecrawl = Firecrawl(api_key=os.environ["FIRECRAWL_API_KEY"])
# --- Full toolset ---
tools = [
{
"type": "function",
"name": "dummy_web_search",
"description": "A fake web search that always returns static dummy results.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"},
"limit": {"type": "integer"}
},
"required": ["query"]
},
},
{
"type": "function",
"name": "firecrawl_search",
"description": "Perform a real web search using Firecrawl.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"},
"limit": {"type": "integer"}
},
"required": ["query"]
},
},
]
# --- Dummy implementation ---
def dummy_web_search(query, limit=3):
return {
"query": query,
"results": [f"[Dummy] Result {i+1} for '{query}'" for i in range(limit)]
}
# --- User asks ---
messages = [
{"role": "user", "content": "Find me the latest info about the stock market."}
]
# --- Restrict to Firecrawl only ---
resp = client.responses.create(
model="gpt-5",
tools=tools,
input=messages,
instructions="Only the firecrawl_search tool is allowed. Do not use dummy_web_search.",
tool_choice={
"type": "allowed_tools",
"mode": "required", # force Firecrawl
"tools": [{"type": "function", "name": "firecrawl_search"}],
},
)
for item in resp.output:
if getattr(item, "type", "") in ("function_call", "tool_call"):
print("\n--- Tool Call ---")
print("Tool name:", item.name)
print("Arguments:", item.arguments)
if item.name == "firecrawl_search":
args = json.loads(item.arguments)
# Firecrawl returns a SearchData object → convert it
results_obj = firecrawl.search(
query=args["query"],
limit=args.get("limit", 3),
)
# 🔥 Convert to JSON-serializable dict
if hasattr(results_obj, "to_dict"):
results = results_obj.to_dict()
elif hasattr(results_obj, "dict"):
results = results_obj.dict()
else:
results = json.loads(results_obj.json()) if hasattr(results_obj, "json") else results_obj
print("\n--- Firecrawl Raw Results ---")
print(json.dumps(results, indent=2)[:500])
# ✅ Extract only the data portion for summarization
safe_results = results.get("data", results)
# Feed back to GPT
messages += resp.output
messages.append({
"type": "function_call_output",
"call_id": item.call_id,
"output": json.dumps(safe_results) # now safe
})
# Final pass
final = client.responses.create(
model="gpt-5",
tools=tools,
input=messages,
instructions="Summarize the Firecrawl search results into 3-4 bullet points with clickable [Title](URL) links."
)
print("\n--- Final Natural Language Answer ---")
print(final.output_text)
elif item.name == "dummy_web_search":
args = json.loads(item.arguments)
results = dummy_web_search(args["query"], args.get("limit", 3))
print("\n--- Dummy Web Search Results ---")
print(json.dumps(results, indent=2))
Il a sélectionné la recherche Firecrawl et, à l'aide de celle-ci, a généré la réponse finale au format Markdown.

Préambules : Indiquez au modèle comment appeler les outils
Les préambules sont de brèves explications générées par le modèle avant d'invoquer un outil, clarifiant la raison de l'appel. Ils renforcent la transparence, renforcent la confiance des utilisateurs et améliorent la clarté du débogage dans les flux de travail complexes. Vous pouvez les activer à l'aide d'une instruction simple telle que « expliquer avant d'appeler un outil », généralement sans ajouter de latence notable.
Nous allons maintenant écrire le code dans lequel le modèle génère d'abord une brève ligne « Préambule : » expliquant pourquoi il fait appel à un outil, puis appelle l'outil, vous l'exécutez localement, renvoyez le résultat, et le modèle produit une réponse finale claire.
Dans cet exemple de code, nous avons :
- Initialisation du client OpenAI et définition d'un outil fonctionnel strictement typé (
medical_advice) avec JSON Schema. - Ajout d'une instruction système demandant au modèle de générer une ligne d'
“Preamble:”s avant tout appel d'outil. - Commencez la conversation en posant une question sur les symptômes de l'utilisateur.
- Effectuer le premier appel de modèle pour obtenir à la fois le préambule et l'appel d'outil avec ses arguments.
- Nous avons extrait et exécuté l'outil localement afin de générer des recommandations.
- Renvoi des résultats de l'outil vers le modèle, lié via
call_id. - Nous avons effectué un appel final au modèle afin que GPT-5 présente le résultat sous la forme d'une réponse concise et conviviale.
from openai import OpenAI
import json
import random
client = OpenAI()
# --- Fake tool implementation ---
def medical_advice(symptom: str):
remedies = {
"headache": "You can take acetaminophen (paracetamol) or ibuprofen, rest in a quiet room, and stay hydrated.",
"cough": "Drink warm fluids, use honey in tea, and consider over-the-counter cough syrup.",
"fever": "Use acetaminophen to reduce fever, stay hydrated, and rest. See a doctor if >39°C.",
}
return {"advice": remedies.get(symptom.lower(), "Please consult a healthcare provider for guidance.")}
# --- Tool definition ---
tools = [{
"type": "function",
"name": "medical_advice",
"description": "Provide safe, general over-the-counter advice for common symptoms.",
"parameters": {
"type": "object",
"properties": {"symptom": {"type": "string"}},
"required": ["symptom"],
"additionalProperties": False
},
"strict": True,
}]
# --- Messages (system preamble instruction) ---
messages = [
{"role": "system", "content": "Before you call a tool, explain why you are calling it in ONE short sentence prefixed with 'Preamble:'."},
{"role": "user", "content": "What should I take for a headache?"}
]
# 1) First call: expect preamble + tool call
resp = client.responses.create(model="gpt-5", input=messages, tools=tools)
print("=== First Response ===")
for item in resp.output:
t = getattr(item, "type", None)
if t == "message":
# Extract just the model's text
content = getattr(item, "content", None)
text = None
if isinstance(content, list):
text = "".join([c.text for c in content if hasattr(c, "text")])
elif content:
text = str(content)
if text:
# ✅ Only print once
print(text)
if t in ("function_call", "tool_call", "custom_tool_call"):
print("Tool:", getattr(item, "name", None))
print("Args:", getattr(item, "arguments", None))
# Extract tool call
tool_call = next(x for x in resp.output if getattr(x, "type", None) in ("function_call","tool_call","custom_tool_call"))
messages += resp.output
# 2) Execute tool locally
args = json.loads(getattr(tool_call, "arguments", "{}"))
symptom = args.get("symptom", "")
tool_result = medical_advice(symptom)
# 3) Return tool result
messages.append({
"type": "function_call_output",
"call_id": tool_call.call_id,
"output": json.dumps(tool_result)
})
# 4) Final model call → natural answer
final = client.responses.create(model="gpt-5", input=messages, tools=tools)
print("\n=== Final Answer ===")
print(final.output_text)
Vous pouvez constater qu'avant d'appeler l'outil, il fournit une explication sur la raison pour laquelle il fait appel à cet outil. Cela est utile pour l'observabilité et le débogage.

Résumé
GPT-5 est le modèle le plus avancé d'OpenAI à ce jour, particulièrement performant dans le domaine du codage et des flux de travail basés sur des agents. Ses dernières fonctionnalités API permettent le développement simple de systèmes de qualité production, de bout en bout.
Dans ce tutoriel, vous avez appris à :
- Renvoyer des résultats structurés à l'aide des outils de fonction et du schéma JSON pour une automatisation en aval fiable.
- Activez l'exécution en format libre avec les outils personnalisés (texte brut), ce qui permet au modèle de générer du code, du SQL, des scripts shell et des fichiers CSV au-delà des simples appels JSON.
- Formats restreints Utilisation des contraintes grammaticales Lark lorsque la précision est essentielle, comme en mathématiques, en SQL ou dans les langages spécifiques à un domaine (DSL).
- Limiter l'accès aux outils à l'aide de listes d'autorisation (ou en imposant un seul outil) afin d'améliorer la sécurité, le contrôle et le déterminisme.
- Améliorer la transparence grâce à de brefs préambules, afin que le modèle explique pourquoi il fait appel à un outil spécifique, ce qui facilite l'observabilité et le débogage.
Pour en savoir plus sur les possibilités offertes par les différents outils d'OpenAI, je vous recommande de suivre notre parcours de compétences cursus de compétences OpenAI Fundamentals et cours « Travailler avec l'API OpenAI ».

En tant que data scientist certifié, je suis passionné par l'utilisation des technologies de pointe pour créer des applications innovantes d'apprentissage automatique. Avec une solide expérience en reconnaissance vocale, en analyse de données et en reporting, en MLOps, en IA conversationnelle et en NLP, j'ai affiné mes compétences dans le développement de systèmes intelligents qui peuvent avoir un impact réel. En plus de mon expertise technique, je suis également un communicateur compétent, doué pour distiller des concepts complexes dans un langage clair et concis. En conséquence, je suis devenu un blogueur recherché dans le domaine de la science des données, partageant mes idées et mes expériences avec une communauté grandissante de professionnels des données. Actuellement, je me concentre sur la création et l'édition de contenu, en travaillant avec de grands modèles linguistiques pour développer un contenu puissant et attrayant qui peut aider les entreprises et les particuliers à tirer le meilleur parti de leurs données.