Aller au contenu principal

Conversations multi-tours avec les outils

Quand Claude utilise des outils, une seule requete ne suffit pas toujours. Il faut mettre en place une boucle de conversation qui continue tant que Claude demande a utiliser des outils, et qui s’arrete quand il a sa reponse finale.

Detecter les demandes d’outils

Le champ stop_reason de la reponse indique pourquoi Claude a arrete de generer du texte. Quand il veut appeler un outil, ce champ vaut "tool_use" :

if response.stop_reason != "tool_use":
    break  # Claude a termine, plus besoin d'outils

C’est le signal cle : tant que stop_reason vaut "tool_use", il faut continuer la boucle.

La boucle de conversation

Le schema general est simple : on boucle indefiniment, on envoie les messages a Claude, on traite les outils demandes, et on recommence jusqu’a ce que Claude fournisse une reponse finale.

def run_conversation(messages):
    while True:
        response = chat(messages, tools=[get_current_datetime_schema])
        add_assistant_message(messages, response)
        print(text_from_message(response))

        if response.stop_reason != "tool_use":
            break

        tool_results = run_tools(response)
        add_user_message(messages, tool_results)

    return messages

A chaque iteration :

  1. On appelle Claude avec les messages et les outils disponibles
  2. On ajoute la reponse de Claude a l’historique
  3. Si Claude ne demande pas d’outil, on sort de la boucle
  4. Sinon, on execute les outils et on renvoie les resultats

Gerer plusieurs appels d’outils en parallele

Claude peut demander plusieurs outils dans une seule reponse. Le contenu du message est une liste de blocs, et chaque bloc de type tool_use correspond a un appel distinct.

La fonction run_tools filtre ces blocs et traite chacun d’eux :

def run_tools(message):
    tool_requests = [
        block for block in message.content if block.type == "tool_use"
    ]
    tool_result_blocks = []

    for tool_request in tool_requests:
        # Traiter chaque demande d'outil...

Les blocs de resultats

Chaque bloc tool_use doit recevoir un bloc tool_result correspondant. Le lien entre les deux se fait via l’identifiant (tool_use_id) :

tool_result_block = {
    "type": "tool_result",
    "tool_use_id": tool_request.id,
    "content": json.dumps(tool_output),
    "is_error": False
}

Les champs importants :

  • type : toujours "tool_result"
  • tool_use_id : doit correspondre exactement a l’id du bloc tool_use
  • content : le resultat serialise en JSON
  • is_error : True si l’execution a echoue

Gestion des erreurs

Meme en cas d’erreur, il faut renvoyer un bloc de resultat a Claude pour qu’il puisse continuer la conversation :

try:
    tool_output = run_tool(tool_request.name, tool_request.input)
    tool_result_block = {
        "type": "tool_result",
        "tool_use_id": tool_request.id,
        "content": json.dumps(tool_output),
        "is_error": False
    }
except Exception as e:
    tool_result_block = {
        "type": "tool_result",
        "tool_use_id": tool_request.id,
        "content": f"Error: {e}",
        "is_error": True
    }

En signalant is_error: True, Claude sait que l’outil a echoue et peut adapter sa reponse en consequence (retenter, demander des informations supplementaires, ou informer l’utilisateur).

Routage extensible des outils

Pour gerer plusieurs outils proprement, on cree une fonction de routage qui associe chaque nom d’outil a son implementation :

def run_tool(tool_name, tool_input):
    if tool_name == "get_current_datetime":
        return get_current_datetime(**tool_input)
    elif tool_name == "another_tool":
        return another_tool(**tool_input)
    # Ajouter d'autres outils ici

Cette approche permet d’ajouter de nouveaux outils sans modifier la logique principale de la conversation.

Recapitulatif du flux complet

Le cycle complet d’une conversation multi-tours avec outils :

  1. Envoi du message utilisateur a Claude avec la liste des outils disponibles
  2. Reponse de Claude contenant du texte et/ou des demandes d’outils
  3. Execution de tous les outils demandes et creation des blocs de resultats
  4. Renvoi des resultats sous forme de message utilisateur
  5. Repetition jusqu’a ce que Claude fournisse une reponse finale (sans demande d’outil)

Ce mecanisme permet a Claude d’enchainer plusieurs outils sur plusieurs tours pour repondre a des questions complexes, tout en gardant le contexte complet de la conversation.