Module 10 — Bibliothèque de consignes réutilisables
Les neuf modules précédents ont écrit une consigne. Ce module la fait
survivre au développeur qui l'a écrite. Une consigne enfouie dans un
fichier notes.txt n'existe que pour elle-même ; une consigne versée
dans la bibliothèque d'équipe devient un actif de l'entreprise, comme
une fonction dans une bibliothèque logicielle.
Le problème du chaos silencieux
Dans une équipe sans discipline, six mois après le lancement du premier service LLM, la situation typique est celle-ci :
- Cinq services utilisent chacun leur propre consigne pour la même tâche (« extraire des champs d'un courriel »).
- Trois d'entre elles ont un vouvoiement, deux un tutoiement.
- Aucune n'a de numéro de version.
- Deux sont dans le code Python, deux dans un fichier YAML, une dans un secret manager par confusion avec une clé.
- Personne ne se souvient de la performance mesurée sur laquelle la décision de choisir tel modèle a été prise.
Le coût de ce chaos n'apparaît pas à court terme. Il apparaît quand il faut changer de fournisseur, quand une contrainte réglementaire impose une revue, ou quand un ingénieur clef part.
Un gabarit paramétrable
La première brique : séparer la partie fixe de la consigne des variables qui changent à chaque appel. Un gabarit ressemble à ceci :
# consignes/extraction-reclamation/v3.yml
id: extraction-reclamation
version: "3.0.2"
description: |
Extrait quatre champs d'un courriel de réclamation client.
Utilisée par le service de tri support depuis avril 2026.
modele: gpt-4o-mini-2024-07-18
temperature: 0
response_format: json_schema
systeme: |
Tu extrais quatre champs d'un courriel de réclamation au service
après-vente d'une enseigne de petit électroménager.
Rends un objet JSON conforme au schéma « reclamation ».
variables:
- nom: courriel
type: string
description: contenu textuel du courriel du client
schema: schemas/reclamation.json
exemples:
- fichier: exemples/plusieurs_produits.yml
- fichier: exemples/pas_une_reclamation.yml
Le service applicatif charge ce fichier et remplit les variables depuis son propre contexte :
def extraire(courriel: str) -> dict:
gabarit = charger_gabarit("extraction-reclamation", version="3.0.2")
return gabarit.executer(variables={"courriel": courriel})
La consigne ne vit plus dans le code Python. Le code fait référence à un identifiant et une version, et le contenu réel est un artefact versionné à part.
Versionnage sémantique
Le versionnage des consignes suit la même logique que le versionnage des bibliothèques logicielles :
| Changement | Version | Compatible ? |
|---|---|---|
| Correction de typo, ajout d'un exemple | patch (3.0.1 → 3.0.2) | oui |
| Ajout d'un champ optionnel dans la sortie | mineur (3.0.2 → 3.1.0) | oui |
| Nouvelle énumération, retrait d'un champ | majeur (3.1.0 → 4.0.0) | non |
Un consommateur de la consigne s'épingle sur une version majeure
(^3) et bénéficie automatiquement des corrections. Une bascule vers
la version majeure suivante demande une décision explicite parce
qu'elle peut casser le contrat de sortie.
Documenter le contexte d'usage
Une consigne n'est pas universellement bonne : elle est bonne pour un usage donné. La bibliothèque documente cet usage :
# extraction-reclamation
## Cas d'usage
Extraction de quatre champs (motif, produit, urgence, action) depuis
un courriel de réclamation client rédigé en français, adressé au
service après-vente de l'enseigne Baresso.
## Limitations connues
- Un courriel bilingue français-anglais est traité comme français ;
la clause étrangère est ignorée. Pour du bilingue avéré, utiliser
`extraction-reclamation-multilingue`.
- Les courriels contenant plus de trois produits ne sont pas fiables
sur le champ « produit » : préférer un traitement manuel.
- Non testée sur les tentatives d'injection venues de pièces jointes
(voir module 8).
## Performance mesurée
Sur le jeu de test `reclamations-v2` (50 entrées) :
- motif : 94 %
- produit : 82 %
- urgence : 87 %
- action_demandee : 91 %
## Historique
- v3.0.0 (mars 2026) : ajout du champ action_demandee, cassure v2.
- v3.0.2 (juin 2026) : correction d'un exemple qui biaisait vers
« urgence : élevée ».
Ce document est la première chose que consulte un ingénieur qui envisage de réutiliser la consigne. Sans lui, la réutilisation devient un pari.
Revue entre pairs
Une consigne modifie un service en production ; elle mérite le même niveau de revue qu'un changement de code. La procédure typique :
- Proposer le changement dans une pull request.
- Ajouter les résultats d'évaluation avant/après sur le jeu de test.
- Faire relire par un pair, sur trois axes : justesse de la formulation, respect du style et de la voix de marque, absence de régression métrique.
- Fusionner uniquement si l'évaluation passe et si le pair a validé.
Cette procédure est identique à celle d'un changement de code, avec un critère spécifique : le diff de la consigne est difficile à lire, car un simple mot changé peut changer la performance de plusieurs points. La pull request doit inclure la métrique, sinon la revue est aveugle.
Gouvernance d'équipe
Trois rôles se distinguent naturellement dans une équipe mûre :
Le propriétaire de bibliothèque maintient les gabarits, arbitre les propositions de nouvelle consigne, refuse les doublons.
Les rédacteurs de consigne produisent les gabarits initiaux et leurs évolutions ; ils sont responsables de l'évaluation.
Les consommateurs intègrent les gabarits dans leurs services ; ils signalent les régressions observées en production.
Cette répartition évite deux dérives : la consigne écrite par un seul développeur qui part avec son savoir, et la consigne réécrite par chaque équipe qui refuse de dépendre de « la version de l'autre ».
Le nombre de consignes distinctes dans une bibliothèque est un indicateur de santé. Deux consignes qui font presque la même chose doublent le coût de maintenance sans bénéfice ; elles sont un signal à fusionner.
Le fil rouge, une dernière fois
Le courriel de réclamation qui a servi de fil rouge depuis le module 1
existe maintenant en tant qu'entrée de bibliothèque :
extraction-reclamation:3.0.2. Son évolution est tracée : le passage
de la version 1 (module 1, sans cadrage) à la version 2 (modules 2 à
7, cadrée), puis à la version 3 (module 8, avec défense contre
l'injection, et module 9, avec évaluation continue).
La consigne originale de trois lignes du module 1 est devenue un artefact avec :
- un fichier gabarit YAML
- un schéma JSON
- cinq exemples annotés
- un jeu de test de 50 entrées
- une documentation de cas d'usage
- un historique de versions
- des métriques d'évaluation reproductibles
C'est la différence entre un prompt et une ingénierie des consignes.
Une bibliothèque de consignes qui n'est plus maintenue induit en erreur les nouveaux arrivants, qui croient réutiliser un actif validé alors qu'ils tombent sur des versions obsolètes. Si l'équipe n'a pas la capacité de maintenir la bibliothèque, il vaut mieux la démanteler proprement que la laisser pourrir sans mainteneur désigné.
Une bibliothèque naissante gagne en tenir peu d'entrées bien maintenues plutôt que beaucoup d'entrées à l'abandon. Deux ou trois consignes réellement utilisées par plusieurs services, avec leurs jeux de test et leurs métriques à jour, valent mieux qu'une bibliothèque de trente entrées non testées. La qualité vient de l'usage répété, pas de la couverture initiale.
En résumé
- Un gabarit paramétrable sépare la partie fixe de la consigne des variables d'appel, et vit dans un fichier versionné à part du code.
- Le versionnage sémantique signale explicitement quand un changement peut casser un consommateur, et permet l'épinglage.
- La documentation du cas d'usage, avec limitations et métriques, est la première chose qui doit exister pour qu'une consigne soit réutilisable.
- La gouvernance d'équipe — propriétaire, rédacteurs, consommateurs — évite le chaos silencieux qui apparaît toujours au bout de six mois.
Le récapitulatif suivant reprend les fils qui traversent le cours et prépare l'examen final.