Piloter un agent de code : six principes qui font la différence
Entre un agent de code qui aide parfois et un agent sur lequel on peut s'appuyer, l'écart ne vient pas du modèle mais de la méthode. Six principes de pilotage, des hooks à la vérification.
Un agent de code produit vite. Trop vite pour qu’on relise tout, assez bien pour qu’on ait envie de lui faire confiance. C’est exactement là que les ennuis commencent : la question n’est pas de savoir s’il écrit du bon code, mais de savoir comment on s’en assure sans tout relire.
La différence entre un agent qui fait gagner du temps et un agent qui en fait perdre tient rarement au modèle. Elle tient à six principes de pilotage.
1. Ce qui doit arriver à chaque fois relève d’un hook, pas d’une consigne
C’est le principe le plus rentable, et le plus souvent ignoré.
Écrire « après chaque modification, lance le formateur de code » dans un fichier d’instructions fonctionne la plupart du temps. Une instruction reste soumise au jugement du modèle, à la longueur du contexte, à la concurrence avec les autres consignes. Elle se dilue.
Un hook est un script exécuté par le logiciel, pas par le modèle. Il est déterministe.
| Besoin | Mécanisme |
|---|---|
| Un contrôle après chaque modification de fichier | Hook PostToolUse filtré sur les outils d’édition |
| Un contrôle final avant de rendre la main | Hook Stop |
| Une information que l’agent doit connaître | Fichier d’instructions |
Le hook Stop mérite une mention à part : il se déclenche au moment où l’agent estime avoir terminé. Si le contrôle échoue, l’erreur lui est renvoyée et il reprend le travail au lieu de s’arrêter sur un résultat incomplet. C’est ce qui transforme « pense à lancer les tests » en « les tests tournent, sans exception ».
La règle : distinguez ce que l’agent doit savoir de ce qui doit toujours se produire. Le premier va dans les instructions, le second dans un hook.
Le corollaire sur les procédures sensibles
Une procédure outillée — déploiement, envoi d’e-mails, publication — peut être déclenchée par l’agent lui-même s’il juge qu’elle correspond à la tâche. Pour tout ce qui est irréversible ou visible par des tiers, cette capacité doit lui être retirée explicitement dans la configuration de la procédure. Seule une commande humaine doit pouvoir la lancer.
2. Les instructions permanentes coûtent du contexte en permanence
Le réflexe naturel est de tout écrire dans le fichier d’instructions du projet « pour que l’agent ait tout ». C’est contre-productif pour deux raisons.
D’abord, ce fichier est chargé à chaque session, y compris pour une tâche sans rapport. Y coller l’intégralité de la documentation d’une API interne, c’est immobiliser durablement une part de la fenêtre de contexte.
Ensuite, et c’est plus grave : plus le fichier est long, moins chaque règle est suivie. Les consignes vraiment importantes se noient dans la masse.
Un bon fichier d’instructions est court et ne contient que ce que l’agent ne peut pas découvrir seul : commandes de build et de test, conventions propres au projet, pièges connus.
Test à appliquer à chaque ligne : « si je la retire, l’agent fera-t-il une erreur ? » Si la réponse est non, elle n’a rien à faire là.
Le reste va dans des fichiers séparés, simplement signalés (« la convention de nommage des tables est dans docs/schema.md »), que l’agent consulte quand c’est utile.
Une consigne locale, un fichier local
Les fichiers d’instructions se chargent de façon hiérarchique. Celui placé à la racine est lu systématiquement ; celui placé dans un sous-dossier n’est chargé que lorsque l’agent travaille dans ce sous-dossier.
Une règle qui ne concerne que les migrations de base de données — jamais modifier une migration déjà appliquée, toujours en créer une nouvelle — appartient donc à migrations/, pas à la racine. Même logique pour api/, infra/, docs/. Le contexte n’est consommé que lorsque la consigne sert réellement.
3. Un contexte pollué se nettoie, il ne se corrige pas
Le scénario est universel. Un agent écrit une requête de reporting ; elle agrège de travers parce qu’une jointure duplique des lignes. On corrige, il recommence. On corrige à nouveau, il reproduit la même faute sous une autre forme.
La raison est mécanique. Les tentatives ratées restent dans le contexte et continuent d’influencer l’agent, qui a tendance à reproduire les schémas qu’il voit — y compris ses propres erreurs. Une quatrième correction, même plus ferme, ne fait qu’ajouter du bruit.
Règle pratique : après deux corrections infructueuses sur le même point, on repart d’un contexte propre. Et le nouveau premier message intègre directement ce qu’on a appris — le schéma des tables concernées, la cardinalité attendue, un exemple du résultat correct sur trois lignes.
Trois outils, trois usages distincts :
| Situation | Action |
|---|---|
| On change complètement de sujet | Repartir d’une conversation vide (/clear) |
| Une même tâche longue, le contexte se remplit | Résumer l’échange (/compact) |
| Une longue série de tâtonnements, mais on veut garder le code produit | Revenir en arrière en ne restaurant que la conversation (/rewind) |
Ce dernier point est sous-estimé : après vingt messages passés à traquer une fuite mémoire, on peut retirer tout ce tâtonnement du contexte en conservant les fichiers dans leur état corrigé.
Deux réflexes complémentaires :
- Avant une tâche volumineuse — migrer une bibliothèque de composants vers une version majeure, reprendre l’ensemble des requêtes d’un module — regarder l’état du contexte (
/context) avant de commencer. S’il est déjà à moitié occupé, l’agent aura peu de place pour le travail réel. - Quand on tient à une information précise — la liste des endpoints déjà migrés, par exemple — lancer le résumé soi-même en précisant ce qu’il faut conserver, plutôt que de laisser le résumé automatique choisir. Mieux encore : faire écrire cette liste dans un fichier du projet, où elle survit à tout.
Enfin, les outils connectés consomment du contexte avant même le premier message : chaque serveur ajoute la description de ses outils. Un diagnostic de l’installation (/doctor) signale ce qui pèse trop lourd, et les serveurs se désactivent à la session (/mcp).
4. Un sous-agent ne voit que ce qu’on lui transmet
Un sous-agent travaille dans son propre contexte, séparé de la conversation principale. Il ne voit ni l’historique des échanges, ni — pour certains sous-agents de recherche en lecture seule — le fichier d’instructions du projet.
Sa seule source d’information est le message qu’on lui passe.
Conséquence concrète : si les instructions du projet disent d’ignorer le dossier v1/, conservé le temps d’une refonte, un sous-agent lancé pour cartographier le projet le parcourra quand même. Il perdra du temps sur du code mort, et pourra remonter une implémentation abandonnée comme si elle était en service.
Les consignes utiles se répètent dans la demande qu’on lui passe. Ce n’est pas de la redondance, c’est la seule façon qu’il en ait connaissance.
Cette séparation de contexte est aussi ce qui fait leur force — voir le principe suivant.
5. Donner à l’agent un moyen objectif de vérifier son travail
Sans critère vérifiable, un agent s’arrête quand il pense avoir fini. Les problèmes se découvrent au retour.
Avec un contrôle qu’il peut exécuter lui-même — tests qui passent, build qui réussit, capture comparée à une maquette — il peut boucler seul : modifier, vérifier, corriger, jusqu’à ce que le contrôle passe. C’est la différence entre « fais de ton mieux » et « voici comment savoir que c’est terminé ».
Formulez toujours le critère de fin. « C’est terminé quand le build passe et que la page correspond à la maquette » est une consigne exploitable. « Fais quelque chose de propre » ne l’est pas.
Les tests d’abord, quand le résultat est connu d’avance
Pour une logique métier dont vous connaissez les bonnes réponses — un prorata d’abonnement, un barème de quota, une règle d’arrondi — l’ordre des opérations compte :
- Vos cas concrets deviennent des tests, écrits avant le code
- L’agent vérifie qu’ils échouent — preuve qu’ils testent bien quelque chose
- Il écrit le code jusqu’à ce qu’ils passent, sans pouvoir modifier les tests
La vérité vient alors de vous, indépendamment de son code. Des tests écrits après le code décrivent ce que le code fait, pas ce qu’il devrait faire : ils valident ses erreurs au lieu de les révéler.
Et pensez aux valeurs limites. Pour un abonnement résilié en cours de mois, une résiliation le premier jour, le dernier jour, et pendant un mois de 28 jours sont bien plus révélatrices qu’une résiliation au milieu d’un mois de 30.
La relecture par un regard neuf
Dans la conversation où il a écrit le code, l’agent a en tête le raisonnement qui l’y a conduit. Il relit à travers ses propres hypothèses et tend à justifier ses choix.
Une relecture par un sous-agent qui démarre avec un contexte vierge, ne voit que les modifications et vos critères — validation des entrées, gestion des erreurs, cas limites, sécurité — repère beaucoup mieux les angles morts. C’est la position du relecteur externe, reproduite techniquement.
Vérifier une donnée issue d’un outil
Un montant inattendu dans un rapport de coûts cloud a trois origines possibles : une mauvaise requête (mauvais compte, période décalée, filtre oublié), une mauvaise lecture de la réponse, ou une dépense bien réelle.
Demander à l’agent s’il est sûr ne sert à rien — sa confiance n’est pas une preuve. Demandez la requête exacte envoyée à l’outil (compte, période, granularité, filtres) et la réponse brute. On tranche immédiatement, en remontant à la source.
6. On corrige la cause, jamais le symptôme
Une erreur bloquante est un signal. La masquer — désactiver un test, ignorer un avertissement, contourner une vérification — fait disparaître le symptôme, pas le problème. Celui-ci ressortira plus tard, souvent en production, là où il coûte le plus cher.
Ajouter un commentaire explicatif ne corrige rien : ça documente un bug qu’on livre quand même.
C’est une règle qui mérite sa place dans les instructions du projet : ne jamais désactiver un test ou un contrôle pour faire passer un build.
Deux réglages qui conditionnent le reste
Le niveau d’autonomie
Laisser un agent travailler sans surveillance suppose de choisir le bon niveau de permission. Le bon compromis existe : un mode où il enchaîne les actions sans demander confirmation, mais où les opérations risquées — déploiements, réécriture d’historique Git, suppressions — passent par un contrôle qui les bloque.
On renforce utilement avec des règles de refus explicites sur les commandes de publication et de déploiement. Un garde-fou vaut mieux qu’une consigne de prudence.
Le niveau d’effort
Les modes de raisonnement poussé sont des réglages de session : une fois activés, ils s’appliquent à toutes les tâches suivantes jusqu’à désactivation. Pertinents pour un audit ou une refonte, ils rendent chaque petite retouche plus lente et nettement plus coûteuse, sans bénéfice.
Après une grosse tâche, revenir au niveau standard fait partie du travail.
Un dernier réflexe : tester une consigne avant de la généraliser
Un champ d’API interne change de nom. Il faut le répercuter dans une quarantaine de fichiers. L’erreur coûteuse n’est pas une faute de frappe, c’est une consigne mal calibrée appliquée en masse.
Commencer par deux ou trois fichiers révèle les cas imprévus : les variables dérivées du nom, les clés dans les jeux de données de test, les occurrences dans la documentation, et surtout les chaînes qu’il ne faut pas toucher parce qu’elles correspondent à une version d’API encore déployée. La consigne s’ajuste sur l’échantillon, puis s’applique au reste en confiance.
Le même principe vaut pour tout ce qui relève du style. Les messages d’erreur d’une application, par exemple : leur ton se décrit mal mais se montre bien. Donner cinq messages existants permet à l’agent de voir ce qui est constant — le niveau de langue, la présence ou non d’une action suggérée, la façon de ne pas accuser l’utilisateur — et de produire le sixième dans le même registre. « Sois clair et professionnel » ne veut rien dire ; cinq exemples réels, si.
Ces six principes ont un point commun : aucun ne porte sur le modèle. Ils portent sur l’environnement de travail qu’on lui construit — ce qui est automatique plutôt que demandé, ce qui occupe le contexte, ce qui permet de vérifier.
C’est précisément là que se joue l’écart entre un agent qui dépanne et un agent sur lequel une équipe s’appuie en production.
Pour un échange sur l’intégration d’agents IA dans vos processus de développement, prenez contact.