Loading...
  • 빌드
  • 관리
  • 모델 및 가격
  • 클라이언트 SDK
  • API 참조
Search...
⌘K
Log in
중지 이유 처리
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...

Solutions

  • AI agents
  • Code modernization
  • Coding
  • Customer support
  • Education
  • Financial services
  • Government
  • Life sciences

Partners

  • Amazon Bedrock
  • Google Cloud's Vertex AI

Learn

  • Blog
  • Courses
  • Use cases
  • Connectors
  • Customer stories
  • Engineering at Anthropic
  • Events
  • Powered by Claude
  • Service partners
  • Startups program

Company

  • Anthropic
  • Careers
  • Economic Futures
  • Research
  • News
  • Responsible Scaling Policy
  • Security and compliance
  • Transparency

Learn

  • Blog
  • Courses
  • Use cases
  • Connectors
  • Customer stories
  • Engineering at Anthropic
  • Events
  • Powered by Claude
  • Service partners
  • Startups program

Help and security

  • Availability
  • Status
  • Support
  • Discord

Terms and policies

  • Privacy policy
  • Responsible disclosure policy
  • Terms of service: Commercial
  • Terms of service: Consumer
  • Usage policy
빌드/Claude로 구축하기

중지 이유 처리

Claude의 응답에서 stop_reason 필드를 이해하고 처리하는 방법을 알아봅니다.

Was this page helpful?

  • stop_reason 필드
  • stop_reason 값
  • end_turn
  • max_tokens
  • stop_sequence
  • tool_use
  • pause_turn
  • refusal
  • model_context_window_exceeded
  • 1. 항상 stop_reason 확인
  • 2. 잘린 응답을 우아하게 처리
  • 3. pause_turn에 대한 재시도 로직 구현

Messages API에 요청을 보낼 때, Claude의 응답에는 모델이 응답 생성을 중지한 이유를 나타내는 stop_reason 필드가 포함됩니다. 이러한 값들을 이해하는 것은 다양한 응답 유형을 적절하게 처리하는 견고한 애플리케이션을 구축하는 데 중요합니다.

API 응답의 stop_reason에 대한 자세한 내용은 Messages API 참조를 참조하세요.

stop_reason 필드

stop_reason 필드는 모든 성공적인 Messages API 응답에 포함됩니다. 요청 처리 실패를 나타내는 오류와 달리, stop_reason은 Claude가 응답 생성을 성공적으로 완료한 이유를 알려줍니다.

Example response
{
  "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,
  "usage": {
    "input_tokens": 100,
    "output_tokens": 50
  }
}

stop_reason 값

end_turn

가장 일반적인 중지 이유입니다. Claude가 응답을 자연스럽게 완료했음을 나타냅니다.

Python
from anthropic import Anthropic

client = Anthropic()
response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello!"}],
)
if response.stop_reason == "end_turn":
    # Process the complete response
    print(response.content[0].text)

end_turn과 함께 빈 응답

때때로 Claude는 stop_reason: "end_turn"과 함께 빈 응답(정확히 2-3개의 토큰이고 내용이 없음)을 반환합니다. 이는 일반적으로 Claude가 어시스턴트 턴이 완료되었다고 해석할 때, 특히 도구 결과 이후에 발생합니다.

일반적인 원인:

  • 도구 결과 직후에 텍스트 블록 추가 (Claude는 도구 결과 후 사용자가 항상 텍스트를 삽입할 것으로 예상하도록 학습하므로, 패턴을 따르기 위해 턴을 종료합니다)
  • Claude의 완료된 응답을 아무것도 추가하지 않고 다시 보내기 (Claude가 이미 완료되었다고 결정했으므로, 그대로 유지됩니다)

빈 응답 방지 방법:

# INCORRECT: Adding text immediately after tool_result
messages = [
    {"role": "user", "content": "Calculate the sum of 1234 and 5678"},
    {
        "role": "assistant",
        "content": [
            {
                "type": "tool_use",
                "id": "toolu_123",
                "name": "calculator",
                "input": {"operation": "add", "a": 1234, "b": 5678},
            }
        ],
    },
    {
        "role": "user",
        "content": [
            {"type": "tool_result", "tool_use_id": "toolu_123", "content": "6912"},
            {
                "type": "text",
                "text": "Here's the result",  # Don't add text after tool_result
            },
        ],
    },
]

