Aller au contenu principal

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 :

ChangementVersionCompatible ?
Correction de typo, ajout d'un exemplepatch (3.0.1 → 3.0.2)oui
Ajout d'un champ optionnel dans la sortiemineur (3.0.2 → 3.1.0)oui
Nouvelle énumération, retrait d'un champmajeur (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 :

  1. Proposer le changement dans une pull request.
  2. Ajouter les résultats d'évaluation avant/après sur le jeu de test.
  3. 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.
  4. 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 ».

Couˆt de maintenanceNconsignes2Neˊquipes\text{Coût de maintenance} \propto \frac{N_{\text{consignes}}^2}{N_{\text{équipes}}}

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 abandonnée est pire que pas de bibliothèque

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é.

Commencer avec deux consignes, pas dix

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.