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

중단 이유 vs. 오류

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 값을 적절히 처리함으로써, 다양한 응답 시나리오를 우아하게 처리하고 더 나은 사용자 경험을 제공하는 더 견고한 애플리케이션을 구축할 수 있습니다.