Accueil / Articles / Ingénierie des boucles : Création de boucles d’agents à l’aide de vérificateurs et de règles d’arrêt.

Ingénierie des boucles : Création de boucles d’agents à l’aide de vérificateurs et de règles d’arrêt.

Un guide pratique pour créer quatre boucles d’agents empilées : les bases de ReAct, les évaluateurs de critères, le routage LangGraph, un contrat de boucle, les déclencheurs d’événements, la méthode de montée en pente et les mécanismes de protection contre les échecs.

2535 mots

La logique sous-jacente à tout cela est simple à expliquer. Cessez de diriger une IA instruction par instruction et concevez plutôt le cycle dans lequel elle évolue. L’idée principale est que c’est le vérificateur, et non le modèle, qui limite ce en quoi on peut avoir confiance ; il faut se représenter quatre cycles imbriqués les uns dans les autres. Voici comment le construire : les composants d’un cycle, le code pour chaque couche, les raisons pour lesquelles les cycles échouent, ainsi que les règles d’arrêt qui empêchent qu’ils épuisent votre budget. À la fin, vous saurez suffisamment pour laisser un cycle préparer une demande de fusion de code pendant que vous dormez.

Les exemples de code suivent les API documentées, les identifiants des modèles sont des placeholders, et tout extrait qui n’est qu’un pseudocode le précise dans un commentaire en tête. Un exemple est présenté tout au long, le point de départ habituel dans ce domaine : un cycle de codage qui reproduit un test échoué, le corrige, fait vérifier cette correction par un élément autre que l’agent lui-même, et ouvre une proposition de fusion de code en version brouillon.

Les cinq composants d’une boucle

