Aller au contenu principal

Fine-tuning pour le function calling

Mis à jour le 28 juillet 2026

Pourquoi fine-tuner le function calling

Le function calling (appel de fonctions) permet au modèle de décider quand et comment appeler des fonctions externes. Sur ce terrain, le fine-tuning ne sert pas à retoucher un style de rédaction : il fiabilise une mécanique de décision. Un modèle entraîné sur vos propres appels apprend d’abord à choisir la bonne fonction parmi plusieurs disponibles. Si votre application expose à la fois une consultation de créneaux et une création de rendez-vous, la phrase « je voudrais voir ce qui est libre jeudi » ne doit jamais déclencher une réservation.

Il apprend ensuite à extraire les bons paramètres de la requête utilisateur, c’est-à-dire à convertir une formulation naturelle en valeurs conformes au schéma : « demain à 14h » devient une date et une heure normalisées. Le même mécanisme lui enseigne des réflexes moins spectaculaires mais tout aussi décisifs. Savoir quand ne PAS appeler de fonction évite l’écueil du modèle qui déclenche un outil sur un simple bonjour. Et chaîner plusieurs appels de fonctions de manière logique — lister les disponibilités, puis réserver le créneau retenu — suppose que le modèle ait vu à l’entraînement des séquences complètes plutôt que des appels isolés.

Format des données pour le function calling

Les exemples d’entraînement incluent la définition des fonctions (tools) et les appels correspondants. Le message de l’assistant ne porte plus de texte mais un tableau tool_calls ; le résultat renvoyé par votre système apparaît dans un message de rôle tool, relié à l’appel par tool_call_id ; l’assistant reprend enfin la parole pour formuler la réponse destinée à l’utilisateur. C’est cette boucle entière, et pas seulement l’appel, que le modèle doit apprendre à reproduire.