# CORRECT: Send tool results directly without additional text
messages = [
    {"role": "user", "content": "Calculate the sum of 1234 and 5678"},
    {
        "role": "assistant",
        "content": [
            {
                "type": "tool_use",
                "id": "toolu_123",
                "name": "calculator",
                "input": {"operation": "add", "a": 1234, "b": 5678},
            }
        ],
    },
    {
        "role": "user",
        "content": [
            {"type": "tool_result", "tool_use_id": "toolu_123", "content": "6912"}
        ],
    },  # Just the tool_result, no additional text
]


# If you still get empty responses after fixing the above:
def handle_empty_response(client, messages):
    response = client.messages.create(
        model="claude-opus-4-7", max_tokens=1024, messages=messages
    )

    # Check if response is empty
    if response.stop_reason == "end_turn" and not response.content:
        # INCORRECT: Don't just retry with the empty response
        # This won't work because Claude already decided it's done

        # CORRECT: Add a continuation prompt in a NEW user message
        messages.append({"role": "user", "content": "Please continue"})

        response = client.messages.create(
            model="claude-opus-4-7", max_tokens=1024, messages=messages
        )

    return response

모범 사례:

  1. 도구 결과 직후에 텍스트 블록을 절대 추가하지 마세요 - 이는 Claude에게 모든 도구 사용 후 사용자 입력을 기대하도록 가르칩니다
  2. 수정 없이 빈 응답을 재시도하지 마세요 - 단순히 빈 응답을 다시 보내는 것은 도움이 되지 않습니다
  3. 마지막 수단으로 연속 프롬프트 사용 - 위의 수정 사항이 문제를 해결하지 못한 경우에만 사용합니다

max_tokens

Claude가 요청에서 지정한 max_tokens 제한에 도달했기 때문에 중지했습니다.

Python
# Request with limited tokens
response = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=10,
    messages=[{"role": "user", "content": "Explain quantum physics"}],
)

if response.stop_reason == "max_tokens":
    # Response was truncated
    print("Response was cut off at token limit")
    # Consider making another request to continue

불완전한 도구 사용 블록

Claude의 응답이 max_tokens 제한에 도달하여 잘렸고, 잘린 응답에 불완전한 도구 사용 블록이 포함되어 있다면, 더 높은 max_tokens 값으로 요청을 재시도하여 전체 도구 사용을 얻어야 합니다.

stop_sequence

Claude가 사용자 정의 중지 시퀀스 중 하나를 만났습니다.

Python
response = client.messages.create(
    model="claude-opus-4-7",
    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}")

tool_use

Claude가 도구를 호출하고 있으며 사용자가 이를 실행하기를 기대합니다.

대부분의 도구 사용 구현의 경우, 도구 실행, 결과 형식 지정 및 대화 관리를 자동으로 처리하는 tool runner를 사용하는 것을 권장합니다.

Python
from anthropic import Anthropic

client = 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-sonnet-4-20250514",
    max_tokens=1024,
    tools=[weather_tool],
    messages=[{"role": "user", "content": "What's the weather?"}],
)

if response.stop_reason == "tool_use":
    # Extract and execute the tool
    for content in response.content:
        if content.type == "tool_use":
            result = execute_tool(content.name, content.input)
            # Return result to Claude for final response

pause_turn

웹 검색 또는 웹 가져오기와 같은 server tools를 실행하는 동안 서버 측 샘플링 루프가 반복 제한에 도달할 때 반환됩니다. 기본 제한은 요청당 10회 반복입니다.

이 경우 응답에는 해당하는 server_tool_result 없이 server_tool_use 블록이 포함될 수 있습니다. Claude가 처리를 완료하도록 하려면 응답을 그대로 다시 보내 대화를 계속하세요.

