Der Aufbau eines Konversationssystems mit Tools erfordert die Implementierung einer Schleife, die Claude so lange aufruft, bis es keine Tool-Nutzung mehr anfordert. Wenn Claude keine Tools mehr anfordert, signalisiert dies, dass eine endgültige Antwort für den Nutzer bereit ist.
Tool-Anfragen erkennen
Der Schlüssel, um zu erkennen, ob Claude ein Tool nutzen möchte, liegt im Feld stop_reason der Antwortnachricht. Wenn Claude entscheidet, dass es ein Tool aufrufen muss, wird dieses Feld auf "tool_use" gesetzt. Dies gibt uns eine saubere Möglichkeit zu prüfen, ob wir die Konversationsschleife fortsetzen müssen:
if response.stop_reason != "tool_use":
break # Claude is done, no more tools neededDie Konversationsschleife
Die Hauptfunktion der Konversation folgt einem einfachen Muster:
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 messagesDiese Schleife läuft weiter, bis Claude eine endgültige Antwort liefert, ohne weitere Tools anzufordern.
Umgang mit mehreren Tool-Aufrufen
Claude kann in einer einzigen Antwort mehrere Tools anfordern. Der Nachrichteninhalt enthält eine Liste von Blöcken, und wir müssen jeden Tool-Use-Block separat verarbeiten:

Die Funktion run_tools übernimmt dies, indem sie nach Tool-Use-Blöcken filtert und jeden einzeln verarbeitet:
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:
# Verarbeite jede Tool-Anfrage...Tool-Result-Blöcke
Jeder Tool-Use-Block muss mit einem entsprechenden Tool-Result-Block beantwortet werden. Die Verbindung zwischen ihnen wird durch übereinstimmende IDs aufrechterhalten:

Die Struktur des Tool-Result-Blocks umfasst:
tool_result_block = {
"type": "tool_result",
"tool_use_id": tool_request.id,
"content": json.dumps(tool_output),
"is_error": False
}Fehlerbehandlung
Eine robuste Tool-Ausführung erfordert die Behandlung potenzieller Fehler. Wenn ein Tool fehlschlägt, müssen wir Claude trotzdem einen Result-Block zur Verfügung stellen:
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
}Skalierbares Tool-Routing
Um mehrere Tools zu unterstützen, erstelle eine Routing-Funktion, die Tool-Namen auf ihre Implementierungen abbildet:
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)
# Füge bei Bedarf weitere Tools hinzuDieser Ansatz macht es einfach, neue Tools hinzuzufügen, ohne die Kernlogik der Konversation zu verändern.
Vollständiger Workflow
Der vollständige Multi-Turn-Konversationsablauf funktioniert wie folgt:
- Sende die Nutzernachricht mit verfügbaren Tools an Claude
- Claude antwortet mit Text und/oder Tool-Anfragen
- Führe alle angeforderten Tools aus und erstelle Result-Blöcke
- Sende die Tool-Ergebnisse als Nutzernachricht zurück
- Wiederhole dies, bis Claude eine endgültige Antwort liefert
Dies schafft ein nahtloses Erlebnis, bei dem Claude mehrere Tools über mehrere Turns hinweg nutzen kann, um komplexe Nutzeranfragen vollständig zu beantworten. Der Konversationsverlauf bewahrt den vollständigen Kontext und ermöglicht es Claude, auf vorherigen Tool-Ergebnissen aufzubauen, um umfassende Antworten zu liefern.