Aller au contenu principal

Définir des Fonctions avec JSON Schema

Mis à jour le 29 juillet 2026

Le contrat entre votre code et le modèle

Pour que le modèle Mistral puisse appeler vos fonctions, il doit savoir ce qui existe et comment l’utiliser. C’est le rôle du JSON Schema : un format standardisé qui décrit chaque fonction — son nom, ce qu’elle fait, quels paramètres elle attend et lesquels sont obligatoires.

Gardez à l’esprit une chose pendant toute cette leçon : le modèle ne voit jamais votre code Python. Il ne voit que cette spécification. Si votre fonction gère élégamment les identifiants en minuscules mais que le schéma ne le dit pas, le modèle l’ignore. Plus votre schéma est précis et bien documenté, plus les arguments générés seront corrects.

Anatomie d’une spécification de tool

Chaque outil envoyé à l’API Mistral a la même structure :

tool = {
    "type": "function",
    "function": {
        "name": "nom_de_la_fonction",
        "description": "Description claire de ce que fait la fonction",
        "parameters": {
            "type": "object",
            "properties": {
                "param1": {
                    "type": "string",
                    "description": "Description du paramètre"
                },
                "param2": {
                    "type": "integer",
                    "description": "Description du paramètre"
                }
            },
            "required": ["param1"]
        }
    }
}
ChampRôle
typeToujours "function" (d’autres types pourront exister dans le futur)
function.nameLe nom exact de votre fonction Python — c’est ce que le modèle retournera dans tool_calls
function.descriptionUne phrase claire qui aide le modèle à choisir la bonne fonction
function.parametersUn objet JSON Schema décrivant les paramètres attendus
requiredLa liste des paramètres obligatoires

Les types JSON Schema supportés

Le vocabulaire de types dont vous disposez pour décrire les paramètres est volontairement restreint, et chaque type oriente le modèle différemment. Un enum en particulier ne se contente pas de documenter : il ferme la porte aux valeurs inventées.

# String — texte libre ou contraint
{"type": "string", "description": "Identifiant de transaction"}

# String avec enum — valeurs limitées
{"type": "string", "enum": ["asc", "desc"], "description": "Ordre de tri"}

# Integer — nombre entier
{"type": "integer", "description": "Nombre de résultats à retourner"}

# Number — nombre décimal
{"type": "number", "description": "Montant en euros"}

# Boolean — vrai/faux
{"type": "boolean", "description": "Inclure les transactions annulées"}

# Array — liste de valeurs
{
    "type": "array",
    "items": {"type": "string"},
    "description": "Liste des identifiants de transaction"
}

# Object — objet imbriqué
{
    "type": "object",
    "properties": {
        "city": {"type": "string"},
        "country": {"type": "string"}
    },
    "description": "Adresse de livraison"
}

Distinguez bien integer et number : un montant en euros vaut 125,50 et exige un number, tandis qu’un nombre de résultats à retourner est un integer. Déclarer un montant en integer conduira le modèle à arrondir.

Exemple complet : deux fonctions complémentaires

Voici un exemple réaliste avec deux fonctions liées aux paiements, inspiré de la documentation officielle Mistral :

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": "L'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": "L'identifiant unique de la transaction (ex: T1001)"
                    }
                },
                "required": ["transaction_id"]
            }
        }
    }
]

Les deux fonctions attendent rigoureusement le même paramètre, transaction_id, et pourtant le modèle doit choisir entre elles. Ce choix ne peut se faire que sur la description de la fonction. À « Ce paiement est-il passé ? » correspond retrieve_payment_status ; à « C’était quand ? » correspond retrieve_payment_date. Si vous aviez écrit deux descriptions vagues et interchangeables, le modèle se tromperait la moitié du temps — et vous accuseriez le modèle alors que la faute est dans le schéma.

Paramètres requis vs optionnels

La distinction entre paramètres requis et optionnels décide de ce que le modèle est autorisé à omettre.

{
    "type": "function",
    "function": {
        "name": "search_transactions",
        "description": "Recherche des transactions selon différents critères",
        "parameters": {
            "type": "object",
            "properties": {
                "status": {
                    "type": "string",
                    "enum": ["payé", "en_attente", "échoué"],
                    "description": "Filtrer par statut de paiement"
                },
                "date_from": {
                    "type": "string",
                    "description": "Date de début au format YYYY-MM-DD"
                },
                "date_to": {
                    "type": "string",
                    "description": "Date de fin au format YYYY-MM-DD"
                },
                "min_amount": {
                    "type": "number",
                    "description": "Montant minimum en euros"
                }
            },
            "required": ["status"]
        }
    }
}

Ici, seul status est requis ; les autres paramètres ne seront inclus que si l’utilisateur les mentionne. Comparez deux formulations. À « Montre-moi les paiements échoués », le modèle génère simplement {"status": "échoué"}. À « Montre-moi les paiements échoués de mars 2026 », il ajoute de lui-même date_from et date_to. Rendre ces dates obligatoires aurait cassé la première requête, ou pire, poussé le modèle à inventer une plage.

Bonnes pratiques pour les descriptions

La qualité des descriptions impacte directement la précision du modèle. Les contre-exemples ci-dessous sont plus instructifs que n’importe quelle règle abstraite.

# Mauvais — trop vague
{"description": "Récupère des données"}

# Bon — précis et contextuel
{"description": "Récupère le statut d'un paiement (payé, en attente, échoué) "
                "à partir de l'identifiant de transaction unique"}

# Mauvais — pas de description pour le paramètre
{"transaction_id": {"type": "string"}}

# Bon — description avec exemple
{"transaction_id": {
    "type": "string",
    "description": "Identifiant unique de la transaction (format: T suivi de 4 chiffres, ex: T1001)"
}}

Une bonne description dit en une phrase ce que fait la fonction, précise le format attendu pour chaque paramètre, et donne un exemple dès que ce format n’est pas évident — T1001 vaut mieux que « identifiant de transaction ». Lorsque les valeurs possibles sont limitées, ne les décrivez pas en prose : déclarez-les avec enum, c’est la seule façon de les rendre contraignantes.

Points clés à retenir

  • Le JSON Schema est le contrat entre votre code et le modèle — il décrit vos fonctions sans exposer le code
  • Chaque tool a un name, une description et des parameters typés
  • Les types supportés incluent string, integer, number, boolean, array et object
  • La liste required distingue les paramètres obligatoires des optionnels
  • Des descriptions précises avec des exemples améliorent significativement la précision du modèle