Position du problème
Il y a des questions posées par l’utilisateur comportant implicitement une connaissance que seul cet utilisateur connaît. Par exemple l’endroit où l’utilisateur se trouve alors que la question est "à quelle distance se trouve Paris". L’agent devra poser une question telle que " Où te trouves tu ? ".
Une difficulté réside dans le fait que l’agent ReAct de Llama-index est statique (il ne peut gérer la persistance de son état interne). Au moment de l’interruption pour retourner vers l’utilisateur avec la question, il ne faut pas sortir du processus (ne pas terminer le raisonnement) sous peine de perdre son état interne.
Solution
Une bonne méthode est de mettre à la disposition du LLM un outil ’ask_user’ que le raisonnement pourra intégrer sans nécessiter l’arrêt.
Puisque que nous devons rester dans la boucle ReAct, c’est là que nous devons y insérer un nouvel échange system -> user -> system. Dans la classe ReActAgent :
- async def handle_tool_call_results(
- self, ctx: Context, results: List[ToolCallResult], memory: BaseMemory
- ) -> None:
- """Handle tool call results for React agent."""
- current_reasoning: list[BaseReasoningStep] = await ctx.store.get(
- self.reasoning_key, default=[]
- )
- for tool_call_result in results:
- ...
- # Question user
- if tool_call_result.tool_name == "ask_user":
- current_reasoning.append(
- ResponseReasoningStep(
- thought="I need to ask the user a question.",
- response=obs_step.observation, # contient la question
- is_streaming=False,
- )
- )
- break
- ...
- await ctx.store.set(self.reasoning_key, current_reasoning)
Pour assurer la cohérence entre l’outil et son usage, nous avons confié à la classe ReActAgent le soin de fournir l’outil ask_user :
- @staticmethod
- def get_ask_user_tool() -> FunctionTool:
- """
- Retourne un outil permettant au modèle de poser une question à l'utilisateur.
- """
- def ask_user(question: str) -> str:
- """Ask the user a question and wait for their answer; use this when information is missing to proceed.
- Example:
- Thought: I need the user's client number to proceed.
- Action: ask_user
- Action Input: "Quel est votre numéro de client ?"
- """
- return f"[USER_INPUT_REQUIRED] {question}"
- ask_user_tool = FunctionTool.from_defaults(
- fn=ask_user,
- name="ask_user",
- description= "Ask the user with a question and wait for their answer.",
- return_direct=True,
- )
- return ask_user_tool
Et dans l’Orchestrateur, au moment de la construction de la liste des outils :
- # Ajouter l'outil de dialogue avec l'utilisateur
- try:
- ask_user = ReActAgent.get_ask_user_tool()
- tools.append(ask_user)
- except:
- pass