Cuando realizas una solicitud a la API de Mensajes, la respuesta de Claude incluye un campo stop_reason que indica por qué el modelo dejó de generar su respuesta. Comprender estos valores es crucial para construir aplicaciones robustas que manejen diferentes tipos de respuestas de manera apropiada.
Para obtener detalles sobre stop_reason en la respuesta de la API, consulta la referencia de la API de Mensajes.
El campo stop_reason es parte de cada respuesta exitosa de la API de Mensajes. A diferencia de los errores, que indican fallos en el procesamiento de tu solicitud, stop_reason te indica por qué Claude completó exitosamente la generación de su respuesta.
{
"id": "msg_01234",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "Aquí está la respuesta a tu pregunta..."
}
],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 100,
"output_tokens": 50
}
}La razón de parada más común. Indica que Claude terminó su respuesta de manera natural.
if response.stop_reason == "end_turn":
# Procesar la respuesta completa
print(response.content[0].text)A veces Claude devuelve una respuesta vacía (exactamente 2-3 tokens sin contenido) con stop_reason: "end_turn". Esto típicamente sucede cuando Claude interpreta que el turno del asistente está completo, particularmente después de resultados de herramientas.
Causas comunes:
Cómo prevenir respuestas vacías:
# INCORRECTO: Agregar texto inmediatamente después de tool_result
messages = [
{"role": "user", "content": "Calcula la suma de 1234 y 5678"},
{"role": "assistant", "content": [
{
"type": "tool_use",
"id": "toolu_123",
"name": "calculator",
"input": {"operation": "add", "a": 1234, "b": 5678}
}
]},
{"role": "user", "content": [
{
"type": "tool_result",
"tool_use_id": "toolu_123",
"content": "6912"
},
{
"type": "text",
"text": "Aquí está el resultado" # No agregues texto después de tool_result
}
]}
]
# CORRECTO: Enviar resultados de herramientas directamente sin texto adicional
messages = [
{"role": "user", "content": "Calcula la suma de 1234 y 5678"},
{"role": "assistant", "content": [
{
"type": "tool_use",
"id": "toolu_123",
"name": "calculator",
"input": {"operation": "add", "a": 1234, "b": 5678}
}
]},
{"role": "user", "content": [
{
"type": "tool_result",
"tool_use_id": "toolu_123",
"content": "6912"
}
]} # Solo el tool_result, sin texto adicional
]
# Si aún obtienes respuestas vacías después de corregir lo anterior:
def handle_empty_response(client, messages):
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
messages=messages
)
# Verificar si la respuesta está vacía
if (response.stop_reason == "end_turn" and
not response.content):
# INCORRECTO: No simplemente reintentar con la respuesta vacía
# Esto no funcionará porque Claude ya decidió que está hecho
# CORRECTO: Agregar un mensaje de continuación en un NUEVO mensaje de usuario
messages.append({"role": "user", "content": "Por favor continúa"})
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
messages=messages
)
return responseMejores prácticas:
Claude se detuvo porque alcanzó el límite de max_tokens especificado en tu solicitud.
# Solicitud con tokens limitados
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=10,
messages=[{"role": "user", "content": "Explica la física cuántica"}]
)
if response.stop_reason == "max_tokens":
# La respuesta fue truncada
print("La respuesta fue cortada en el límite de tokens")
# Considera hacer otra solicitud para continuarClaude encontró una de tus secuencias de parada personalizadas.
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
stop_sequences=["END", "STOP"],
messages=[{"role": "user", "content": "Genera texto hasta que digas END"}]
)
if response.stop_reason == "stop_sequence":
print(f"Parado en la secuencia: {response.stop_sequence}")Claude está llamando a una herramienta y espera que la ejecutes.
Para la mayoría de implementaciones de uso de herramientas, recomendamos usar el ejecutor de herramientas que maneja automáticamente la ejecución de herramientas, el formato de resultados y la gestión de conversaciones.
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
tools=[weather_tool],
messages=[{"role": "user", "content": "¿Cuál es el clima?"}]
)
if response.stop_reason == "tool_use":
# Extraer y ejecutar la herramienta
for content in response.content:
if content.type == "tool_use":
result = execute_tool(content.name, content.input)
# Devolver resultado a Claude para la respuesta finalSe utiliza con herramientas de servidor como búsqueda web cuando Claude necesita pausar una operación de larga duración.
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
tools=[{"type": "web_search_20250305", "name": "web_search"}],
messages=[{"role": "user", "content": "Busca las últimas noticias de IA"}]
)
if response.stop_reason == "pause_turn":
# Continuar la conversación
messages = [
{"role": "user", "content": original_query},
{"role": "assistant", "content": response.content}
]
continuation = client.messages.create(
model="claude-opus-4-6",
messages=messages,
tools=[{"type": "web_search_20250305", "name": "web_search"}]
)Claude se negó a generar una respuesta debido a preocupaciones de seguridad.
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "[Solicitud insegura]"}]
)
if response.stop_reason == "refusal":
# Claude se negó a responder
print("Claude no pudo procesar esta solicitud")
# Considera reformular o modificar la solicitudSi encuentras razones de parada refusal frecuentemente mientras usas Claude Sonnet 4.5 u Opus 4.1, puedes intentar actualizar tus llamadas de API para usar Sonnet 4 (claude-sonnet-4-20250514), que tiene restricciones de uso diferentes. Aprende más sobre entender los filtros de seguridad de API de Sonnet 4.5.
Para aprender más sobre rechazos desencadenados por filtros de seguridad de API para Claude Sonnet 4.5, consulta Entender los Filtros de Seguridad de API de Sonnet 4.5.
Claude se detuvo porque alcanzó el límite de la ventana de contexto del modelo. Esto te permite solicitar el máximo de tokens posibles sin conocer el tamaño exacto de la entrada.
# Solicitud con tokens máximos para obtener la mayor cantidad posible
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=64000, # Tokens de salida máximos del modelo
messages=[{"role": "user", "content": "Entrada grande que usa la mayoría de la ventana de contexto..."}]
)
if response.stop_reason == "model_context_window_exceeded":
# La respuesta alcanzó el límite de la ventana de contexto antes de max_tokens
print("La respuesta alcanzó el límite de la ventana de contexto del modelo")
# La respuesta sigue siendo válida pero fue limitada por la ventana de contextoEsta razón de parada está disponible por defecto en Sonnet 4.5 y modelos más nuevos. Para modelos anteriores, usa el encabezado beta model-context-window-exceeded-2025-08-26 para habilitar este comportamiento.
Acostúmbrate a verificar el stop_reason en tu lógica de manejo de respuestas:
def handle_response(response):
if response.stop_reason == "tool_use":
return handle_tool_use(response)
elif response.stop_reason == "max_tokens":
return handle_truncation(response)
elif response.stop_reason == "model_context_window_exceeded":
return handle_context_limit(response)
elif response.stop_reason == "pause_turn":
return handle_pause(response)
elif response.stop_reason == "refusal":
return handle_refusal(response)
else:
# Manejar end_turn y otros casos
return response.content[0].textCuando una respuesta se trunca debido a límites de tokens o ventana de contexto:
def handle_truncated_response(response):
if response.stop_reason in ["max_tokens", "model_context_window_exceeded"]:
# Opción 1: Advertir al usuario sobre el límite específico
if response.stop_reason == "max_tokens":
message = "[Respuesta truncada debido al límite de max_tokens]"
else:
message = "[Respuesta truncada debido al límite de la ventana de contexto]"
return f"{response.content[0].text}\n\n{message}"
# Opción 2: Continuar la generación
messages = [
{"role": "user", "content": original_prompt},
{"role": "assistant", "content": response.content[0].text}
]
continuation = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
messages=messages + [{"role": "user", "content": "Por favor continúa"}]
)
return response.content[0].text + continuation.content[0].textPara herramientas de servidor que pueden pausarse:
def handle_paused_conversation(initial_response, max_retries=3):
response = initial_response
messages = [{"role": "user", "content": original_query}]
for attempt in range(max_retries):
if response.stop_reason != "pause_turn":
break
messages.append({"role": "assistant", "content": response.content})
response = client.messages.create(
model="claude-opus-4-6",
messages=messages,
tools=original_tools
)
return responseEs importante distinguir entre valores de stop_reason y errores reales:
try:
response = client.messages.create(...)
# Manejar respuesta exitosa con stop_reason
if response.stop_reason == "max_tokens":
print("La respuesta fue truncada")
except anthropic.APIError as e:
# Manejar errores reales
if e.status_code == 429:
print("Límite de velocidad excedido")
elif e.status_code == 500:
print("Error del servidor")Cuando se usa streaming, stop_reason es:
null en el evento inicial message_startmessage_deltawith client.messages.stream(...) as stream:
for event in stream:
if event.type == "message_delta":
stop_reason = event.delta.stop_reason
if stop_reason:
print(f"El stream terminó con: {stop_reason}")Más simple con ejecutor de herramientas: El ejemplo a continuación muestra manejo manual de herramientas. Para la mayoría de casos de uso, el ejecutor de herramientas maneja automáticamente la ejecución de herramientas con mucho menos código.
def complete_tool_workflow(client, user_query, tools):
messages = [{"role": "user", "content": user_query}]
while True:
response = client.messages.create(
model="claude-opus-4-6",
messages=messages,
tools=tools
)
if response.stop_reason == "tool_use":
# Ejecutar herramientas y continuar
tool_results = execute_tools(response.content)
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
else:
# Respuesta final
return responsedef get_complete_response(client, prompt, max_attempts=3):
messages = [{"role": "user", "content": prompt}]
full_response = ""
for _ in range(max_attempts):
response = client.messages.create(
model="claude-opus-4-6",
messages=messages,
max_tokens=4096
)
full_response += response.content[0].text
if response.stop_reason != "max_tokens":
break
# Continuar desde donde se quedó
messages = [
{"role": "user", "content": prompt},
{"role": "assistant", "content": full_response},
{"role": "user", "content": "Por favor continúa desde donde te quedaste."}
]
return full_responseCon la razón de parada model_context_window_exceeded, puedes solicitar el máximo de tokens posibles sin calcular el conteo de tokens de entrada:
def get_max_possible_tokens(client, prompt):
"""
Obtener la mayor cantidad de tokens posibles dentro de la ventana de contexto del modelo
sin necesidad de calcular el conteo de tokens de entrada
"""
response = client.messages.create(
model="claude-opus-4-6",
messages=[{"role": "user", "content": prompt}],
max_tokens=64000 # Establecer a los tokens de salida máximos del modelo
)
if response.stop_reason == "model_context_window_exceeded":
# Obtuviste el máximo de tokens posibles dado el tamaño de entrada
print(f"Se generaron {response.usage.output_tokens} tokens (límite de contexto alcanzado)")
elif response.stop_reason == "max_tokens":
# Obtuviste exactamente los tokens solicitados
print(f"Se generaron {response.usage.output_tokens} tokens (max_tokens alcanzado)")
else:
# Finalización natural
print(f"Se generaron {response.usage.output_tokens} tokens (finalización natural)")
return response.content[0].textAl manejar adecuadamente los valores de stop_reason, puedes construir aplicaciones más robustas que manejen elegantemente diferentes escenarios de respuesta y proporcionen mejores experiencias de usuario.
Was this page helpful?