{
  "messages": [
    {
      "role": "system",
      "content": "Vous êtes un assistant qui aide à gérer les rendez-vous."
    },
    {
      "role": "user",
      "content": "Réserve-moi un créneau demain à 14h avec Dr. Martin."
    },
    {
      "role": "assistant",
      "tool_calls": [
        {
          "id": "call_001",
          "type": "function",
          "function": {
            "name": "creer_rendez_vous",
            "arguments": "{\"date\": \"2026-04-03\", \"heure\": \"14:00\", \"praticien\": \"Dr. Martin\"}"
          }
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_001",
      "content": "{\"status\": \"confirme\", \"id\": \"rdv_42\"}"
    },
    {
      "role": "assistant",
      "content": "Votre rendez-vous avec Dr. Martin est confirmé pour demain à 14h. Référence : RDV-42."
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "creer_rendez_vous",
        "description": "Crée un nouveau rendez-vous médical",
        "parameters": {
          "type": "object",
          "properties": {
            "date": {
              "type": "string",
              "description": "Date au format YYYY-MM-DD"
            },
            "heure": {
              "type": "string",
              "description": "Heure au format HH:MM"
            },
            "praticien": {
              "type": "string",
              "description": "Nom du praticien"
            }
          },
          "required": ["date", "heure", "praticien"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "lister_creneaux",
        "description": "Liste les créneaux disponibles pour un praticien",
        "parameters": {
          "type": "object",
          "properties": {
            "praticien": {"type": "string"},
            "date": {"type": "string"}
          },
          "required": ["praticien"]
        }
      }
    }
  ]
}

Cas d’usage courants

Sélection de la bonne fonction

Entraînez le modèle à distinguer quelle fonction appeler selon le contexte. Dans l’exemple ci-dessous, la demande porte sur une consultation de disponibilités et non sur une réservation : l’exemple ancre le fait qu’une question ouverte appelle lister_creneaux, et rien d’autre.

{
  "messages": [
    {"role": "user", "content": "Quels créneaux sont libres jeudi chez Dr. Martin ?"},
    {
      "role": "assistant",
      "tool_calls": [
        {
          "id": "call_002",
          "type": "function",
          "function": {
            "name": "lister_creneaux",
            "arguments": "{\"praticien\": \"Dr. Martin\", \"date\": \"2026-04-04\"}"
          }
        }
      ]
    }
  ],
  "tools": ["... mêmes tools que ci-dessus ..."]
}

Ne PAS appeler de fonction

Réservez une part de votre jeu à des échanges où le modèle ne doit utiliser aucune fonction. Un modèle entraîné exclusivement sur des appels prend l’habitude d’en produire un à chaque tour, y compris sur une salutation ou une question générale — comportement pénible pour l’utilisateur et coûteux pour votre back-end. Le contre-exemple suivant tient en quelques lignes et supprime une classe entière d’erreurs.

{
  "messages": [
    {"role": "user", "content": "Bonjour, comment allez-vous ?"},
    {
      "role": "assistant",
      "content": "Bonjour ! Je vais bien, merci. Comment puis-je vous aider avec vos rendez-vous aujourd'hui ?"
    }
  ],
  "tools": ["... mêmes tools ..."]
}

Extraction de paramètres complexes

Les demandes réelles sont rarement structurées. « Lundi prochain matin » et « le cardiologue » doivent devenir une date absolue, une période et une spécialité. C’est précisément là que le modèle de base trébuche le plus souvent, donc là que le fine-tuning produit le gain le plus visible : multipliez ce type d’exemples plutôt que les cas déjà propres.

{
  "messages": [
    {"role": "user", "content": "Annule mon rendez-vous de lundi prochain matin avec le cardiologue"},
    {
      "role": "assistant",
      "tool_calls": [
        {
          "id": "call_003",
          "type": "function",
          "function": {
            "name": "annuler_rendez_vous",
            "arguments": "{\"date\": \"2026-04-06\", \"periode\": \"matin\", \"specialite\": \"cardiologie\"}"
          }
        }
      ]
    }
  ],
  "tools": ["..."]
}

Script de préparation des données

La fabrication du fichier reste mécanique : une fonction d’assemblage, une définition d’outils partagée par tous les exemples, une liste de cas, puis une écriture ligne à ligne au format JSONL. Notez l’usage de json.dumps pour le champ arguments, qui doit être une chaîne et non un objet.

import json

def creer_exemple_function_calling(
    messages: list[dict],
    tools: list[dict]
) -> dict:
    """Crée un exemple d'entraînement pour le function calling."""
    return {
        "messages": messages,
        "tools": tools
    }

# Définition des outils
tools = [
    {
        "type": "function",
        "function": {
            "name": "rechercher_produit",
            "description": "Recherche un produit dans le catalogue",
            "parameters": {
                "type": "object",
                "properties": {
                    "requête": {"type": "string", "description": "Termes de recherche"},
                    "categorie": {"type": "string", "enum": ["electronique", "vetements", "maison"]},
                    "prix_max": {"type": "number", "description": "Prix maximum en euros"}
                },
                "required": ["requête"]
            }
        }
    }
]

# Exemples d'entraînement
exemples = [
    creer_exemple_function_calling(
        messages=[
            {"role": "user", "content": "Je cherche un casque audio à moins de 100 euros"},
            {
                "role": "assistant",
                "tool_calls": [{
                    "id": "call_1",
                    "type": "function",
                    "function": {
                        "name": "rechercher_produit",
                        "arguments": json.dumps({
                            "requête": "casque audio",
                            "categorie": "electronique",
                            "prix_max": 100
                        })
                    }
                }]
            }
        ],
        tools=tools
    )
]

# Sauvegarder
with open("function_calling_train.jsonl", "w", encoding="utf-8") as f:
    for ex in exemples:
        f.write(json.dumps(ex, ensure_ascii=False) + "\n")

Lancer le fine-tuning

Le job se crée exactement comme pour un fine-tuning conversationnel : le format enrichi est reconnu à partir du contenu du fichier, sans paramètre supplémentaire.

from openai import OpenAI

client = OpenAI()

fichier = client.files.create(
    file=open("function_calling_train.jsonl", "rb"),
    purpose="fine-tune"
)

job = client.fine_tuning.jobs.create(
    training_file=fichier.id,
    model="gpt-5.6-luna",
    suffix="function-calling-v1"
)

Bonnes pratiques

Le résultat dépend d’abord de la diversité de votre jeu. Chaque fonction doit apparaître plusieurs fois, les formulations utilisateur doivent varier pour une même intention, et vous gagnez à inclure des cas ambigus accompagnés de la résolution que vous jugez correcte, sans oublier les conversations normales qui n’appellent aucune fonction.

Vient ensuite le réalisme des paramètres. Les arguments doivent correspondre exactement au schéma défini dans tools, avec des valeurs plausibles plutôt que des placeholders comme « xxx » — un modèle entraîné sur des valeurs factices en produira. Testez systématiquement que chaque champ arguments est un JSON valide : une accolade ou un guillemet manquant suffit à rendre l’exemple inutilisable.

Reste la question des proportions. Pour un jeu de 100 exemples couvrant 3 fonctions, la répartition ci-dessous donne un équilibre sain entre couverture fonctionnelle et retenue.

Type d’exempleQuantité
Par fonction25-30
Sans appel de fonction10-15
Appels chaînés (multi-step)5-10

Points clés à retenir

  • Le format inclut les tools en plus des messages
  • Les appels de fonction utilisent tool_calls dans le message assistant
  • Incluez des exemples où le modèle ne doit PAS appeler de fonction
  • Variez les formulations pour une même intention
  • Vérifiez que tous les arguments sont des JSON valides conformes au schéma