当您向 Messages API 发送请求时,Claude 的响应包含一个 stop_reason 字段,指示模型为何停止生成其响应。理解这些值对于构建能适当处理不同响应类型的健壮应用程序至关重要。

有关 API 响应中 stop_reason 的详细信息,请参阅 Messages API 参考

什么是 stop_reason?

stop_reason 字段是每个成功的 Messages API 响应的一部分。与表示请求处理失败的错误不同,stop_reason 告诉您 Claude 为何成功完成了其响应生成。

示例响应
{
  "id": "msg_01234",
  "type": "message",
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "这是您问题的答案..."
    }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 100,
    "output_tokens": 50
  }
}

停止原因值

end_turn

最常见的停止原因。表示 Claude 自然地完成了其响应。

if response.stop_reason == "end_turn":
    # 处理完整响应
    print(response.content[0].text)

max_tokens

Claude 停止是因为达到了您请求中指定的 max_tokens 限制。

# 带有限制令牌的请求
response = client.messages.create(
    model="claude-3-7-sonnet-20250219",
    max_tokens=10,
    messages=[{"role": "user", "content": "解释量子物理学"}]
)

if response.stop_reason == "max_tokens":
    # 响应被截断
    print("响应在令牌限制处被截断")
    # 考虑发出另一个请求以继续

stop_sequence

Claude 遇到了您的自定义停止序列之一。

response = client.messages.create(
    model="claude-3-7-sonnet-20250219",
    max_tokens=1024,
    stop_sequences=["END", "STOP"],
    messages=[{"role": "user", "content": "生成文本直到你说END"}]
)

if response.stop_reason == "stop_sequence":
    print(f"在序列处停止: {response.stop_sequence}")

tool_use

Claude 正在调用工具并期望您执行它。

response = client.messages.create(
    model="claude-3-7-sonnet-20250219",
    max_tokens=1024,
    tools=[weather_tool],
    messages=[{"role": "user", "content": "天气怎么样?"}]
)

if response.stop_reason == "tool_use":
    # 提取并执行工具
    for content in response.content:
        if content.type == "tool_use":
            result = execute_tool(content.name, content.input)
            # 将结果返回给Claude以获取最终响应

pause_turn

在 Claude 需要暂停长时间运行的操作时,与网络搜索等服务器工具一起使用。

response = client.messages.create(
    model="claude-3-7-sonnet-20250219",
    max_tokens=1024,
    tools=[{"type": "web_search_20250305", "name": "web_search"}],
    messages=[{"role": "user", "content": "搜索最新的AI新闻"}]
)

if response.stop_reason == "pause_turn":
    # 继续对话
    messages = [
        {"role": "user", "content": original_query},
        {"role": "assistant", "content": response.content}
    ]
    continuation = client.messages.create(
        model="claude-3-7-sonnet-20250219",
        messages=messages,
        tools=[{"type": "web_search_20250305", "name": "web_search"}]
    )

处理停止原因的最佳实践

1. 始终检查stop_reason

养成在响应处理逻辑中检查 stop_reason 的习惯:

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 == "pause_turn":
        return handle_pause(response)
    else:
        # 处理end_turn和其他情况
        return response.content[0].text

2. 优雅地处理max_tokens

当响应因令牌限制而被截断时:

def handle_truncated_response(response):
    if response.stop_reason == "max_tokens":
        # 选项1:警告用户
        return f"{response.content[0].text}\n\n[响应因长度而被截断]"
        
        # 选项2:继续生成
        messages = [
            {"role": "user", "content": original_prompt},
            {"role": "assistant", "content": response.content[0].text}
        ]
        continuation = client.messages.create(
            model="claude-3-7-sonnet-20250219",
            max_tokens=1024,
            messages=messages + [{"role": "user", "content": "请继续"}]
        )
        return response.content[0].text + continuation.content[0].text

3. 为pause_turn实现重试逻辑

对于可能暂停的服务器工具:

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-3-7-sonnet-20250219",
            messages=messages,
            tools=original_tools
        )
    
    return response

停止原因与错误的区别

区分 stop_reason 值和实际错误很重要:

停止原因(成功的响应)

  • 响应体的一部分
  • 指示为何正常停止生成
  • 响应包含有效内容

错误(请求失败)

  • HTTP状态码4xx或5xx
  • 表示请求处理失败
  • 响应包含错误详情
try:
    response = client.messages.create(...)
    
    # 处理带有stop_reason的成功响应
    if response.stop_reason == "max_tokens":
        print("响应被截断")
    
except anthropic.APIError as e:
    # 处理实际错误
    if e.status_code == 429:
        print("超出速率限制")
    elif e.status_code == 500:
        print("服务器错误")

流式处理考虑因素

使用流式处理时,stop_reason 是:

  • 在初始 message_start 事件中为 null
  • message_delta 事件中提供
  • 在所有其他事件中为非null
with 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"流以以下原因结束: {stop_reason}")

常见模式

处理工具使用工作流

def complete_tool_workflow(client, user_query, tools):
    messages = [{"role": "user", "content": user_query}]
    
    while True:
        response = client.messages.create(
            model="claude-3-7-sonnet-20250219",
            messages=messages,
            tools=tools
        )
        
        if response.stop_reason == "tool_use":
            # 执行工具并继续
            tool_results = execute_tools(response.content)
            messages.append({"role": "assistant", "content": response.content})
            messages.append({"role": "user", "content": tool_results})
        else:
            # 最终响应
            return response

确保完整响应

def 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-3-7-sonnet-20250219",
            messages=messages,
            max_tokens=4096
        )
        
        full_response += response.content[0].text
        
        if response.stop_reason != "max_tokens":
            break
            
        # 从中断处继续
        messages = [
            {"role": "user", "content": prompt},
            {"role": "assistant", "content": full_response},
            {"role": "user", "content": "请从你中断的地方继续。"}
        ]
    
    return full_response

通过正确处理 stop_reason 值,您可以构建更加健壮的应用程序,优雅地处理不同的响应场景并提供更好的用户体验。