Aller au contenu principal

Le Processus en 5 Étapes

Mis à jour le 29 juillet 2026

Un protocole clair entre vous et le modèle

Le function calling avec Mistral suit un processus en cinq étapes bien définies. Ce qui rend ce protocole lisible, c’est que chaque étape a un responsable unique : soit vous, le développeur, soit le modèle, soit l’utilisateur. Aucune n’est partagée, aucune n’est ambiguë. Prenez le temps de mémoriser ce partage avant d’écrire la moindre ligne de code : la plupart des bugs de function calling viennent d’un développeur qui attend du modèle une étape dont il est lui-même responsable.

1

Définir les fonctions (Développeur)

Vous décrivez chaque fonction disponible avec un schéma JSON : nom, description, paramètres, types et champs requis. Le modèle ne voit que cette spécification, pas votre code.

2

Interroger le modèle (Utilisateur)

L'utilisateur pose sa question en langage naturel. Vous envoyez cette requête au modèle Mistral accompagnée de la liste des outils disponibles.

3

Générer les arguments (Modèle)

Le modèle analyse la requête, choisit la fonction appropriée et génère les arguments au format JSON. Il ne l'exécute pas — il vous dit simplement quoi appeler et avec quels paramètres.

4

Exécuter la fonction (Développeur)

Votre code extrait le nom de la fonction et les arguments de la réponse du modèle, exécute la fonction correspondante et récupère le résultat.

5

Générer la réponse finale (Modèle)

Vous renvoyez le résultat de la fonction au modèle. Il l'intègre dans le contexte de la conversation et formule une réponse naturelle pour l'utilisateur.

Le flux en détail

Ces cinq étapes se traduisent très directement dans le code. Suivons-les sur un cas unique et volontairement minimal : un utilisateur veut connaître le statut du paiement T1001. Le même exemple servira de fil rouge jusqu’à la fin du bloc « Implémentation Python », alors autant vous familiariser dès maintenant avec ses identifiants.

Étape 1 : Vous définissez les outils

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_payment_status",
            "description": "Récupère le statut d'un paiement à partir de son identifiant de transaction",
            "parameters": {
                "type": "object",
                "properties": {
                    "transaction_id": {
                        "type": "string",
                        "description": "L'identifiant unique de la transaction (ex: T1001)"
                    }
                },
                "required": ["transaction_id"]
            }
        }
    }
]

Rien ici n’est du code exécutable : c’est une description. Le modèle apprendra qu’une fonction nommée get_payment_status existe, ce qu’elle fait et qu’elle exige un transaction_id de type chaîne. Il n’apprendra jamais comment elle est implémentée.

Étape 2 : L’utilisateur pose sa question

messages = [
    {"role": "user", "content": "Quel est le statut du paiement T1001 ?"}
]

Étape 3 : Le modèle génère les arguments

from mistralai import Mistral

client = Mistral(api_key="votre-clé-api")
response = client.chat.complete(
    model="mistral-large-latest",
    messages=messages,
    tools=tools
)

# Le modèle retourne un tool_call :
# function.name = "get_payment_status"
# function.arguments = '{"transaction_id": "T1001"}'

Le modèle a extrait « T1001 » de la phrase et l’a placé dans le bon champ. Notez que arguments arrive sous forme de chaîne de caractères, pas de dictionnaire : ce détail vous occupera à l’étape suivante.

Étape 4 : Vous exécutez la fonction

import json

tool_call = response.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
result = get_payment_status(**args)
# → {"status": "payé", "date": "2026-03-15"}

Étape 5 : Le modèle formule la réponse

messages.append(response.choices[0].message)
messages.append({
    "role": "tool",
    "name": "get_payment_status",
    "content": json.dumps(result),
    "tool_call_id": tool_call.id
})

final = client.chat.complete(
    model="mistral-large-latest",
    messages=messages,
    tools=tools
)
print(final.choices[0].message.content)
# → "Le paiement T1001 a été effectué le 15 mars 2026."

Deux messages ont été ajoutés à l’historique, jamais un seul : celui de l’assistant qui portait la demande d’appel, puis celui qui porte le résultat. Le tool_call_id fait le lien entre les deux. Omettez l’un ou l’autre et l’API refusera la requête ou le modèle répondra à côté.

Les patterns de flux

Selon la complexité de la requête, ce flux prend des formes différentes. Le cas le plus simple est celui où aucune fonction n’intervient : l’utilisateur pose une question générale — « que peux-tu faire ? » — et le modèle répond directement, sans jamais toucher aux outils. Vient ensuite l’appel simple, celui que nous venons de dérouler : une fonction, un résultat, une réponse.

Les deux formes suivantes sont plus intéressantes. Dans un enchaînement séquentiel, le modèle appelle une première fonction, lit le résultat, et s’en sert pour décider du second appel — typiquement retrouver l’identifiant d’un client avant d’interroger ses factures. Dans un appel parallèle, il demande l’exécution de plusieurs fonctions en même temps parce qu’aucune ne dépend de l’autre. Ces deux patterns feront l’objet de leçons entières ; retenez pour l’instant qu’ils reposent tous deux exactement sur les cinq étapes ci-dessus, simplement répétées.

Points clés à retenir

  • Le function calling suit un processus en 5 étapes avec des responsabilités claires
  • Le modèle ne peut jamais exécuter de fonction directement — il génère uniquement les arguments
  • Votre code est le gardien : c’est lui qui décide d’exécuter ou non la fonction
  • Le résultat de la fonction est renvoyé au modèle pour qu’il formule une réponse naturelle
  • Le flux peut être simple (un appel) ou complexe (séquentiel, parallèle)