Quel que soit le framework utilisé, une boucle fonctionnelle se résume toujours à cinq éléments. En omettre un fait que la boucle dérive, s’arrête ou tourne indéfiniment.

  1. Un déclencheur. Ce qui la met en marche, qu’il s’agisse d’un message humain, d’une fréquence programmée, d’un webhook ou d’une nouvelle ligne de tableau.
  2. Un objectif que la machine peut vérifier. « Faire passer les tests » correspond, tandis que « améliorer le code » ne le fait pas. Si le logiciel ne peut pas déterminer si l’objectif a été atteint, la boucle non plus.
  3. Des outils fournissant des retours concrets. L’agent doit agir sur le monde et observer les résultats en exécutant du code, en lisant stderr ou en appelant une API.
  4. Un état maîtrisé et minimaliste. Conservez l’objectif, un carnet de notes et un historique des tentatives effectuées. Un état surchargé est la cause pour laquelle les boucles ralentissent, dérivent et dépassent leur fenêtre de contexte.
  • Règles d’arrêt explicites. C’est l’élément le plus négligé. Une boucle sans règle d’arrêt constitue une faille dans le compte de facturation.
  • Prévoyez trois sorties et non deux. Succès : le vérificateur a validé, donc procédez à l’envoi. Échec : le budget ou la limite d’itérations est atteint, donc arrêtez-vous et résumez ce qui reste. Transfert : l’agent est confronté à une décision qui ne devrait être prise que par un humain, donc l’affaire est escaladée. Faire partie de la conception d’une bonne boucle, c’est reconnaître les appels qu’elle ne devrait pas effectuer elle-même.

    Boucle 1 : la boucle de l’agent

    Au cœur se trouve le cycle que tous les agents exécutent déjà, le modèle ReAct de 2022 : réfléchir, agir en appelant une outil, observer le résultat, et répéter jusqu’à completion. En 2026, il est conçu délibérément et n’est plus géré manuellement. Dans sa forme la plus simple, il s’agit d’un seul appel de fonction :

    from langchain.agents import create_agent
    def run_tests() -> str:
    """Run the project's test suite and return the raw output."""
    …
    agent = create_agent(
      model="anthropic:claude-opus-5",
      tools=[run_tests],
      system_prompt="You are a careful Python engineer. Fix failing tests.",
      )
    # create_agent returns a graph that calls tools in a loop, repeating
    # until the model replies with no tool calls. The loop runs on .invoke()
    

    Cette brève description cache une boucle, et vous devriez pouvoir vous en faire une idée. Ci-dessous se trouve la même structure de contrôle sous forme de pseudocode, sans aucun framework. Notez que chaque sortie est délimitée :

    # PSEUDOCODE - shows the control structure a harness implements.
    # The helper names below are yours to supply, not a real library API.
    def run_loop(goal):
      state = init_state(goal) # goal + scratchpad + attempt log
      for step in range(MAX_STEPS): # hard cap: never loop forever
        thought = model.reason(state) # ReAct: reason…
        action = model.choose_action(state) # …then pick a tool call
        result = tools.execute(action) # touch the real environment
        state = update(state, thought, action, result)
        state = compact(state) # keep context under budget
        if verifier.passes(state): # deterministic check = reward
          return success(state)
        if no_progress(state) or budget.exhausted():
          return escalate_to_human(state) # third exit: hand-off
      return escalate_to_human(state)
    

    Parmi toutes les formes présentées ici, souvenez-vous de celle-ci. Les autres ne sont que des variantes affinées d’elle.

    Boucle 2 : ajouter un vérificateur

    Un agent simple décide par lui-même quand il a terminé, et c’est en faisant confiance à cela que l’on obtient des résultats erronés. Il faut donc envelopper cet agent dans un évaluateur qui vérifie son travail selon des critères prédéfinis. Lorsque le travail échoue, les retours d’erreur sont réutilisés et la boucle se poursuit, jusqu’à atteindre une limite maximale. Le middleware de vérification se trouve dans le package deepagents.

    from deepagents import RubricMiddleware, create_deep_agent
    from langchain.messages import HumanMessage
    from langgraph.checkpoint.memory import InMemorySaver
    RUBRIC = """
    - All tests pass in run_tests
    - No test is skipped or deleted to force a pass
    """
    agent = create_deep_agent(
      model="anthropic:claude-opus-5",
      system_prompt="You are a careful Python engineer.",
      middleware=[
      RubricMiddleware(
      model="anthropic:claude-haiku-4–5", # a cheap grader is fine
      system_prompt="Grade against the rubric. Be strict.",
      max_iterations=5, # the stop rule (default is 3)
      ),
      ],
      checkpointer=InMemorySaver(),
     )
    # The rubric is passed at invoke time - not to the constructor.
    result = agent.invoke(
      {
      "messages": [HumanMessage("Make the failing tests pass.")],
      "rubric": RUBRIC,
      },
      config={"configurable": {"thread_id": "fix-tests-session"}},
    )
    

    C’est ainsi que cela fonctionne. Chaque fois que l’agent est sur le point de terminer, un sous-agent évaluateur distinct lit la transcription en fonction du critère d’évaluation. Un verdict needs_revision renvoie les retours dans la conversation sous forme de HumanMessage, permettant à l’agent de continuer. Les seules issues possibles sont satisfied, failed, max_iterations_reached et grader_error ; ainsi, la boucle se ferme et s’arrête toujours. Si l’évaluateur doit effectuer ses propres vérifications, fournissez-lui des outils sous forme d’instances BaseTool.

    Il existe deux types de vérificateurs, et choisir le bon est l’essentiel de la compétence requise.

    • Déterministe : exécute les tests, valide le schéma et confirme la note. C’est peu coûteux, rapide et impossible à tromper ; essayez-les en premier.
  • LLM-en-titre-juge : un deuxième modèle évalue selon des critères prédéfinis. Cette méthode convient aux objectifs flous, mais les biais liés à la position, à l’excès de détails et aux préférences personnelles peuvent fausser les résultats. Ne faites jamais de l’agent qui a effectué le travail son seul juge.
  • Transformer en graphe

    Lorsqu’une tâche dépasse le stade du trivial, un graphe explicite est préférable à une boucle cachée : les nœuds, les arêtes ainsi que le point où s’arrête l’exécution sont tous visibles. Un agent de recherche peut être représenté par trois nœuds, chaque décision d’arrêt étant prise par le routeur :

    from typing import Literal, TypedDict
    from pydantic import BaseModel, Field
    from langgraph.graph import END, StateGraph
    class ResearchState(TypedDict):
    question: str
    draft: str
    verdict: str
    feedback: str
    iterations: int
    class Verdict(BaseModel):
    status: str = Field(description='"verified" or "needs_work"')
    feedback: str = Field(description="claims lacking support, if any")
    def decide(state: ResearchState) -> Literal["research", "__end__"]:
    if state["verdict"] == "verified": # success exit
    return "__end__"
    if state["iterations"] >= MAX_ITERATIONS: # surrender exit
    return "__end__"
    return "research" # else: loop again with the feedback
    builder = StateGraph(ResearchState)
    builder.add_node("research", research_node) # generator
    builder.add_node("verify", verify_node) # verifier
    builder.add_edge("research", "verify")
    builder.add_conditional_edges(
    "verify", decide, {"research": "research", "__end__": END}
    )
    builder.set_entry_point("research")
    graph = builder.compile()
    

    Aucun prompt ingénieux n’apparaît dans ce code. L’intelligence réside dans la structure : un nœud génère, un autre vérifie, et un routeur transforme le résultat en une nouvelle tentative avec des retours d’information ou en arrêt. LangGraph considère les sentinelles __end__ et END comme équivalentes.

    Le contrat de boucle

    C’est ici que le changement de mentalité devient concret. Au lieu d’écrire des instructions, on rédige une spécification de « fin », c’est-à-dire une fonction de récompense associée à une règle d’arrêt. C’est cet artefact que l’on examine, que l’on compare et que l’on enregistre :

    Objectif : une compilation CI verte sur la branche payments-refactor. Cela signifie que tous les tests passent et qu’aucun n’a été sauté ou supprimé de manière frauduleuse. Étapes : lire le test qui échoue, corriger la cause probable, puis relancer les tests. Mémoire : un journal des approches déjà tentées afin d’éviter toute répétition. Arrêter lorsque tout est vert en ouvrant un PR provisoire, après six essais en résumant ce qui reste à faire, ou dès que le travail concerne la logique d’authentification ou de paiement en le transférant à une autre personne.

    Aucune instruction n’a été transmise au modèle. Ce qui a été écrit, c’est l’objectif, les contrôles, la règle de mémoire ainsi que les trois conditions d’arrêt ; ce contrat constitue en fait une ingénierie de boucles.

    Boucles 3 et 4 : empilement vers l’extérieur

    Déjà, une seule boucle bien conçue est utile. Les gains s’accumulent lorsque l’on en enveloppe d’autres, chacune fonctionnant à un rythme plus lent. Les boucles 1 et 2 assurent l’exécution correcte des tâches, tandis que les boucles 3 et 4 en font un processus continu et auto-améliorant.

    Boucle 3 : événements

    Un événement externe transforme votre boucle, d’un outil que vous appelez en un service qui s’exécute automatiquement. C’est également l’endroit idéal pour intégrer une étape d’approbation humaine avant toute mise en production :

    # Loop 3: an event turns the loop into a service
    from pydantic import BaseModel
    class CIEvent(BaseModel):
      branch: str
    @app.post("/webhook/ci-failed")
    def on_ci_failure(event: CIEvent):
      if not event.branch.startswith("fix/"): # cheap triage first
        return {"skipped": True}
      result = agent.invoke(
        {
        "messages": [HumanMessage(
          f"Fix the failing test on {event.branch}.")],
        "rubric": TEST_GREEN_RUBRIC,
        },
        config={"configurable": {"thread_id": event.branch}},
      )
      open_draft_pr(result) # a human approves the merge, not the loop
      return {"opened_pr": True}
    

    Boucle 4 : montée en pente

    La boucle la plus extérieure est la plus lente, et elle agit directement sur la boucle elle-même. Chaque exécution laisse une trace derrière elle. Un agent d’analyse lit ces traces, identifie les échecs qui se reproduisent constamment et propose des modifications au système : le prompt, les outils, la grille d’évaluation que les humains examinent. Imaginez la flèche de retour : au lieu de ne renvoyer des informations qu’au point de départ, elle atteint la boucle intérieure et la modifie. Le système améliore ainsi le système lui-même.

    Un point d’attention : les boucles extérieures multiplient tout ce qui se trouve à l’intérieur d’elles. N’ajoutez-les qu’une fois que le vérificateur intérieur est fiable, car une quatrième boucle autour d’un vérificateur faible ne fait que transformer des erreurs en masse en processus automatisés.

    Pourquoi cela compte comme de l’ingénierie

    Les garde-fous peuvent sembler être de la bureaucratie. Ils perdent cet aspect dès que l’on considère un agent comme un contrôleur à boucle fermée, c’est-à-dire une correspondance point par point. L’objectif est la valeur cible, l’agent constitue le contrôleur, et les outils ainsi que l’environnement forment la plante. Le vérificateur agit comme le capteur, et son verdict « nécessite des travaux » représente le signal d’erreur qui déclenche la correction suivante. Une tâche terminée signifie convergence. Le contrôleur est piloté par l’écart entre la valeur cible et la lecture du capteur, que la plante soit un moteur à réaction ou un ensemble de tests.

    Le même vocabulaire décrit deux manières dont une boucle peut s’interrompre. Elle peut osciller, en répétant indéfiniment une même action, ou diverger, s’éloignant de l’objectif tandis que les ressources s’épuisent. Les mécanismes de contrôle ne sont rien d’autre que les conditions de stabilité qui la maintiennent dans des limites définies, et la règle suprême est que le système doit garantir une fin, tâche pour laquelle on ne peut pas se fier à l’agent.

    Une journée avec les quatre boucles

    Observez comment les quatre boucles fonctionnent au cours d’une matinée. À 09:14, un test relatif à payments-refactor échoue et un webhook est déclenché, ce qui correspond à la boucle 3, sans que personne n’ait tapé quoi que ce soit. Pendant les sept minutes suivantes, l’agent lit l’échec, applique des correctifs, relance le test, lit à nouveau l’échec et apporte de nouveaux correctifs, tout en tenant un journal des tentatives (boucle 1). Après chaque série d’essais, un outil d’évaluation déterministe exécute l’ensemble des tests pour s’assurer qu’aucun n’a été sauté afin de forcer un résultat positif (boucle 2). La quatrième série d’essais se termine par un résultat positif.

    À 09:22, le cycle se termine correctement, avec un projet de modification préliminaire indiquant ce qui a changé et pourquoi. Une personne doit l’approuver car la modification concerne les paiements. Pendant la nuit, le cycle de détection des problèmes constate qu’il s’agit du troisième bug lié aux fuseaux horaires de la semaine et élabore une nouvelle vérification, qui passe par votre examen (cycle 4). La séance de demain commence de manière plus efficace que celle d’aujourd’hui.

    Vous avez dormi pendant la majeure partie de ce processus. Le matin, il y a un projet de modification préliminaire et une décision à prendre, sans clavier sous la main pour taper.

    Lorsque les cycles échouent

    Les boucles amplifient, et l’amplification fonctionne dans les deux sens. Chaque mode de défaillance affecte la boucle en un point précis et comporte une protection standard, avec un thème récurrent : ce qui génère ne doit pas également évaluer. La protection la moins chère consiste à faire fonctionner le vérificateur sur des entrées connues comme bonnes et connues comme mauvaises avant de laisser la boucle fonctionner seule. Vérifiez qu’il rejette les entrées mauvaises, car un vérificateur non testé n’est qu’une opinion accompagnée d’un coût.

    Quand ne pas créer de boucle

    Se hâter de mettre tout en boucle constitue à son tour un mode de défaillance. Préférez une seule appelation dans ces situations :

    • Une seule passe suffit, comme pour un résumé, une traduction ou un extrait propre. Une boucle ne fait qu’augmenter les coûts et la latence.
    • Aucun objectif ne peut être vérifié. Sans moyen de détecter si la tâche est terminée, il n’y a pas de signal d’erreur, ce qui laisse une boucle ouverte consommant des ressources inutilement.
  • Les erreurs ne peuvent pas être annulées, comme le transfert d’argent, la suppression de données ou l’envoi d’e-mails aux clients. La boucle doit s’arrêter et transférer la tâche.
  • Une personne travaillerait plus rapidement. Si la tâche prend dix secondes manuellement, la boucle est le pire outil.
  • L’ingénierie des boucles consiste à savoir quels problèmes méritent d’être traités par une boucle, tout autant que à savoir comment en construire une.

    Construisez-la comme si vous deviez garder ce poste

    Ces sont les outils : anatomie, boucle d’agent, vérificateur, graphe, contrat, boucles extérieures et catalogue des pannes. Équipez la boucle d’un vérificateur fiable, d’une arrêt automatique et de limites qu’elle ne peut pas dépasser. Ajoutez des points de contrôle humains là où les enjeux sont réels, et gardez à l’esprit qu’un correctif fourni par une boucle ne signifie pas que vous la comprenez. Laissez-la ensuite fonctionner, comme le ferait quelqu’un qui compte rester ingénieur et non simplement la personne qui l’a lancée.

    Le niveau suivant

    Une question mérite d’être posée avant de laisser un boucle sans surveillance : à quel point un vérificateur peut-il être faible et pourtant afficher une couleur verte ? Une étude de référence a été réalisée pour le découvrir. Elle recense des cas d’usurpation de récompenses et évalue les systèmes de contrôle en fonction du nombre d’usurpations qu’ils permettent. Un système de contrôle qui ignore le rapport fourni par l’agent lui-même et réexécute l’ensemble des tests, c’est-à-dire la vérification déterministe suggérée précédemment comme première solution, n’a empêché aucune des huit usurpations. La réexécution de l’ensemble des tests ne fait que confirmer que le signal de récompense a été satisfait, et c’est précisément ce qu’accomplit une usurpation de récompenses.

    Ainsi, si le vérificateur limite le système, la compétence essentielle qui devient alors cruciale est évidente : concevoir, gérer les versions et améliorer les vérifications elles-mêmes. On l’appelle l’ingénierie d’évaluation, c’est-à-dire la tâche de définir les critères que le cycle doit respecter. Un vérificateur correspond à une étape au sein d’un seul cycle. L’ingénierie d’évaluation englobe de nombreux cycles, à travers les ensembles de données et les grilles d’évaluation qui permettent de savoir si le système dans son ensemble s’améliore ou se détériore.

    Renforcer une étape de vérification revient à construire un escalier, dont le sommet est imprévisible. Il s’avère que la meilleure vérification n’est pas du tout un code sophistiqué, mais simplement quelques assertions que l’agent n’a jamais eu le droit de voir. Ainsi, la limite de la vérification se situe à un endroit délicat. Elle dépend moins de la qualité de construction d’une étape que de la qualité des données mises de côté et du fait de les empêcher de fuir à nouveau dans le cycle.