當您向 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 值,您可以構建更強大的應用程式,優雅地處理不同的回應場景並提供更好的用戶體驗。