Spécifier pour une IA
Temps de lecture30 minEn bref
Résumé de l’article
Un agent IA de codage (Copilot, …) ne lit pas dans vos pensées : il produit du code à partir de ce que vous lui écrivez, et rien d’autre. La qualité du code généré dépend donc directement de la qualité de la spécification que vous lui donnez. Cet article propose des bonnes pratiques pour spécifier un problème de programmation à un agent IA, pour spécifier des tests permettant de vérifier que le code produit fait effectivement ce qui était demandé, et pour déboguer efficacement le code généré lorsqu’un test révèle un écart.
Points clés à retenir
- Une bonne spécification décrit le contexte, les entrées/sorties, les cas limites et donne des exemples concrets.
- Il vaut mieux découper une tâche complexe en petites étapes que de tout demander d’un coup.
- Le code généré par une IA peut sembler correct et pourtant contenir des erreurs subtiles : il doit être vérifié, pas seulement lu.
- Spécifier des tests est aussi important que spécifier le code : ils doivent couvrir les cas nominaux, les cas limites, et les cas d’erreur.
- Une IA sait corriger un bug qu’on lui décrit, mais pas détecter qu’un résultat plausible est en réalité faux.
- Dans une boucle de débogage, l’IA propose et corrige, vous détectez et jugez.
- Vous restez responsable du code produit, que vous l’ayez écrit vous-même ou fait écrire par un agent.
Contenu de l’article
Pourquoi la spécification compte particulièrement avec un agent IA
Lorsque vous écrivez du code vous-même, les ambiguïtés se révèlent progressivement : vous les résolvez au fil de l’implémentation, souvent sans même vous en rendre compte. Un agent IA, lui, doit résoudre toutes ces ambiguïtés d’un coup, au moment où il génère le code. S’il ne dispose pas de l’information nécessaire, il ne va pas s’arrêter pour vous demander de préciser (sauf agent conversationnel qui vous questionne) : il va choisir une interprétation plausible, parfois la mauvaise, et produire un code qui compile et s’exécute, mais qui ne fait pas ce que vous vouliez.
Important
Du code généré par une IA qui s’exécute sans erreur n’est pas la même chose qu’un code qui fait ce qui est attendu. L’absence d’erreur ne garantit jamais la correction : seule une vérification (relecture, tests) le permet.
Bonnes pratiques pour spécifier un problème de programmation
Donner le contexte et l’objectif
Avant de décrire le détail technique, indiquez à quoi sert le code : quel problème résout-il, dans quel programme s’insère-t-il, qui va l’utiliser. Cela permet à l’agent de faire des choix cohérents (nommage, structure) quand plusieurs solutions techniques sont possibles.
Préciser les entrées et les sorties
Pour chaque fonction, méthode ou classe demandée, précisez :
- le type et la forme des données en entrée (par exemple : un tableau Numpy de forme
(n, 2), une liste de chaînes de caractères, un entier positif) ; - le type et la forme de la sortie attendue ;
- les contraintes sur ces données (une valeur toujours positive, une liste jamais vide, des coordonnées dans un intervalle donné).
Une spécification comme “une fonction qui calcule la distance entre deux points” est ambiguë (distance euclidienne ? de Manhattan ? points en 2D ou en N dimensions ?), alors que “une fonction distance(a, b) qui prend deux tableaux Numpy 1D de même longueur et retourne la distance euclidienne entre eux, sous forme d’un flottant” ne l’est pas.
Décrire les cas limites et les comportements attendus en cas d’erreur
Les cas limites sont ce que les développeur(se)s (et les agents IA) oublient le plus facilement, alors qu’ils sont souvent le siège des bugs. Demandez-vous, et précisez à l’agent :
- Que doit-il se passer si une entrée est vide, nulle, ou de mauvaise taille ?
- Que doit-il se passer si une méthode est appelée dans le mauvais ordre (par exemple,
predictavanttrain) ? - Y a-t-il des valeurs interdites (division par zéro, indices hors limites) ?
- Le code doit-il lever une exception, retourner une valeur par défaut, ou afficher un avertissement ?
Préciser les contraintes techniques
Indiquez le langage, la version, les bibliothèques à utiliser (ou à éviter), ainsi que les contraintes de style attendues dans le cours ou le projet (nom des méthodes, structure en classes, absence de dépendances externes non autorisées, etc.). Sans cela, l’agent peut proposer une solution techniquement correcte mais qui ne respecte pas les conventions attendues (par exemple, utiliser des boucles for là où l’on attend du code vectorisé avec Numpy).
Donner des exemples concrets
Un exemple d’entrée et de sortie attendue lève souvent plus d’ambiguïtés qu’une longue description textuelle. Par exemple :
Découper la tâche en étapes
Plutôt que de demander d’un seul coup un programme complet (génération de données, entraînement, prédiction, visualisation, évaluation), demandez chaque étape séparément, et vérifiez le résultat de chaque étape avant de passer à la suivante. Cela permet de détecter une erreur tôt, avant qu’elle ne se propage dans les étapes suivantes, et de garder le contrôle sur ce que produit l’agent.
A savoir
Si le résultat produit par l’agent ne correspond pas à ce que vous attendiez, il est rarement utile d’insister avec un simple “non ce n’est pas ça”. Reformulez plutôt votre demande en précisant ce qui ne va pas et pourquoi, comme vous le feriez avec un(e) collègue qui n’a pas deviné votre intention.
Spécifier des tests pour vérifier le code généré
Spécifier le code ne suffit pas : il faut aussi spécifier comment on va vérifier que ce code fait bien ce qui était demandé. C’est d’autant plus important avec un agent IA que vous n’avez pas écrit le code vous-même, et que vous pouvez donc difficilement en garantir la correction seulement à la lecture.
Important
Ne faites jamais confiance à un agent IA qui vous affirme que “les tests passent” sans avoir vous-même exécuté ces tests. Demandez systématiquement à voir le résultat de l’exécution.
Pourquoi tester spécifiquement du code généré par une IA
Le code produit par un agent IA peut être syntaxiquement correct et pourtant :
- traiter mal un cas limite qui n’a pas été mentionné dans la spécification,
- utiliser un algorithme légèrement différent de celui attendu,
- fonctionner correctement sur l’exemple donné dans le prompt, mais pas au-delà,
- reposer sur une hypothèse erronée que l’on retrouve ensuite dans les tests eux-mêmes : si le test est écrit à partir du code, il hérite de la même erreur et « passe » alors que le code est faux.
Les tests permettent de vérifier objectivement le comportement du code, indépendamment de la confiance que vous accordez (ou non) à l’agent.
Que demander de tester ?
Une bonne spécification de tests couvre trois catégories de cas (voir les ressources sur les tests), à demander explicitement à l’agent si elles ne sont pas déjà couvertes :
- Les cas nominaux : le fonctionnement normal du code, sur des données représentatives. C’est le minimum, mais ce n’est pas suffisant à lui seul.
- Les cas limites : entrée vide, valeur unique, valeurs égales ou à égalité (ex : plusieurs voisins à la même distance dans un KNN), valeurs extrêmes.
- Les cas d’erreur : ce qui doit se passer quand une entrée est invalide, ou qu’une méthode est appelée dans le mauvais ordre. Le test doit vérifier qu’une exception appropriée est bien levée (par exemple avec
assertRaisesen Python), pas seulement que le programme ne plante pas.
Comment spécifier un test à l’agent
Comme pour le code, un test doit être spécifié avec un exemple concret : la donnée d’entrée, et le résultat exact attendu (qu’on appelle oracle), en expliquant pourquoi ce résultat est le bon (le raisonnement, pas seulement la valeur). Par exemple :
Retenez cette structure : un test, c’est un cas d’entrée précis associé à un résultat attendu, déterminé indépendamment du code. C’est la brique de base de toute vérification — et vous la retrouverez au moment de déboguer, où décrire à l’agent « pour cette entrée, j’attends ce résultat » revient exactement à lui fournir un test formulé en langage naturel.
Une demande de test vague comme « écris des tests unitaires pour la classe KNN » laisse l’agent libre de choisir des cas faciles, qui valident surtout que le code fait ce qu’il fait plutôt que ce qu’il devrait faire. C’est un piège classique : un test qui se contente de vérifier que le code renvoie ce qu’il renvoie déjà (sans valeur attendue déterminée indépendamment du code) ne détecte aucune erreur.
A savoir
Un bon test est un test qui pourrait échouer. Si vous ne voyez pas de scénario réaliste où le test échouerait sur un code buggé, c’est probablement qu’il ne teste pas grand-chose.
Vérifier les tests eux-mêmes
Les tests générés par un agent IA doivent, eux aussi, être relus avant d’être considérés comme fiables :
- La valeur attendue dans une assertion est-elle correcte, ou a-t-elle simplement été copiée depuis la sortie du programme testé ?
- Le test couvre-t-il vraiment un cas limite pertinent pour le problème, ou reste-t-il uniquement sur des cas simples ?
- Le test échoue-t-il bien si l’on introduit volontairement une erreur dans le code (par exemple en modifiant une valeur de la spécification) ? Ce procédé, appelé parfois mutation manuelle, est un bon moyen de vérifier qu’un test a du sens : un test qui continue de passer alors que le code a été délibérément faussé ne teste rien.
Déboguer du code avec un agent IA
Quand un test échoue ou qu’un comportement vous paraît suspect, vous pouvez donner le code seul à l’agent et lui demander « où est le bug ? » — et souvent il proposera quelque chose de pertinent. Mais cette demande le fait deviner votre intention : il pointe l’endroit le plus plausible, parfois juste, parfois à côté, sans rien qui garantisse qu’il a visé le bon écart. La façon fiable de solliciter l’agent est de lui donner cette intention plutôt que de la lui faire deviner : lui apporter le cas qui échoue et le résultat attendu. Comme pour la génération et les tests, quelques bonnes pratiques font toute la différence — et elles éclairent où se situe votre part irremplaçable dans le débogage.
Fournir à l’agent IA le cas qui échoue et le résultat attendu
Vous savez déjà, depuis la partie sur les tests, ce qu’est un cas d’entrée associé à un résultat attendu. Déboguer avec un agent, c’est appliquer exactement cette brique : ne lui demandez pas de deviner ce qui cloche, apportez-lui le code, l’entrée précise qui pose problème, le résultat que vous obtenez et surtout le résultat que vous attendiez, puis demandez la correction. Formulé ainsi, l’agent dispose de tout ce qu’il faut pour localiser la cause et proposer un correctif — et il le fait généralement bien.
Remarquez ce que vous venez de lui fournir : un cas d’entrée et un résultat attendu, c’est-à-dire un test exprimé en langage naturel. L’agent débogue efficacement précisément parce que vous lui avez apporté l’oracle — la valeur attendue, tirée de votre intention, jamais du code.
Savoir que le comportement est faux : l’étape que l’agent ne peut pas faire à votre place
La bonne pratique ci-dessus suppose une étape acquise : je constate qu’un cas ne donne pas le bon résultat. Or c’est le vrai maillon fragile. Pour certains bugs, l’anomalie saute aux yeux — le programme plante, ou renvoie une aberration. Mais les bugs les plus dangereux ne se signalent pas : le code s’exécute et renvoie un résultat plausible.
Reprenons la classe KNN de l’exemple précédent. Votre spécification demande une distance euclidienne. L’agent a écrit :
Ce code est irréprochable : il s’exécute, ne lève aucune erreur, et renvoie des prédictions crédibles — la distance de Manhattan est une vraie distance, souvent proche de l’euclidienne. Rien, à l’œil, ne vous alerte. Et un agent à qui vous demanderiez « ce code contient-il un bug ? » ne signalerait rien non plus : du point de vue du code seul, il n’y a rien à signaler. L’erreur n’existe que par rapport à votre spécification, que ni vous ni l’agent ne relisez au moment de regarder la sortie.
C’est ici que le test conçu depuis la spécification devient irremplaçable : son rôle n’est pas de corriger le bug — l’agent s’en charge — mais de le révéler. Choisir un point à classer, calculer à la main ses distances euclidiennes aux points d’entraînement, en déduire la classe attendue, puis comparer à la sortie du code : voilà ce qui fait tomber le masque du résultat « plausible ». Le test échoue, et vous tenez enfin votre cas — celui que vous donnerez ensuite à l’agent pour qu’il corrige. Un oracle recopié de la sortie du programme, ou obtenu en exécutant la fonction testée, aurait au contraire épousé la distance de Manhattan et validé le bug en silence : seul un oracle indépendant du code peut faire échouer un code cohérent mais non conforme.
Important
Un agent IA corrige d’autant mieux qu’on lui fournit un oracle. Mais il ne peut pas produire cet oracle à votre place : décider ce que le résultat devrait être relève de la spécification, pas du code. Un agent qui ne connaît que le code ne peut pas savoir que ce code contredit votre intention.
Le partage des rôles dans une boucle de débogage
- L’agent propose et corrige : pistes de cause, correction du code, et souvent des cas de test auxquels vous n’auriez pas pensé.
- Vous détectez et jugez : c’est vous qui tenez la spécification, donc vous seul(e) pouvez produire l’oracle qui révèle l’écart, puis confirmer que la correction est réellement bonne.
Une boucle efficace enchaîne donc : révéler l’écart par un test à oracle indépendant → apporter à l’agent le cas et le résultat attendu → le laisser corriger → relancer tous les tests pour vérifier qu’aucun autre cas n’a été cassé. L’agent IA est pleinement utile aux deux bouts ; au milieu, sur l’oracle, il ne peut pas vous remplacer.
A savoir
La bonne question n’est pas « l’IA sait-elle déboguer ? » (souvent, oui), mais « qu’est-ce que je dois lui apporter pour qu’elle débogue le bon bug ? ». La réponse est presque toujours la même : un cas concret et le résultat attendu, tiré de votre intention — c’est-à-dire un test.
Conclusion
Travailler efficacement avec un agent IA de codage déplace une partie de l’effort : moins de temps passé à écrire le code ligne par ligne, mais davantage de temps et de rigueur nécessaires pour spécifier ce qui est attendu et pour vérifier, via des tests bien choisis, que le résultat correspond à la spécification. Le débogage ne fait pas exception : l’agent sait corriger un bug qu’on lui décrit, mais c’est à vous de le détecter et de déterminer, depuis la spécification, ce que le résultat aurait dû être. Spécifier, vérifier, décider ce qui est correct : ces compétences restent entièrement de votre responsabilité, et c’est précisément ce que l’agent IA ne peut pas remplacer.