Définir des Fonctions en Python
Mis à jour le 29 juillet 2026
De la théorie au code
Vous connaissez maintenant le processus en cinq étapes et la structure JSON Schema. Il est temps d’écrire du vrai code Python. Dans cette leçon, vous allez créer des fonctions, rédiger leurs spécifications et préparer l’ensemble pour l’API Mistral — tout ce qui doit exister avant le premier appel réseau.
Installer le SDK Mistral
Commencez par installer le package officiel :
pip install mistralai
La clé API se configure ensuite. La bonne pratique consiste à ne jamais l’écrire dans le code, mais à la lire depuis une variable d’environnement : votre fichier source pourra alors être commité sans crainte.
export MISTRAL_API_KEY="votre-clé-api"
import os
from mistralai import Mistral
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
Créer les fonctions Python
Prenons un exemple concret : un système de suivi de paiements adossé à un DataFrame Pandas. C’est l’exemple classique de la documentation Mistral, et il illustre parfaitement le concept — le DataFrame tient ici le rôle que jouerait une base de données en production.
import pandas as pd
import json
# Données de paiements
data = {
"transaction_id": ["T1001", "T1002", "T1003", "T1004", "T1005"],
"customer_id": ["C001", "C002", "C003", "C002", "C001"],
"payment_amount": [125.50, 89.99, 350.00, 45.00, 210.75],
"payment_date": ["2026-03-15", "2026-03-16", "2026-03-17", "2026-03-17", "2026-03-18"],
"payment_status": ["payé", "payé", "en_attente", "payé", "échoué"]
}
df = pd.DataFrame(data)
Vient ensuite le code qui accède réellement à ces données. Ce sont des fonctions Python parfaitement ordinaires : rien dans leur écriture ne trahit qu’elles seront pilotées par un modèle de langage.
def retrieve_payment_status(df: pd.DataFrame, transaction_id: str) -> str:
"""Récupère le statut d'un paiement par son identifiant."""
if transaction_id in df["transaction_id"].values:
status = df[df["transaction_id"] == transaction_id]["payment_status"].values[0]
return json.dumps({"status": status})
return json.dumps({"error": f"Transaction {transaction_id} introuvable"})
def retrieve_payment_date(df: pd.DataFrame, transaction_id: str) -> str:
"""Récupère la date d'un paiement par son identifiant."""
if transaction_id in df["transaction_id"].values:
date = df[df["transaction_id"] == transaction_id]["payment_date"].values[0]
return json.dumps({"date": date})
return json.dumps({"error": f"Transaction {transaction_id} introuvable"})
Deux détails d’implémentation méritent votre attention. D’abord, ces fonctions retournent toujours une chaîne JSON, jamais un objet Python : c’est le format que le modèle attend comme résultat de tool, et le json.dumps() est donc non négociable. Ensuite, elles gèrent explicitement le cas de la transaction introuvable au lieu de lever une exception. Cette erreur, formatée en JSON, sera renvoyée au modèle comme n’importe quel autre résultat — il pourra alors dire poliment à l’utilisateur que la transaction T9999 n’existe pas. Vous verrez plus loin dans le cours pourquoi ce réflexe est essentiel.
Écrire les spécifications JSON
Chaque fonction a besoin de sa spécification pour que le modèle la comprenne. Vous retrouvez ici la structure de la leçon précédente, cette fois appliquée aux deux fonctions ci-dessus — notez la correspondance stricte entre les name et les noms Python réels.
tools = [
{
"type": "function",
"function": {
"name": "retrieve_payment_status",
"description": "Récupère le statut d'un paiement (payé, en_attente, échoué) "
"à partir de l'identifiant de transaction.",
"parameters": {
"type": "object",
"properties": {
"transaction_id": {
"type": "string",
"description": "Identifiant unique de la transaction (ex: T1001)"
}
},
"required": ["transaction_id"]
}
}
},
{
"type": "function",
"function": {
"name": "retrieve_payment_date",
"description": "Récupère la date à laquelle un paiement a été effectué "
"à partir de l'identifiant de transaction.",
"parameters": {
"type": "object",
"properties": {
"transaction_id": {
"type": "string",
"description": "Identifiant unique de la transaction (ex: T1001)"
}
},
"required": ["transaction_id"]
}
}
}
]
Organiser les fonctions dans un dictionnaire
Le modèle vous renverra un nom de fonction sous forme de chaîne. Il vous faut donc un moyen de passer de cette chaîne à l’objet appelable correspondant, sans jamais recourir à eval ni à une cascade de if. Le dictionnaire de dispatch résout ce problème en trois lignes.
from functools import partial
# On fixe le DataFrame dans chaque fonction
available_functions = {
"retrieve_payment_status": partial(retrieve_payment_status, df),
"retrieve_payment_date": partial(retrieve_payment_date, df),
}
functools.partial règle une difficulté annexe mais réelle. Vos fonctions attendent deux arguments — le DataFrame et l’identifiant — alors que le modèle n’en fournira qu’un seul : il ne sait rien de df, et il ne doit rien en savoir. partial pré-remplit ce premier paramètre une fois pour toutes. Le même mécanisme vaut pour une connexion à une base de données, un client HTTP ou un jeton d’authentification. L’appel dynamique devient alors trivial.
function_name = "retrieve_payment_status"
function_params = {"transaction_id": "T1001"}
result = available_functions[function_name](**function_params)
# → '{"status": "payé"}'
L’option tool_choice
Au moment d’envoyer ces tools à l’API, un paramètre décide du pouvoir laissé au modèle : tool_choice. Trois valeurs sont possibles.
# Le modèle décide s'il utilise un tool ou répond directement (par défaut)
response = client.chat.complete(
model="mistral-large-latest",
messages=messages,
tools=tools,
tool_choice="auto"
)
# Force le modèle à utiliser un tool
response = client.chat.complete(
model="mistral-large-latest",
messages=messages,
tools=tools,
tool_choice="any"
)
# Empêche le modèle d'utiliser les tools
response = client.chat.complete(
model="mistral-large-latest",
messages=messages,
tools=tools,
tool_choice="none"
)
Le mode "auto" est le plus courant en production, et pour une bonne raison : un assistant de suivi de paiements doit pouvoir répondre « bonjour » sans déclencher une requête en base. Le modèle répond directement aux questions générales et n’utilise les fonctions que lorsque c’est pertinent. Une leçon entière reviendra plus loin sur les usages précis de any et none.
Points clés à retenir
- Les fonctions doivent retourner des chaînes JSON — jamais des objets Python bruts
- Utilisez un dictionnaire de dispatch pour mapper les noms de fonctions à leurs implémentations
functools.partialest idéal pour pré-remplir des paramètres comme les connexions DB ou DataFramestool_choicecontrôle si le modèle peut/doit utiliser les fonctions (auto,any,none)- Gérez toujours les cas d’erreur dans vos fonctions (paramètre invalide, donnée introuvable)