Toda resposta da Messages API inclui um campo stop_reason que informa por que Claude parou de gerar. Verifique esse campo para decidir se deve usar a resposta como está, continuar a conversa, tentar novamente ou fazer fallback para outro modelo.
Para o esquema completo da resposta, consulte a referência da Messages API.
| Valor | Quando ocorre | O que fazer |
|---|---|---|
end_turn | Claude terminou sua resposta naturalmente. | Use a resposta. |
max_tokens | A resposta atingiu seu limite de max_tokens. | Aumente max_tokens ou continue a resposta. |
stop_sequence | Claude emitiu uma de suas stop_sequences. | Leia stop_sequence para ver qual foi acionada. |
tool_use | Claude está chamando uma ferramenta. | Execute a ferramenta e retorne o resultado. Uma chamada de ferramenta de servidor que ainda não tem seu bloco de resultado é concluída em uma resposta posterior. |
pause_turn | Um loop de ferramenta de servidor atingiu seu limite de iterações. | Envie o conteúdo do assistente de volta para continuar. |
refusal | Claude se recusou a responder. | Leia stop_details e tente novamente em um modelo de fallback. |
model_context_window_exceeded | A resposta preencheu a janela de contexto do modelo. | Trate a resposta como truncada. |
O campo stop_reason faz parte de toda resposta bem-sucedida da Messages API. Diferentemente dos erros, que indicam falhas no processamento da sua solicitação, stop_reason informa por que Claude concluiu a geração de sua resposta.
{
"id": "msg_01234",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "Here's the answer to your question..."
}
],
"stop_reason": "end_turn",
"stop_sequence": null,
"stop_details": null,
"usage": {
"input_tokens": 100,
"output_tokens": 50
}
}O motivo de parada mais comum. Indica que Claude terminou sua resposta naturalmente.
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
)
if response.stop_reason == "end_turn":
# Processa a resposta completa
for block in response.content:
if block.type == "text":
print(block.text)Claude parou porque atingiu o limite de max_tokens especificado em sua solicitação.
client = anthropic.Anthropic()
# Requisição com tokens limitados
response = client.messages.create(
model="claude-opus-5",
max_tokens=10,
messages=[{"role": "user", "content": "Explain quantum physics"}],
)
if response.stop_reason == "max_tokens":
# A resposta foi truncada
print("Response was cut off at token limit")
# Considere fazer outra requisição para continuarClaude encontrou uma de suas sequências de parada personalizadas.
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
stop_sequences=["END", "STOP"],
messages=[{"role": "user", "content": "Generate text until you say END"}],
)
if response.stop_reason == "stop_sequence":
print(f"Stopped at sequence: {response.stop_sequence}")Claude está chamando uma ferramenta e espera que você a execute.
Para a maioria das implementações de uso de ferramentas, use o tool runner, que lida automaticamente com a execução de ferramentas, formatação de resultados e gerenciamento de conversas.
client = anthropic.Anthropic()
weather_tool = {
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City and state"},
},
"required": ["location"],
},
}
def execute_tool(name, tool_input):
"""Execute a tool and return the result."""
return f"Weather in {tool_input.get('location', 'unknown')}: 72°F"
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
tools=[weather_tool],
messages=[{"role": "user", "content": "What is the weather in San Francisco?"}],
)
if response.stop_reason == "tool_use":
# Extrai e executa a ferramenta
for block in response.content:
if block.type == "tool_use":
result = execute_tool(block.name, block.input)
# Retorna o resultado para Claude gerar a resposta finalUma resposta tool_use também pode conter um bloco server_tool_use cujo id não tem um bloco de resultado correspondente. Essa chamada de ferramenta de servidor não está concluída, e esta resposta não carrega seu resultado. No caso comum, Claude chama uma ferramenta de servidor e uma de suas ferramentas de cliente no mesmo grupo de chamadas de ferramentas paralelas: a API retorna sem executar a ferramenta de servidor para que você possa executar as ferramentas de cliente primeiro. Não há outro marcador para esse estado; detecte-o verificando o id de cada bloco server_tool_use ou mcp_tool_use em busca de um bloco de resultado correspondente.
Com chamada programática de ferramentas, o mesmo formato de resposta significa algo diferente. O bloco tool_use do cliente vem de código que está sendo executado na ferramenta code_execution em vez de vir diretamente de Claude, e seu campo caller nomeia o bloco code_execution que o chamou. Esse código já começou: ele está pausado aguardando seus blocos tool_result, e enviá-los retoma a execução em vez de iniciar uma ferramenta adiada. O próprio bloco de resultado do bloco code_execution chega quando o código termina, o que pode levar mais de uma rodada de resultados de ferramentas. A mensagem de usuário de acompanhamento em si é a mesma em ambos os casos; com chamada programática de ferramentas, também passe de volta o id do campo container da resposta, como essa página mostra.
{
"stop_reason": "tool_use",
"content": [
{
"type": "server_tool_use",
"id": "srvtoolu_01HxbWnMRmbWyMfUtJKC45rA",
"name": "web_search",
"input": { "query": "example article" }
},
{
"type": "tool_use",
"id": "toolu_01PjgRJLbXrXEMZwDNYLnBqk",
"name": "run_command",
"input": { "command": "uname -a" }
}
]
}A continuação é uma mensagem de usuário com blocos tool_result, um para cada bloco tool_use na resposta (consulte Lidar com chamadas de ferramentas), com duas regras extras: essa mensagem não deve conter nada além dos blocos tool_result, e a solicitação deve manter o mesmo array tools. Uma solicitação de retomada que não define mais a ferramenta de servidor em espera falha com um 400 cuja mensagem termina com but no `web_search` tool was provided. A API anexa seus resultados ao turno do assistente ainda aberto, executa a ferramenta de servidor adiada (para execução de código pausada, a retoma) e continua o turno. Para uma ferramenta de servidor que Claude chamou diretamente, o content da próxima resposta começa com o bloco de resultado que responde ao id do server_tool_use da resposta anterior.
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01PjgRJLbXrXEMZwDNYLnBqk",
"content": "Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux"
}
]
}Adicionar qualquer coisa após os blocos tool_result nessa mensagem de usuário, como texto, encerra o turno do assistente; para uma ferramenta de servidor que Claude chamou diretamente, a solicitação então falha com um 400 invalid_request_error que nomeia a ferramenta de servidor não resolvida:
`web_search` tool use with id `srvtoolu_01HxbWnMRmbWyMfUtJKC45rA` was found without a corresponding `web_search_tool_result` blockOmitir um tool_result, ou colocar um após outro conteúdo, falha antes com o erro padrão tool_use ids were found without tool_result blocks immediately after. Para dar mais entrada a Claude, envie-a como uma mensagem de usuário separada após o turno ser concluído.
Retornado quando o loop de amostragem do lado do servidor atinge seu limite de iterações ao executar ferramentas de servidor, como busca na web. O limite padrão é de 10 iterações por solicitação.
Quando isso acontece, a resposta pode conter um bloco server_tool_use sem um bloco de resultado correspondente. Para permitir que Claude termine o processamento, continue a conversa enviando a resposta de volta como está. Uma resposta que deixa um bloco tool_use de cliente aguardando você nunca tem um stop_reason de pause_turn: quando Claude para para chamar suas ferramentas, stop_reason é tool_use, e você o continua enviando os blocos tool_result do cliente em vez da própria resposta.
response = client.messages.create(
model="claude-opus-5",
max_tokens=4096,
tools=[{"type": "web_search_20250305", "name": "web_search"}],
messages=[{"role": "user", "content": "Search for latest AI news"}],
)
if response.stop_reason == "pause_turn":
# Continue a conversa enviando a resposta de volta
messages = [
{"role": "user", "content": "Search for latest AI news"},
{"role": "assistant", "content": response.content},
]
continuation = client.messages.create(
model="claude-opus-5",
max_tokens=4096,
messages=messages,
tools=[{"type": "web_search_20250305", "name": "web_search"}],
)Sua aplicação deve lidar com pause_turn em qualquer loop de agente que use ferramentas de servidor. Adicione a resposta do assistente ao seu array de mensagens e faça outra solicitação à API para permitir que Claude continue.
Claude se recusou a gerar uma resposta. Classificadores de segurança retornam esse motivo de parada como uma resposta HTTP 200 normal, não um erro.
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
messages=[{"role": "user", "content": "[Unsafe request]"}],
)
if response.stop_reason == "refusal":
# Claude se recusou a responder
print("Claude was unable to process this request")
# Considere reformular ou modificar a solicitaçãoSe você encontrar motivos de parada refusal com frequência ao usar Claude Sonnet 4.5 ou Opus 4.1 (descontinuado; consulte Descontinuações de modelos), você pode tentar atualizar suas chamadas de API para usar Haiku 4.5 (claude-haiku-4-5-20251001), que tem restrições de uso diferentes. Saiba mais sobre como entender os filtros de segurança da API do Sonnet 4.5.
Em uma recusa, o objeto stop_details identifica a categoria de política que a acionou. As categorias e o formato completo da resposta de recusa são abordados em Recusas e fallback. stop_details é null para todos os motivos de parada que não sejam refusal.
Uma solicitação recusada no Claude Fable 5 ou Claude Opus 5 geralmente pode ser atendida tentando novamente em outro modelo Claude, e Recusas e fallback mostra como configurar essa nova tentativa, no lado do servidor ou no seu cliente. Crédito de fallback aborda como evitar pagar o custo do cache de prompt duas vezes quando você mesmo constrói a nova tentativa.
Claude parou porque atingiu o limite da janela de contexto do modelo. Isso permite que você solicite o máximo possível de tokens sem saber o tamanho exato da entrada.
Este motivo de parada está atualmente tipado apenas no namespace beta dos SDKs, então os exemplos a seguir chamam client.beta.messages e usam os tipos com prefixo Beta. No Sonnet 4.5 e modelos mais recentes, a API retorna esse valor sem um cabeçalho beta. Para modelos anteriores, adicione o cabeçalho beta model-context-window-exceeded-2025-08-26 para habilitá-lo.
# Requisição com o máximo de tokens para obter o máximo possível
response = client.beta.messages.create(
model="claude-opus-5",
max_tokens=20000, # Python SDK requires streaming for max_tokens above ~21k
messages=[
{"role": "user", "content": "Large input that uses most of context window..."}
],
)
if response.stop_reason == "model_context_window_exceeded":
# A resposta atingiu o limite da janela de contexto antes de max_tokens
print("Response reached model's context window limit")
# A resposta ainda é válida, mas foi limitada pela janela de contextoCrie o hábito de verificar o stop_reason em sua lógica de tratamento de respostas:
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:
# Lida com end_turn e outros casos
return next(
(block.text for block in response.content if block.type == "text"), ""
)Quando uma resposta é truncada por causa de limites de tokens ou da janela de contexto, anexe um aviso para que o leitor saiba que a saída está incompleta. Para continuar gerando de onde a resposta parou, consulte Garantindo respostas completas.
def handle_truncated_response(response):
text = next((block.text for block in response.content if block.type == "text"), "")
if response.stop_reason in ["max_tokens", "model_context_window_exceeded"]:
if response.stop_reason == "max_tokens":
note = "[Response truncated due to max_tokens limit]"
else:
note = "[Response truncated due to context window limit]"
return f"{text}\n\n{note}"
return textAo usar ferramentas de servidor, a API pode retornar pause_turn se o loop de amostragem do lado do servidor atingir seu limite de iterações (padrão 10). Lide com isso continuando a conversa:
def handle_server_tool_conversation(client, user_query, tools, max_continuations=5):
"""
Handle server tool conversations that may require multiple continuations.
The server runs a sampling loop when executing server tools. If the loop
reaches its iteration limit, the API returns pause_turn. Continue the
conversation by sending the response back to let Claude finish.
"""
messages = [{"role": "user", "content": user_query}]
for _ in range(max_continuations):
response = client.messages.create(
model="claude-opus-5", max_tokens=4096, messages=messages, tools=tools
)
if response.stop_reason != "pause_turn":
# Claude terminou o processamento - retorna a resposta final
return response
# pause_turn: substitui a lista completa de mensagens para manter os papéis alternados
messages = [
{"role": "user", "content": user_query},
{"role": "assistant", "content": response.content},
]
# Atingiu o máximo de continuações - retorna a última resposta
return responseÉ importante distinguir entre valores de stop_reason e erros reais:
client = anthropic.Anthropic()
try:
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
)
# Trata a resposta bem-sucedida com stop_reason
if response.stop_reason == "max_tokens":
print("Response was truncated")
except anthropic.APIStatusError as e:
# Trata os erros reais
if e.status_code == 429:
print("Rate limit exceeded")
elif e.status_code == 500:
print("Server error")Ao usar streaming, stop_reason é:
null no evento inicial message_startmessage_deltaclient = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
) as stream:
for event in stream:
if event.type == "message_delta":
stop_reason = event.delta.stop_reason
if stop_reason:
print(f"Stream ended with: {stop_reason}")Mais simples com o tool runner: O exemplo a seguir mostra o tratamento manual de ferramentas. Para a maioria dos casos de uso, o tool runner lida automaticamente com a execução de ferramentas com muito 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-5", max_tokens=1024, messages=messages, tools=tools
)
if response.stop_reason == "tool_use":
# Execute as ferramentas e continue
tool_results = execute_tools(response.content)
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
else:
# Resposta 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-5", messages=messages, max_tokens=4096
)
full_response += next(
(block.text for block in response.content if block.type == "text"), ""
)
if response.stop_reason != "max_tokens":
break
# Continue de onde parou
messages = [
{"role": "user", "content": prompt},
{"role": "assistant", "content": full_response},
{"role": "user", "content": "Please continue from where you left off."},
]
return full_responseCom o motivo de parada model_context_window_exceeded, você pode solicitar o máximo possível de tokens sem calcular o tamanho da entrada:
def get_max_possible_tokens(client, prompt):
"""
Get as many tokens as possible within the model's context window
without needing to calculate input token count
"""
response = client.beta.messages.create(
model="claude-opus-5",
messages=[{"role": "user", "content": prompt}],
max_tokens=20000, # Python SDK requires streaming for max_tokens above ~21k
)
if response.stop_reason == "model_context_window_exceeded":
# Obteve o máximo de tokens possível dado o tamanho da entrada
print(
f"Generated {response.usage.output_tokens} tokens (context limit reached)"
)
elif response.stop_reason == "max_tokens":
# Obteve exatamente os tokens solicitados
print(f"Generated {response.usage.output_tokens} tokens (max_tokens reached)")
else:
# Conclusão natural
print(f"Generated {response.usage.output_tokens} tokens (natural completion)")
return next((block.text for block in response.content if block.type == "text"), "")Tente novamente solicitações recusadas em um modelo de fallback, no lado do servidor ou no seu cliente.
Deixe o SDK gerenciar o loop de tool_use, a formatação de resultados e as novas tentativas para você.
Leia stop_reason do evento message_delta ao usar streaming.
Lide com erros HTTP 4xx e 5xx, que são distintos dos motivos de parada.
Was this page helpful?