Construir un sistema de conversación con herramientas requiere implementar un bucle que siga llamando a Claude hasta que deje de solicitar el uso de herramientas. Cuando Claude ya no solicita herramientas, eso indica que tiene una respuesta final lista para el usuario.
Detectando solicitudes de herramientas
La clave para saber si Claude quiere usar una herramienta está en el campo stop_reason del mensaje de respuesta. Cuando Claude decide que necesita llamar a una herramienta, este campo se establece en "tool_use". Esto nos da una forma clara de verificar si necesitamos continuar el bucle de conversación:
if response.stop_reason != "tool_use":
break # Claude is done, no more tools neededEl bucle de conversación
La función principal de conversación sigue un patrón 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 messagesEste bucle continúa hasta que Claude proporciona una respuesta final sin solicitar ninguna herramienta.
Manejo de múltiples llamadas a herramientas
Claude puede solicitar múltiples herramientas en una sola respuesta. El contenido del mensaje contiene una lista de bloques, y necesitamos procesar cada bloque de uso de herramienta por separado:

La función run_tools maneja esto filtrando los bloques de uso de herramienta y procesando cada uno:
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:
# Process each tool request...Bloques de resultado de herramienta
Para cada bloque de uso de herramienta, necesitamos crear un bloque de resultado de herramienta correspondiente. Estos bloques tienen campos específicos requeridos:

El bloque de resultado de herramienta debe incluir el mismo ID que el bloque de uso de herramienta original, pero en el campo tool_use_id:
tool_result_block = {
"type": "tool_result",
"tool_use_id": tool_request.id,
"content": json.dumps(tool_output),
"is_error": False
}Manejo de errores
La ejecución robusta de herramientas requiere manejar posibles errores. Cuando una herramienta falla, aún necesitamos devolver un bloque de resultado de herramienta, pero con información de error:
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
}Enrutamiento escalable de herramientas
Para admitir múltiples herramientas, crea una función de enrutamiento separada en lugar de codificar los nombres de las herramientas directamente:
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)
# Agrega más herramientas según sea necesarioEste enfoque facilita agregar nuevas herramientas sin modificar la lógica central de conversación.
Flujo de trabajo completo
La conversación completa de múltiples turnos funciona así:
- Enviar el mensaje del usuario a Claude con las herramientas disponibles
- Claude responde con texto y/o bloques de uso de herramienta
- Ejecutar las herramientas solicitadas y crear bloques de resultado de herramienta
- Enviar los resultados de las herramientas de vuelta a Claude como un mensaje de usuario
- Repetir hasta que Claude proporcione una respuesta final sin solicitudes de herramientas
Esto crea una experiencia fluida donde Claude puede realizar múltiples llamadas a herramientas a lo largo de varios turnos de conversación para recopilar toda la información necesaria antes de proporcionar una respuesta final completa al usuario.