Définir des Fonctions en Python
De la théorie au code
Vous connaissez maintenant le processus en 5 é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, leurs spécifications et préparer le tout pour l’API Mistral.
Installer le SDK Mistral
Commencez par installer le package officiel :
pip install mistralai
Configurez votre clé API. La bonne pratique est d’utiliser une variable d’environnement :
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 avec un DataFrame Pandas. C’est l’exemple classique de la documentation Mistral, et il illustre parfaitement le concept.
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)
Maintenant, définissez les fonctions qui accèdent à ces données :
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 points importants :
- Les fonctions retournent toujours une chaîne JSON — c’est ce que le modèle attend comme résultat de tool
- Elles gèrent le cas d’erreur (transaction introuvable) — vous verrez plus tard pourquoi c’est essentiel
Écrire les spécifications JSON
Chaque fonction a besoin de sa spécification pour que le modèle la comprenne :
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
Pour pouvoir appeler dynamiquement la bonne fonction à partir de son nom (retourné par le modèle), créez un dictionnaire de dispatch :
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 permet de pré-remplir le paramètre df pour que l’appel dynamique n’ait plus qu’à passer le transaction_id. Ainsi, quand le modèle dit « appelle retrieve_payment_status avec transaction_id=T1001 », votre code fait simplement :
function_name = "retrieve_payment_status"
function_params = {"transaction_id": "T1001"}
result = available_functions[function_name](**function_params)
# → '{"status": "payé"}'
L’option tool_choice
Quand vous envoyez des tools à l’API, vous pouvez contrôler comment le modèle les utilise via le paramètre tool_choice :
# 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. Le modèle répond directement aux questions générales et utilise les fonctions uniquement quand c’est pertinent.
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)