• Messages
  • Managed Agents
  • 관리자
Search...
⌘K
첫 단계
Claude 소개빠른 시작
Claude로 빌드하기
기능 개요Messages API 사용하기중지 사유 및 폴백거부 및 폴백폴백 크레딧
모델 기능
확장 사고적응형 사고Effort작업 예산 (베타)빠른 모드 (리서치 프리뷰)구조화된 출력인용스트리밍 Messages배치 처리검색 결과스트리밍 거부다국어 지원임베딩
도구
개요도구 사용 작동 방식튜토리얼: 도구 사용 에이전트 빌드하기도구 정의도구 호출 처리병렬 도구 사용Tool Runner (SDK)엄격한 도구 사용프롬프트 캐싱과 함께 도구 사용서버 도구문제 해결웹 검색 도구웹 가져오기 도구코드 실행 도구Advisor 도구메모리 도구Bash 도구컴퓨터 사용 도구텍스트 편집기 도구
도구 인프라
도구 레퍼런스도구 컨텍스트 관리도구 조합도구 검색프로그래밍 방식 도구 호출세분화된 도구 스트리밍
컨텍스트 관리
컨텍스트 윈도우압축컨텍스트 편집프롬프트 캐싱대화 중 시스템 메시지오케스트레이션 모드 빌드하기캐시 진단 (베타)토큰 계산
파일 작업
Files APIPDF 지원이미지 및 비전
스킬
개요빠른 시작모범 사례엔터프라이즈용 스킬API에서의 스킬
MCP
원격 MCP 서버MCP 커넥터
클라우드 플랫폼의 Claude
Amazon BedrockAmazon Bedrock (레거시)AWS의 Claude PlatformMicrosoft FoundryVertex AI
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
Messages/Claude로 빌드하기

중지 이유 및 폴백

stop_reason 필드, 각 값의 의미, 그리고 거부 및 폴백을 처리하는 위치에 대해 설명합니다.

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
  }
}

중지 이유 값

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":
    # 완전한 응답 처리
    print(response.content[0].text)

end_turn과 함께 반환되는 빈 응답

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

일반적인 원인:

  • 도구 결과 바로 뒤에 텍스트 블록을 추가하는 경우 (Claude는 사용자가 도구 결과 뒤에 항상 텍스트를 삽입할 것이라고 학습하게 되어, 해당 패턴을 따르기 위해 자신의 턴을 종료합니다)
  • Claude의 완료된 응답을 아무것도 추가하지 않고 다시 보내는 경우 (Claude는 이미 완료했다고 판단했으므로 계속 완료 상태를 유지합니다)

빈 응답을 방지하는 방법:

# 잘못된 예: 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
            },
        ],
    },
]

# 올바른 예: 추가 텍스트 없이 도구 결과를 직접 전송
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
]


# 메시지 구조를 수정한 후에도 빈 응답이 계속되는 경우:
def handle_empty_response(client, messages):
    response = client.messages.create(
        model="claude-opus-4-8", max_tokens=1024, messages=messages
    )

    # 응답이 비어 있는지 확인
    if response.stop_reason == "end_turn" and not response.content:
        # 잘못된 예: 빈 응답으로 단순히 재시도하지 마세요
        # Claude가 이미 완료했다고 판단했으므로 이 방법은 작동하지 않습니다

        # 올바른 예: 새로운 사용자 메시지에 계속 진행 프롬프트 추가
        messages.append({"role": "user", "content": "Please continue"})

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

    return response

모범 사례:

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

max_tokens

Claude가 요청에 지정된 max_tokens 제한에 도달하여 중지했습니다.

Python
# 제한된 토큰으로 요청
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":
    # 응답이 잘렸습니다
    print("Response was cut off at token limit")
    # 계속하려면 추가 요청을 고려하세요

불완전한 도구 사용 블록

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

# 도구 사용 중 응답이 잘렸는지 확인
if response.stop_reason == "max_tokens":
    # 마지막 콘텐츠 블록이 불완전한 tool_use인지 확인
    last_block = response.content[-1]
    if last_block.type == "tool_use":
        # 더 높은 max_tokens 값으로 요청 전송
        response = client.messages.create(
            model="claude-opus-4-8",
            max_tokens=4096,  # Increased limit
            messages=messages,
            tools=tools,
        )

stop_sequence

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

Python
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}")

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":
    # 도구를 추출하고 실행합니다
    for content in response.content:
        if content.type == "tool_use":
            result = execute_tool(content.name, content.input)
            # 최종 응답을 위해 결과를 Claude에 반환합니다

pause_turn

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

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

