Conversations multi-tours avec outils
Mis à jour le 30 juillet 2026
Le cycle manuel du Tool Use fonctionne ; reste à l’automatiser. Construire des conversations multi-tours avec le Tool Use nécessite de gérer différents types de réponses de Claude : parfois il a besoin d’un outil, parfois il répond directement — et votre code doit gérer les deux scénarios sans intervention humaine. C’est l’objet de cette leçon : la boucle conversationnelle qui rend le système autonome.
Le problème de l’intégration simple
Pourquoi une boucle intelligente plutôt qu’un enchaînement fixe ? Parce que si vous ajoutez systématiquement des résultats d’outils à chaque conversation, vous aurez des problèmes : quand Claude répond à une question simple comme « Combien font 1+1 ? », il n’a besoin d’aucun outil — et un code qui tente quand même de traiter des résultats d’outils ajoutera des messages vides à l’historique, cassant l’alternance des rôles au passage.
La solution : vérifier le stop_reason de chaque réponse de Claude, et laisser cette information piloter la suite.
Raisons d’arrêt
Claude peut s’arrêter pour plusieurs raisons, chacune appelant un traitement différent :
| stop_reason | Signification |
|---|---|
"tool_use" | Le modèle veut appeler un outil |
"end_turn" | Le modèle a fini de générer sa réponse |
"max_tokens" | Limite de sortie atteinte |
"stop_sequence" | Séquence d’arrêt rencontrée |
Pour notre boucle, le pivot est la distinction entre les deux premières : "tool_use" signifie « la conversation n’est pas finie, il me faut un résultat », "end_turn" signifie « voilà ma réponse ».
Améliorer la fonction chat
Pour piloter la boucle, la fonction chat doit remonter toutes les informations nécessaires — renvoyez un dictionnaire :
def chat(messages, tools=None, system=None, **kwargs):
# ... code existant ...
return {
"parts": parts,
"stop_reason": response["stopReason"],
"text": "\n".join([p["text"] for p in parts if "text" in p])
}
Trois clés, trois usages : parts porte la réponse brute (parties texte et ToolUse) à archiver dans l’historique, stop_reason pilote la décision de boucler, et text agrège les parties textuelles pour l’affichage. Cette signature enrichie servira dans tout le reste du cours.
Construire une boucle conversationnelle
def run_conversation(messages):
while True:
result = chat(messages, tools=[get_current_datetime_schema])
add_assistant_message(messages, result["parts"])
print(result["text"])
if result["stop_reason"] != "tool_use":
break
tool_result_parts = run_tools(result["parts"])
add_user_message(messages, tool_result_parts)
return messages
Cette boucle continue tant que Claude demande des outils. À chaque itération :
- Envoyer les messages actuels à Claude
- Ajouter la réponse de Claude à l’historique
- Vérifier si Claude veut utiliser un outil
- Si oui : exécuter les outils et ajouter les résultats à la conversation
- Si non : sortir de la boucle
Notez l’ordre des opérations : la réponse est archivée avant le test de sortie — l’historique reste intègre quel que soit le chemin. Et la boucle ne borne pas le nombre de tours : Claude peut enchaîner deux, trois appels d’outils successifs, chacun nourri du résultat précédent — c’est précisément ce qui permettra les workflows où un calcul dépend d’un autre.
Tester l’implémentation
# Question nécessitant un outil
messages = []
add_user_message(messages, "Quelle heure est-il ?")
run_conversation(messages)
# Question simple
messages = []
add_user_message(messages, "Combien font 1+1 ?")
run_conversation(messages)
Pour la question sur l’heure, Claude utilisera l’outil datetime — un tour d’outil, puis la réponse. Pour le calcul, il répond directement — la boucle sort dès la première itération. Aucun des deux cas n’a demandé de traitement spécial : la boucle s’adapte automatiquement selon la raison d’arrêt de Claude.
Ce pattern se généralise bien quand vous ajoutez plus d’outils — la même boucle gère n’importe quelle combinaison d’utilisations d’outils et de réponses directes. C’est la dernière pièce d’infrastructure du Tool Use : à partir d’ici, étendre le système ne touchera plus jamais ce moteur.
Points clés à retenir
- Le
stop_reasonpilote la boucle :"tool_use"= continuer,"end_turn"= réponse finale chatrenvoie un dictionnaire (parts, stop_reason, text) — la signature qui servira tout le cours- Archivez la réponse avant le test de sortie : l’historique reste intègre sur tous les chemins
- La boucle non bornée autorise les enchaînements d’outils dépendants, sans code supplémentaire
- Une seule boucle pour tous les cas : questions simples, un outil, ou séquences complexes