Construire un système de conversation avec des outils nécessite d'implémenter 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étecter les 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 continuer la boucle de conversation :
if response.stop_reason != "tool_use":
break # Claude is done, no more tools neededLa boucle de conversation
La fonction principale de conversation 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.
Gérer 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
Chaque bloc d'utilisation d'outils doit recevoir une réponse sous la forme d'un bloc de résultat d'outil correspondant. La connexion entre eux est maintenue grâce à des identifiants correspondants :

La structure du bloc de résultat d'outil comprend :
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 de gérer les erreurs potentielles. Lorsqu'un outil échoue, nous devons toujours fournir un bloc de résultat à Claude :
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 qui associe les noms d'outils à leurs implémentations :
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)
# Ajoutez d'autres outils selon les besoinsCette approche facilite l'ajout de nouveaux outils sans modifier la logique de conversation principale.
Flux de travail complet
Le flux de travail complet de conversation multi-tours fonctionne ainsi :
- Envoyer le message de l'utilisateur à Claude avec les outils disponibles
- Claude répond avec du texte et/ou des demandes d'outils
- Exécuter tous les outils demandés et créer des blocs de résultats
- Renvoyer les résultats des outils sous forme de message utilisateur
- Répéter jusqu'à ce que Claude fournisse une réponse finale
Cela crée une expérience fluide où Claude peut utiliser plusieurs outils sur plusieurs tours pour répondre pleinement à des demandes utilisateur complexes. L'historique de la conversation maintient le contexte complet, permettant à Claude de s'appuyer sur les résultats d'outils précédents pour fournir des réponses complètes.