Python
response = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=1024,
    tools=[{"type": "web_search_20250305", "name": "web_search"}],
    messages=[{"role": "user", "content": "Search for latest AI news"}],
)

if response.stop_reason == "pause_turn":
    # Continue the conversation by sending the response back
    messages = [
        {"role": "user", "content": original_query},
        {"role": "assistant", "content": response.content},
    ]
    continuation = client.messages.create(
        model="claude-opus-4-7",
        messages=messages,
        tools=[{"type": "web_search_20250305", "name": "web_search"}],
    )

애플리케이션은 서버 도구를 사용하는 모든 에이전트 루프에서 pause_turn을 처리해야 합니다. 어시스턴트의 응답을 메시지 배열에 추가하고 Claude가 계속하도록 하는 다른 API 요청을 만드세요.

refusal

Claude가 안전 문제로 인해 응답 생성을 거부했습니다.

Python
response = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=1024,
    messages=[{"role": "user", "content": "[Unsafe request]"}],
)

if response.stop_reason == "refusal":
    # Claude declined to respond
    print("Claude was unable to process this request")
    # Consider rephrasing or modifying the request

Claude Sonnet 4.5 또는 Opus 4.1을 사용하는 동안 refusal 중지 이유가 자주 발생하면, API 호출을 Haiku 4.5(claude-haiku-4-5-20251001)를 사용하도록 업데이트하는 것을 시도할 수 있습니다. 이는 다른 사용 제한이 있습니다. Sonnet 4.5의 API 안전 필터 이해에 대해 자세히 알아보세요.

Claude Sonnet 4.5에 대한 API 안전 필터로 인해 트리거된 거부에 대해 자세히 알아보려면 Sonnet 4.5의 API 안전 필터 이해를 참조하세요.

model_context_window_exceeded

Claude가 모델의 컨텍스트 윈도우 제한에 도달했기 때문에 중지했습니다. 이를 통해 정확한 입력 크기를 알지 못해도 최대한 많은 토큰을 요청할 수 있습니다.

Python
# Request with maximum tokens to get as much as possible
response = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=64000,  # Practical non-streaming ceiling (Opus 4.7 supports 128K with streaming)
    messages=[
        {"role": "user", "content": "Large input that uses most of context window..."}
    ],
)

if response.stop_reason == "model_context_window_exceeded":
    # Response hit context window limit before max_tokens
    print("Response reached model's context window limit")
    # The response is still valid but was limited by context window

이 중지 이유는 Sonnet 4.5 이상의 모델에서 기본적으로 사용 가능합니다. 이전 모델의 경우, 베타 헤더 model-context-window-exceeded-2025-08-26을 사용하여 이 동작을 활성화하세요.

중지 이유 처리 모범 사례

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 == "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:
        # Handle end_turn and other cases
        return response.content[0].text

2. 잘린 응답을 우아하게 처리

토큰 제한 또는 컨텍스트 윈도우로 인해 응답이 잘렸을 때:

def handle_truncated_response(response):
    if response.stop_reason in ["max_tokens", "model_context_window_exceeded"]:
        # Option 1: Warn the user about the specific limit
        if response.stop_reason == "max_tokens":
            message = "[Response truncated due to max_tokens limit]"
        else:
            message = "[Response truncated due to context window limit]"
        return f"{response.content[0].text}\n\n{message}"

        # Option 2: Continue generation
        messages = [
            {"role": "user", "content": original_prompt},
            {"role": "assistant", "content": response.content[0].text},
        ]
        continuation = client.messages.create(
            model="claude-opus-4-7",
            max_tokens=1024,
            messages=messages + [{"role": "user", "content": "Please continue"}],
        )
        return response.content[0].text + continuation.content[0].text

3. pause_turn에 대한 재시도 로직 구현