Python
response = client.messages.create(
    model="claude-opus-4-8",
    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":
    # 응답을 다시 전송하여 대화를 계속합니다
    messages = [
        {"role": "user", "content": original_query},
        {"role": "assistant", "content": response.content},
    ]
    continuation = client.messages.create(
        model="claude-opus-4-8",
        max_tokens=1024,
        messages=messages,
        tools=[{"type": "web_search_20250305", "name": "web_search"}],
    )

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

refusal

Claude가 응답 생성을 거부했습니다. Claude Fable 5에서는 안전 분류기가 이 중지 이유를 오류가 아닌 일반 HTTP 200 응답으로 반환합니다.

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

if response.stop_reason == "refusal":
    # Claude가 응답을 거부했습니다
    print("Claude was unable to process this request")
    # 요청을 다시 표현하거나 수정하는 것을 고려하세요

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

거부 시 stop_details 객체는 거부를 트리거한 정책 카테고리를 식별합니다. 카테고리와 전체 거부 응답 형태는 거부 및 폴백에서 다룹니다. stop_details는 refusal 이외의 모든 중지 이유에 대해 null입니다.

Claude Fable 5에서 거부된 요청은 일반적으로 다른 Claude 모델에서 재시도하여 처리할 수 있으며, 거부 및 폴백에서 서버 측 또는 클라이언트에서 해당 재시도를 설정하는 방법을 보여줍니다. 폴백 크레딧에서는 재시도를 직접 구축할 때 프롬프트 캐시 비용을 두 번 지불하지 않는 방법을 다룹니다.

model_context_window_exceeded

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

Python
# 가능한 한 많이 얻기 위해 최대 토큰으로 요청
response = client.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":
    # 응답이 max_tokens 이전에 컨텍스트 윈도우 한도에 도달함
    print("Response reached model's context window limit")
    # 응답은 여전히 유효하지만 컨텍스트 윈도우에 의해 제한됨

이 중지 이유는 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:
        # end_turn 및 기타 경우 처리
        return response.content[0].text

2. 잘린 응답을 적절하게 처리하기

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

def handle_truncated_response(response):
    if response.stop_reason in ["max_tokens", "model_context_window_exceeded"]:
        # 옵션 1: 사용자에게 특정 제한에 대해 경고
        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}"

        # 옵션 2: 생성 계속하기
        messages = [
            {"role": "user", "content": original_prompt},
            {"role": "assistant", "content": response.content[0].text},
        ]
        continuation = client.messages.create(
            model="claude-opus-4-8",
            max_tokens=1024,
            messages=messages + [{"role": "user", "content": "Please continue"}],
        )
        return response.content[0].text + continuation.content[0].text

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

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

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

        if response.stop_reason != "pause_turn":
            # Claude가 처리를 완료함 - 최종 응답 반환
            return response

        # pause_turn: 역할 교대를 유지하기 위해 전체 메시지 목록을 교체
        messages = [
            {"role": "user", "content": user_query},
            {"role": "assistant", "content": response.content},
        ]

    # 최대 연속 횟수에 도달함 - 마지막 응답 반환
    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!"}],
    )

    # stop_reason이 있는 성공 응답 처리
    if response.stop_reason == "max_tokens":
        print("Response was truncated")

except anthropic.APIStatusError as e:
    # 실제 오류 처리
    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-8", max_tokens=1024, 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-opus-4-8", 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": "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-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":
        # 입력 크기를 고려한 최대 가능 토큰 수를 받았습니다
        print(
            f"Generated {response.usage.output_tokens} tokens (context limit reached)"
        )
    elif response.stop_reason == "max_tokens":
        # 요청한 토큰 수를 정확히 받았습니다
        print(f"Generated {response.usage.output_tokens} tokens (max_tokens reached)")
    else:
        # 자연스러운 완료
        print(f"Generated {response.usage.output_tokens} tokens (natural completion)")

    return response.content[0].text

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

Was this page helpful?

  • stop_reason 필드
  • 중지 이유 값
  • end_turn
  • max_tokens
  • stop_sequence
  • tool_use
  • pause_turn
  • refusal
  • model_context_window_exceeded
  • 중지 이유 처리를 위한 모범 사례
  • 1. 항상 stop_reason 확인하기
  • 2. 잘린 응답을 적절하게 처리하기
  • 3. pause_turn에 대한 재시도 로직 구현하기
  • 중지 이유와 오류의 차이
  • 중지 이유 (성공적인 응답)
  • 오류 (실패한 요청)
  • 스트리밍 고려 사항
  • 일반적인 패턴
  • 도구 사용 워크플로 처리하기
  • 완전한 응답 보장하기
  • 입력 크기를 모르는 상태에서 최대 토큰 얻기