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 recorrer a outro modelo.
Para o esquema completo da resposta, consulte a referência da Messages API.
| Valor | Quando ocorre | O que fazer |
|---|---|---|
end_turn | Claude finalizou 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 de erros, que indicam falhas no processamento da sua requisiçã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 finalizou sua resposta naturalmente.
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
)
if response.stop_reason == "end_turn":
# Processa a resposta completa
print(response.content[0].text)Claude parou porque atingiu o limite de max_tokens especificado em sua requisição.
client = anthropic.Anthropic()
# Requisição com tokens limitados
response = client.messages.create(
model="claude-opus-4-8",
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-4-8",
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-4-8",
max_tokens=1024,
tools=[weather_tool],
messages=[{"role": "user", "content": "What is the weather in San Francisco?"}],
)
if response.stop_reason == "tool_use":
# Extrair e executar a ferramenta
for block in response.content:
if block.type == "tool_use":
result = execute_tool(block.name, block.input)
# Retornar o resultado ao Claude para 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á finalizada, e essa 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 de cliente vem de código que está sendo executado na ferramenta code_execution em vez de diretamente de Claude, e seu campo caller nomeia o bloco code_execution que o chamou. Esse código já foi iniciado: 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 assim que o código termina, o que pode levar mais de uma rodada de resultados de ferramentas. A mensagem de usuário de continuação em si é a mesma em ambos os casos; com chamada programática de ferramentas, passe também de volta o id do campo container da resposta, como aquela página mostra.
{
"stop_reason": "tool_use",
"content": [
{
"type": "server_tool_use",
"id": "srvtoolu_01HxbWnMRmbWyMfUtJKC45rA",
"name": "web_fetch",
"input": { "url": "https://example.com/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 requisição deve manter o mesmo array tools. Uma requisição de retomada que não define mais a ferramenta de servidor em espera falha com um erro 400 cuja mensagem termina com but no `web_fetch` 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 requisição então falha com um invalid_request_error 400 que nomeia a ferramenta de servidor não resolvida:
`web_fetch` tool use with id `srvtoolu_01HxbWnMRmbWyMfUtJKC45rA` was found without a corresponding `web_fetch_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 fornecer 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 ou web fetch. O limite padrão é de 10 iterações por requisiçã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 por você nunca tem um stop_reason de pause_turn: quando Claude para para chamar suas ferramentas, stop_reason é tool_use, e você continua enviando os blocos tool_result de cliente em vez da própria resposta.
response = client.messages.create(
model="claude-opus-4-8",
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-4-8",
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 requisição à API para permitir que Claude continue.
Claude se recusou a gerar uma resposta. No Claude Fable 5, classificadores de segurança retornam esse motivo de parada como uma resposta HTTP 200 normal, não como um erro.
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
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), 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 diferentes de refusal.
Uma requisição recusada no Claude Fable 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 em 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 de tokens possível sem saber o tamanho exato da entrada.
Esse motivo de parada atualmente está 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 em 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 máximo de tokens para obter o máximo possível
response = client.beta.messages.create(
model="claude-opus-4-8",
max_tokens=20000, # Python SDK requires streaming for max_tokens above ~21k (Opus 4.8 supports 128k with streaming)
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:
# Lidar com end_turn e outros casos
return response.content[0].textQuando uma resposta é truncada devido a limites de tokens ou à 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):
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"{response.content[0].text}\n\n{note}"
return response.content[0].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-4-8", 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 a alternância de papéis
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-4-8",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
)
# Trata resposta bem-sucedida com stop_reason
if response.stop_reason == "max_tokens":
print("Response was truncated")
except anthropic.APIStatusError as e:
# Trata 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-4-8",
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-4-8", max_tokens=1024, messages=messages, tools=tools
)
if response.stop_reason == "tool_use":
# Executar ferramentas e continuar
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-4-8", messages=messages, max_tokens=4096
)
full_response += response.content[0].text
if response.stop_reason != "max_tokens":
break
# Continuar 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 de tokens possível 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-4-8",
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 possível de tokens 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 response.content[0].textTente novamente requisições recusadas em um modelo de fallback, no lado do servidor ou em seu cliente.
Deixe o SDK gerenciar o loop de tool_use, a formatação de resultados e as novas tentativas por 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?