Aller au contenu principal

Module 1 — Anatomie d'une consigne efficace

Le cours 16 a expliqué ce qu'est un grand modèle de langage. Celui-ci explique comment lui parler pour obtenir un résultat qu'un logiciel puisse consommer. Et tout commence par une distinction simple : une consigne n'est pas un souhait, c'est une spécification exécutable.

Le fil rouge du cours : un courriel de réclamation

L'équipe support reçoit chaque matin plusieurs centaines de courriels de réclamation. On veut en extraire quatre champs pour les router vers le bon service :

  • motif — livraison, produit défectueux, facturation, autre
  • produit — la référence mentionnée, ou null
  • urgencefaible, moyenne ou élevée
  • action_demandée — remboursement, remplacement, information, aucune

Voici un exemple d'entrée réaliste, que nous garderons jusqu'au module 10 :

Bonjour, j'ai reçu hier ma commande CMD-77812 (cafetière Baresso Duo) et le
bac à eau fuit dès qu'on le remplit. Je pars en déplacement lundi, j'aurais
besoin d'un remplacement avant. Merci.

La version naïve, et pourquoi elle échoue

La première tentative ressemble presque toujours à ceci :

from openai import OpenAI

client = OpenAI()

reponse = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": f"Extrais les infos de ce courriel : {courriel}"}
],
)
print(reponse.choices[0].message.content)

Lancée sur dix courriels différents, cette consigne produit dix formats de sortie différents : un paragraphe rédigé, une liste à puces, un JSON parfois entouré de guillemets triples, parfois de texte d'introduction (« Voici les informations extraites : »), avec des noms de champs qui varient (urgency, niveau_urgence, Priorité). Rien n'est faux, mais rien n'est consommable par un logiciel sans travail d'adaptation à chaque cas.

Le modèle n'a pas mal compris. Il a compris que la tâche était vague, et il a improvisé. Une consigne efficace supprime cette latitude.

Les cinq éléments d'une consigne complète

Presque toutes les consignes robustes contiennent, explicitement ou implicitement, les mêmes cinq éléments.

ÉlémentQuestion à laquelle il répondSymptôme si absent
TâcheQue faut-il produire ?Le modèle rédige au lieu d'extraire
ContexteDe quoi parle-t-on ?Réponses génériques, hors domaine
ContraintesQu'est-il interdit ? Quels choix imposés ?Valeurs inventées, hors énumération
FormatSous quelle forme rendre le résultat ?Format différent à chaque appel
ExemplesÀ quoi ressemble un bon résultat ?Interprétation libre des cas ambigus

L'ordre n'a pas d'importance stricte, mais l'expérience montre qu'une tâche placée en tête et un format placé à la fin donnent les résultats les plus stables.

La version cadrée

Voici la même tâche, écrite avec les cinq éléments en tête :

consigne = """
Tâche : extraire quatre champs d'un courriel de réclamation client.

Contexte : les courriels arrivent en français au service après-vente d'une
enseigne de petit électroménager. Un même courriel peut mentionner plusieurs
produits ; on garde le premier explicitement défectueux.

Contraintes :
- motif ∈ {livraison, produit_defectueux, facturation, autre}
- urgence ∈ {faible, moyenne, elevee}
- action_demandee ∈ {remboursement, remplacement, information, aucune}
- si le produit n'est pas identifiable, mettre null

Format : un unique objet JSON valide, sans texte avant ni après, avec
exactement les clés motif, produit, urgence, action_demandee.

Courriel :
{courriel}
""".strip()

reponse = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": consigne.format(courriel=courriel)}],
)

Sur le même échantillon de dix courriels, cette version produit dix JSON de même structure. Il reste des erreurs de contenu — c'est ce que les modules suivants traiteront — mais le format, lui, est stable.

Ce que le modèle ignore de votre consigne

Un grand modèle de langage traite votre consigne comme du texte à compléter. Cela impose trois limites qu'aucune formulation ne contourne.

Il ne connaît pas ce que vous n'avez pas dit. Si le SKU du produit suit un format PROD- suivi de six chiffres, le modèle ne le devinera pas ; il faut l'écrire. La probabilité P(yx)P(y \mid x) ne peut inférer un motif absent du contexte xx.

Il ne se souvient pas d'un appel à l'autre. Chaque appel API repart de zéro : les corrections données à la main hier n'ont laissé aucune trace.

Il n'a pas accès au monde extérieur sans outillage explicite. Il ne peut pas vérifier que la référence produit existe réellement dans votre catalogue. Si vous en avez besoin, il faut soit fournir le catalogue dans la consigne, soit valider la sortie a posteriori.

Le modèle imite, il ne raisonne pas par défaut

Si vous écrivez « urgence : élevée » dans un exemple placé dans le contexte, le modèle aura tendance à répondre « élevée » plus souvent qu'il ne le devrait, simplement parce que ce mot est le plus récent qu'il a vu associé au champ. C'est le biais de récence, traité au module 3. La leçon immédiate : ne pas donner comme exemple le cas le plus fréquent qu'on veut que le modèle produise, sinon on ne mesure plus rien.

Diagnostiquer une consigne qui échoue

Devant une sortie décevante, la tentation est de reformuler au hasard. L'approche disciplinée consiste à identifier lequel des cinq éléments manque.

  • Format instable, guillemets triples, texte d'introduction → format sous-spécifié
  • Valeurs inventées ou hors énumération → contraintes absentes
  • Bonnes réponses hors domaine, hallucinations sur des références → contexte insuffisant
  • Réponse rédigée au lieu d'extraite → tâche floue
  • Sortie correcte en moyenne mais erratique sur les cas limites → exemples manquants

Cette grille se retiendra plus utilement qu'une liste de formules magiques. Chacun des modules suivants traite l'un de ces axes.

Toujours tester sur au moins cinq entrées différentes

Une consigne qui marche sur un courriel bien formaté peut échouer silencieusement sur un courriel bilingue, un courriel très court, un courriel sans salutation, ou un courriel qui contient lui-même du JSON. Constituer dès le premier jour un petit jeu de cinq à dix entrées représentatives évite de croire à un succès qui n'existe pas.

En résumé

  • Une consigne efficace est une spécification, pas un souhait : elle contient tâche, contexte, contraintes, format et exemples.
  • La version naïve échoue par format instable avant d'échouer par contenu ; c'est le premier symptôme à traiter.
  • Le modèle ne devine pas ce qui n'est pas écrit, ne se souvient pas entre appels et n'accède pas au monde sans outillage explicite.
  • Devant une sortie décevante, identifier lequel des cinq éléments manque au lieu de reformuler au hasard.

Module suivant : la consigne système, qui donne au modèle un cadre stable que la consigne utilisateur ne peut pas déplacer.