server tools를 사용할 때, 서버 측 샘플링 루프가 반복 제한에 도달하면 API가 pause_turn을 반환할 수 있습니다(기본값 10). 대화를 계속하여 이를 처리하세요:

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-7", messages=messages, tools=tools
        )

        if response.stop_reason != "pause_turn":
            # Claude finished processing - return the final response
            return response

        # pause_turn: replace the full message list to maintain alternating roles
        messages = [
            {"role": "user", "content": user_query},
            {"role": "assistant", "content": response.content},
        ]

    # Reached max continuations - return the last response
    return response

중지 이유 대 오류

stop_reason 값과 실제 오류를 구분하는 것이 중요합니다:

중지 이유 (성공적인 응답)

  • 응답 본문의 일부
  • 생성이 정상적으로 중지된 이유를 나타냅니다
  • 응답에 유효한 내용이 포함됩니다

오류 (실패한 요청)

  • HTTP 상태 코드 4xx 또는 5xx
  • 요청 처리 실패를 나타냅니다
  • 응답에 오류 세부 정보가 포함됩니다
Python
import anthropic
from anthropic import Anthropic

client = Anthropic()

try:
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hello!"}],
    )

    # Handle successful response with stop_reason
    if response.stop_reason == "max_tokens":
        print("Response was truncated")

except anthropic.APIError as e:
    # Handle actual errors
    if e.status_code == 429:
        print("Rate limit exceeded")
    elif e.status_code == 500:
        print("Server error")

스트리밍 고려 사항

스트리밍을 사용할 때, stop_reason은:

  • 초기 message_start 이벤트에서 null입니다
  • message_delta 이벤트에서 제공됩니다
  • 다른 이벤트에서는 제공되지 않습니다
Python
from anthropic import Anthropic

client = Anthropic()

with client.messages.stream(
    model="claude-sonnet-4-20250514",
    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}")

일반적인 패턴

도구 사용 워크플로우 처리

tool runner로 더 간단하게: 아래 예제는 수동 도구 처리를 보여줍니다. 대부분의 사용 사례에서 tool runner는 훨씬 적은 코드로 도구 실행을 자동으로 처리합니다.

def complete_tool_workflow(client, user_query, tools):
    messages = [{"role": "user", "content": user_query}]

    while True:
        response = client.messages.create(
            model="claude-opus-4-7", messages=messages, tools=tools
        )

        if response.stop_reason == "tool_use":
            # Execute tools and continue
            tool_results = execute_tools(response.content)
            messages.append({"role": "assistant", "content": response.content})
            messages.append({"role": "user", "content": tool_results})
        else:
            # Final response
            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-opus-4-7", messages=messages, max_tokens=4096
        )

        full_response += response.content[0].text

        if response.stop_reason != "max_tokens":
            break

        # Continue from where it left off
        messages = [
            {"role": "user", "content": prompt},
            {"role": "assistant", "content": full_response},
            {"role": "user", "content": "Please continue from where you left off."},
        ]

    return full_response

입력 크기를 모르고 최대 토큰 얻기

model_context_window_exceeded 중지 이유를 사용하면, 입력 크기를 계산할 필요 없이 최대한 많은 토큰을 요청할 수 있습니다:

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.messages.create(
        model="claude-opus-4-7",
        messages=[{"role": "user", "content": prompt}],
        max_tokens=64000,  # Practical non-streaming ceiling (Opus 4.7 supports 128K with streaming)
    )

    if response.stop_reason == "model_context_window_exceeded":
        # Got the maximum possible tokens given input size
        print(
            f"Generated {response.usage.output_tokens} tokens (context limit reached)"
        )
    elif response.stop_reason == "max_tokens":
        # Got exactly the requested tokens
        print(f"Generated {response.usage.output_tokens} tokens (max_tokens reached)")
    else:
        # Natural completion
        print(f"Generated {response.usage.output_tokens} tokens (natural completion)")

    return response.content[0].text

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

# Check if response was truncated during tool use
if response.stop_reason == "max_tokens":
    # Check if the last content block is an incomplete tool_use
    last_block = response.content[-1]
    if last_block.type == "tool_use":
        # Send the request with higher max_tokens
        response = client.messages.create(
            model="claude-opus-4-7",
            max_tokens=4096,  # Increased limit
            messages=messages,
            tools=tools,
        )