La création d'un système de conversation avec des outils nécessite l'implémentation d'une boucle qui continue d'appeler Claude jusqu'à ce qu'il arrête de demander l'utilisation d'outils. Lorsque Claude ne demande plus d'outils, cela signale qu'il a une réponse finale prête pour l'utilisateur.
Détection des demandes d'outils
La clé pour savoir si Claude souhaite utiliser un outil réside dans le champ stop_reason du message de réponse. Lorsque Claude décide qu'il doit appeler un outil, ce champ est défini sur "tool_use". Cela nous donne un moyen simple de vérifier si nous devons poursuivre la boucle de conversation :
if response.stop_reason != "tool_use":
break # Claude is done, no more tools neededLa boucle de conversation
La fonction de conversation principale suit un modèle simple :
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 messagesCette boucle continue jusqu'à ce que Claude fournisse une réponse finale sans demander d'outils.
Gestion de plusieurs appels d'outils
Claude peut demander plusieurs outils dans une seule réponse. Le contenu du message contient une liste de blocs, et nous devons traiter chaque bloc d'utilisation d'outils séparément :

La fonction run_tools gère cela en filtrant les blocs d'utilisation d'outils et en traitant 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...Blocs de résultats d'outils
Pour chaque bloc d'utilisation d'outils, nous devons créer un bloc de résultat d'outil correspondant. Ces blocs ont des champs requis spécifiques :

Le bloc de résultat d'outil doit inclure le même ID que le bloc d'utilisation d'outils d'origine, mais dans le champ tool_use_id :
tool_result_block = {
"type": "tool_result",
"tool_use_id": tool_request.id,
"content": json.dumps(tool_output),
"is_error": False
}Gestion des erreurs
Une exécution robuste des outils nécessite la gestion des erreurs potentielles. Lorsqu'un outil échoue, nous devons toujours renvoyer un bloc de résultat d'outil, mais avec des informations sur l'erreur :
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
}Routage évolutif des outils
Pour prendre en charge plusieurs outils, créez une fonction de routage distincte au lieu de coder en dur les noms des outils :
def run_tool(tool_name, tool_input):
if tool_name == "get_current_datetime":
return get_current_datetime(**tool_input)
elif tool_name == "other_tool":
return other_tool_function(**tool_input)
# Ajoutez d'autres outils si nécessaireCette approche permet d'ajouter facilement de nouveaux outils sans modifier la logique de conversation principale.
Flux de travail complet
La conversation complète à plusieurs tours fonctionne comme suit :
- Envoyer le message de l'utilisateur à Claude avec les outils disponibles
- Claude répond avec du texte et/ou des blocs d'utilisation d'outils
- Exécuter les outils demandés et créer des blocs de résultats d'outils
- Renvoyer les résultats des outils à Claude sous forme de message utilisateur
- Répéter jusqu'à ce que Claude fournisse une réponse finale sans demande d'outils
Cela crée une expérience fluide où Claude peut effectuer plusieurs appels d'outils sur plusieurs tours de conversation afin de recueillir toutes les informations nécessaires avant de fournir une réponse finale complète à l'utilisateur.