Boucles d’agent bornées
Une boucle d’outils permet à un modèle d’observer un résultat, de choisir une autre action et de poursuivre. C’est utile pour le débogage et les travaux en plusieurs étapes, mais une mauvaise hypothèse peut alors entraîner une suite d’écritures, de tentatives répétées et un contexte qui grossit.
La séparation importante est simple : le modèle propose ; le harnais d’exécution décide de ce qui peut être lancé et de ce qui compte comme une réussite.
Une seule tâche sert d’exemple tout au long de la page. Supposons que vous demandiez à un agent de réparer un test unitaire en échec, test_parse_date. Le harnais lui accorde 20 étapes et 15 minutes, et n’autorise de modifications que sous src/ et tests/.
Formes courantes de boucles
Réparer test_parse_date relève de la boucle implémentation–vérification. Les cinq formes diffèrent par le moment où elles s’arrêtent : quelle que soit la boucle dans laquelle tourne un modèle, on fixe d’abord les conditions d’arrêt.
Ce que le harnais doit prendre en charge
Budget et arrêt
Fixez les limites avant l’exécution : étapes, temps écoulé, usage du modèle, usage des outils, dépense, ainsi que les fichiers ou services autorisés. Si vous payez l’API vous-même, c’est le plafond de dépense qu’il faut fixer en premier : le mode sans surveillance de Claude Code peut limiter une exécution à 5 dollars avec --max-budget-usd 5.00 et en borner le nombre de tours avec --max-turns (référence de la ligne de commande). Ce plafond est vérifié sur une estimation côté client et la dépense peut le dépasser légèrement : gardez une marge. Arrêtez-vous lorsqu’une limite est atteinte, lorsque l’utilisateur annule, lorsque les éléments de preuve requis ne sont pas disponibles ou lorsque les échecs répétés montrent que la stratégie actuelle ne progresse pas.
Le coupe-circuit pour les appels répétés traite ce dernier cas : quand le même appel échoue N fois de suite, la boucle s’arrête d’elle-même. Dans l’exemple, prenons N = 3. Le modèle lance pytest tests/test_dates.py sans rien changer aux étapes 1, 2 et 3 et obtient chaque fois la même erreur ; le coupe-circuit arrête la boucle après l’étape 3 et rend la main à une personne, au lieu de brûler les 17 étapes restantes sur une seule commande. Le seuil doit correspondre à l’opération : réessayer la lecture d’un fichier n’est pas la même chose que réessayer un paiement ou un déploiement.
Validation des outils
Validez hors du modèle les noms d’outils, les schémas d’arguments, les chemins, les autorisations et les effets de bord ; les tableaux d’arguments et la résolution des chemins sont traités dans Contrats d’outils. Si la sortie du modèle a été tronquée par sa limite de longueur, n’exécutez aucun des appels d’outils qu’elle contient : un JSON coupé en deux peut passer la validation par hasard et lancer quand même la mauvaise opération. Pi marque tous ces appels comme échoués et demande au modèle de les soumettre à nouveau (agent-loop.ts).
Dans l’exemple, si le modèle propose de modifier config/settings.py, le contrôle de chemin constate que ce fichier est hors de src/ et tests/, refuse l’appel et inscrit la raison dans l’état : à l’étape suivante, le modèle doit passer par un autre chemin.
Vérification
La phrase finale d’un modèle n’est pas un signal d’achèvement. Le vérificateur peut être une suite de tests, une vérification de schéma, une comparaison exacte d’artefact, une assertion dans un navigateur ou une revue humaine. Il doit tester le comportement visé et être assez indépendant pour que l’agent ne puisse pas le faire passer au vert en supprimant ou en affaiblissant le contrôle.
Supposons qu’à l’étape 7 le modèle réponde « c’est réparé ». Le vérificateur relance lui-même test_parse_date, le test est toujours rouge, et la fin annoncée est refusée : la boucle continue avec la sortie de l’échec. Si le modèle avait plutôt modifié le test, par exemple en supprimant l’assertion, un vérificateur indépendant devrait aussi l’arrêter, car il contrôle le comportement attendu de l’analyse des dates, pas l’absence d’erreur dans le test.
État durable
Conservez la transcription complète et la sortie brute des outils hors du prompt actif, et tenez à côté un bref état de tâche ; ce qu’il doit contenir au minimum est décrit dans Agents de longue durée. Pour la réparation du test, cet état pourrait dire : objectif, faire passer test_parse_date en ne touchant qu’à src/ et tests/ ; modifié src/dates.py ; pytest signale encore 1 échec ; ne plus essayer de changer de bibliothèque de fuseaux horaires ; ensuite, examiner les années à deux chiffres. Un contexte neuf lit cet état et poursuit. L’état est mis à jour à partir des résultats observés, comme la sortie des tests, et non de l’assurance affichée par le modèle.
Annulation et nettoyage
Les outils de longue durée ont besoin de délais d’expiration, d’un suivi des processus et de nettoyage. Annuler dans l’interface doit aussi annuler le sous-processus ou la tâche en arrière-plan. Dans l’exemple, quand l’utilisateur clique sur Annuler, le harnais doit aussi terminer le sous-processus pytest en cours ; sinon, un agent apparemment arrêté peut continuer à écrire sur le disque.
Une boucle de contrôle minimale
Le code suivant est du pseudocode ; les interfaces d’outils et de modèles varient selon le harnais.
for step in range(max_steps):
if cancelled() or budget.exhausted():
return STOPPED
context = select_working_context(state)
proposal = model.propose(context)
if proposal.is_final:
return verify_final(proposal, state)
checked = policy.validate(proposal.tool_call)
if not checked.allowed:
state.record_denial(checked.reason)
continue
result = tools.execute(checked.call, timeout=checked.timeout)
state.record(result)
if repeated_failure(result, state):
return NEEDS_REVIEW
return STOPPED # max_steps reached
Les implémentations réelles nécessitent aussi la gestion des exceptions, des règles d’idempotence, le contrôle de concurrence et des journaux expurgés. Ce pseudocode indique la place de chaque contrôle : policy.validate bloque le chemin hors périmètre, repeated_failure joue le rôle du coupe-circuit et verify_final relance le test. Ces contrôles entourent l’appel au modèle ; ce n’est pas un prompt qui demande au modèle d’être prudent.
Indices de progrès réel
Un ensemble d’échecs qui diminue, un nouveau test discriminant, un diff plus petit et justifié ou une ambiguïté levée constituent des progrès. Reformuler le même diagnostic, ajouter des abstractions sans éléments de preuve ou prolonger l’exécution n’en sont pas. Dans l’exemple, passer de 3 échecs à 1 est un progrès ; répéter une troisième fois « c’est peut-être le fuseau horaire » sans nouvelle sortie de test n’en est pas un.
La meilleure boucle est généralement la plus petite boucle autonome capable de terminer la tâche de façon fiable. N’ajoutez des exécutants parallèles, des couches de planification et de l’autocritique que lorsqu’un échec mesuré le justifie.