ReActAgent(Workflow)

, par Bertrand Degoy

La boucle ReAct repose sur un principe simple  : le workflow orchestre, l’agent raisonne. À chaque appel, génère un prompt, interroge le LLM, reconstruit une étape de raisonnement et laisse le finalizer décider de la suite. Une mécanique minimale côté workflow, une intelligence maximale côté agent.


La boucle de raisonnement ReAct

Le workflow considéré ici est celui de llamaindex.core.agent workflow de LlamaIndex version 0.14.10, avec le module indépendant workflows version 0.4.9.

Il s’agit d’un workflow synchrone, mono-agent, basé sur 5 événements, orchestré par Workflow.run() : boucle : LLM → Tool → LLM → Tool → … → FinalAnswer

Cette boucle simple permet d’imposer un fonctionnement ReAct strict : Thought ->Action -> Observation.

Les derniers développements de LlamaIndex ont éliminé ce mode de fonctionnement au profit d’un workflow multi-agent et asynchrone. Cela est contraire au principe de ReAct : Si l’on a besoin d’un traitement complexe on crée l’outil nécessaire. Le fonctionnement asynchrone n’a pas de sens au niveau de la boucle ReAct qui fonde son Thought sur l’Observation précédente comportant la totalité des réponses attendues. S’il doit y avoir du parallélisme, ce devra être géré au niveau de l’outil.

Comment ReActAgent s’insère dans le Workflow LlamaIndex

LlamaIndex ReActAgent, construit sur Workflow, fournit le code du step dans un workflow. Le workflow appelle :

BaseAgent.run_agent_step()
    → ReActAgent.take_step()

Donc :

  • le workflow = chef d’orchestre (encore un !)

  • l’agent = une étape du workflow

  • take_step() = la logique ReAct pour une étape

PNG - 563.7 ko

Comment sont construites les steps ReAct ?

En vérité : Le Workflow ne construit pas des steps ReAct. C’est ReActAgent qui les fait construire par le LLM. Le Workflow ne fait que :

  1. appeler take_step()

  2. attendre un AgentStepOutput (Thought, Action, Action Input ...)

  3. décider avec ReActFinalizer si une nouvelle étape doit être exécutée

Voici ce qui se passe dans ReActAgent.take_step() pour construire une étape :

Étape 1 — Construire le prompt ReAct

L’agent génère le prompt ReAct qui fixe les règles que devra suivre le LLM pour élaborer les THOUGHT, ACTION et ACTION INPUT, pour appeler les outils etc. Le prompt contient également l’historique des échanges et, in fine, la question de l’utilisateur. Voici un exemple très naïf :

You are a ReAct agent.
First, think step-by-step and write:
THOUGHT:
Then, if needed, write:
ACTION:
ACTION INPUT:
<context>
<query>

Étape 2 — Appeler le LLM

L’agent appelle :

llm.stream(prompt)

Le LLM génère la réponse au prompt. → Le LLM produit progressivement, par petits fragments, les deltas.

Étape 3 — Le parser reconstruit les blocs

Le ReActStreamParser transforme les deltas en blocs :

THOUGHT: ...
ACTION: ...
OBSERVATION: ...
...
FINAL_ANSWER: ...

Étape 4 — Le ReActFinalizer décide si l’étape est terminée

Le finalizer :

  • valide les blocs

  • détecte les erreurs

  • empêche les boucles

  • décide si une nouvelle étape doit être lancée

Étape 5 — Le workflow relance take_step() si nécessaire

Si le finalizer dit “continue”, alors :

workflow → BaseAgent.run_agent_step → ReActAgent.take_step()

Et une nouvelle étape ReAct est produite.

En résumé : rôle du Workflow

  • Le workflow LlamaIndex ne fait qu’appeler take_step() en boucle.

  • ReActAgent.take_step() génère une étape ReAct en appelant le LLM.

  • Le ReActStreamParser reconstruit les blocs ReAct à partir des deltas.

  • Le ReActFinalizer décide si une nouvelle étape doit être lancée.

  • Le workflow relance take_step() si nécessaire.

Diagramme des classes

PNG - 431.7 ko

Voyez aussi :
 ReActEngine v1 : Finalizer et StreamParser
 ReActEngine v1 : Modules et traitements