Aller au contenu principal

Format des données : conversations JSONL

Mis à jour le 28 juillet 2026

Le format JSONL

JSONL (JSON Lines) est le format requis par l’API OpenAI pour le fine-tuning. Chaque ligne du fichier est un objet JSON indépendant représentant un exemple d’entraînement complet, ce qui permet de streamer un corpus de plusieurs dizaines de milliers d’exemples sans jamais charger le fichier entier en mémoire.

{"messages": [{"role": "system", "content": "..."}, {"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]}
{"messages": [{"role": "system", "content": "..."}, {"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]}

Règle fondamentale : une ligne = un objet JSON = un exemple. Pas de retour à la ligne dans l’objet JSON lui-même. Autrement dit, un JSON indenté « joliment » par votre éditeur casse le fichier — c’est la première cause de rejet à l’upload.

Structure d’une conversation

Chaque exemple est un objet avec une clé messages contenant un tableau de messages. Chaque message a un role et un content. Trois rôles seulement sont acceptés :

  • system : instructions globales pour l’assistant (optionnel, mais recommandé)
  • user : le message de l’utilisateur
  • assistant : la réponse que le modèle doit apprendre à produire

Le format minimal se limite à un échange utilisateur/assistant. C’est suffisant quand le comportement visé ne dépend d’aucun cadrage particulier, par exemple pour un modèle dédié à une seule tâche.

{
  "messages": [
    {"role": "user", "content": "Bonjour, comment allez-vous ?"},
    {"role": "assistant", "content": "Bonjour ! Je suis prêt à vous aider. Que puis-je faire pour vous ?"}
  ]
}

Dès que le modèle doit tenir un rôle précis, ajoutez un message système — et le même dans tous vos exemples. Notez dans l’exemple ci-dessous que la consigne « proposez toujours un rendez-vous de démonstration » est effectivement honorée par la réponse assistant : le message système décrit une contrainte, l’exemple montre à quoi elle ressemble une fois appliquée.

{
  "messages": [
    {
      "role": "system",
      "content": "Vous êtes un assistant commercial pour TechCorp. Répondez de manière concise et professionnelle. Proposez toujours un rendez-vous de démonstration."
    },
    {
      "role": "user",
      "content": "Je cherche une solution de CRM pour mon équipe de 50 personnes."
    },
    {
      "role": "assistant",
      "content": "Notre CRM TechCorp est conçu pour les équipes de 20 à 200 personnes, avec gestion des contacts, pipeline de vente et reporting intégré. Pour une équipe de 50, je vous recommande le plan Business à 29 €/utilisateur/mois. Souhaitez-vous planifier une démonstration personnalisée cette semaine ?"
    }
  ]
}

Conversations multi-tours

Vous pouvez inclure des conversations à plusieurs échanges. Le modèle apprend alors à maintenir la cohérence sur plusieurs tours : ici, la deuxième réponse s’appuie sur l’étape 2 annoncée dans la première, ce qu’un exemple isolé ne pourrait pas enseigner.

{
  "messages": [
    {
      "role": "system",
      "content": "Vous êtes un assistant technique pour une API de paiement."
    },
    {
      "role": "user",
      "content": "Comment intégrer votre API de paiement ?"
    },
    {
      "role": "assistant",
      "content": "L'intégration se fait en 3 étapes : 1) Installer le SDK avec pip install paycorp-sdk, 2) Configurer votre clé API, 3) Créer votre premier paiement. Par quelle étape voulez-vous commencer ?"
    },
    {
      "role": "user",
      "content": "Comment configurer la clé API ?"
    },
    {
      "role": "assistant",
      "content": "Récupérez votre clé dans le dashboard (Settings > API Keys), puis configurez-la dans votre code :\n\nfrom paycorp import PayCorp\nclient = PayCorp(api_key=\"votre_clé\")\n\nUtilisez la clé de test (préfixe sk_test_) en développement et la clé live (sk_live_) en production. Ne commitez jamais vos clés dans le code source."
    }
  ]
}

Pondération avec weight

Vous pouvez indiquer au modèle quels messages assistant sont les plus importants en ajoutant un champ weight :

{
  "messages": [
    {"role": "user", "content": "Résume ce document."},
    {"role": "assistant", "content": "Voici le résumé...", "weight": 1}
  ]
}

Un weight de 0 signifie que le modèle ne s’entraînera pas sur ce message assistant spécifique ; la valeur par défaut est 1. Le cas typique est la conversation multi-tours dans laquelle seul le dernier tour compte : vous conservez les échanges précédents parce qu’ils constituent le contexte nécessaire, mais vous ne voulez pas que le modèle apprenne à les reproduire — il suffit de les passer à 0.

Script de création de fichier JSONL

En pratique, vous n’écrirez jamais ce fichier à la main. La fonction ci-dessous sérialise une liste d’exemples et vous met à l’abri des deux pièges les plus courants : l’oubli du saut de ligne final et l’échappement des accents.

import json

def creer_fichier_jsonl(exemples: list[dict], chemin: str):
    """Crée un fichier JSONL à partir d'une liste d'exemples."""
    with open(chemin, "w", encoding="utf-8") as f:
        for exemple in exemples:
            ligne = json.dumps(exemple, ensure_ascii=False)
            f.write(ligne + "\n")
    print(f"Fichier créé : {chemin} ({len(exemples)} exemples)")

# Vos exemples
exemples = [
    {
        "messages": [
            {"role": "system", "content": "Assistant support client TechCorp."},
            {"role": "user", "content": "Mon compte est bloqué."},
            {"role": "assistant", "content": "Je comprends votre frustration. Pour débloquer votre compte, j'ai besoin de votre adresse email d'inscription. Je vais vérifier le statut et vous guider dans la procédure de réactivation."}
        ]
    },
    {
        "messages": [
            {"role": "system", "content": "Assistant support client TechCorp."},
            {"role": "user", "content": "Comment changer mon mot de passe ?"},
            {"role": "assistant", "content": "Pour changer votre mot de passe : allez dans Paramètres > Sécurité > Modifier le mot de passe. Entrez votre mot de passe actuel, puis le nouveau (minimum 12 caractères, avec majuscule, chiffre et caractère spécial). Confirmez et cliquez sur Enregistrer."}
        ]
    }
]

creer_fichier_jsonl(exemples, "training_data.jsonl")

Les erreurs que vous rencontrerez sont toujours les mêmes, et toutes se détectent avant l’upload. Le retour à la ligne oublié entre deux objets fusionne deux exemples en une ligne illisible. Un JSON mal formé — guillemet manquant, virgule en trop — fait échouer la ligne entière. Un content vide provoque une erreur de validation côté OpenAI, tout comme un rôle inventé : seuls system, user et assistant sont acceptés. Enfin, écrivez toujours en UTF-8 avec ensure_ascii=False, sans quoi vos accents partiront en séquences d’échappement que le modèle apprendra consciencieusement à reproduire.

Points clés à retenir

  • Une ligne JSONL = un objet JSON = une conversation complète
  • Chaque conversation contient au minimum un message user et un message assistant
  • Le message system est optionnel mais recommandé pour la cohérence
  • Utilisez weight: 0 pour exclure certains tours d’entraînement dans les conversations multi-tours
  • Validez toujours votre fichier JSONL avant de l’uploader