Loading...
    • 개발자 가이드
    • API 참조
    • MCP
    • 리소스
    • 릴리스 노트
    Search...
    ⌘K
    첫 단계
    Claude 소개빠른 시작
    모델 및 가격
    모델 개요모델 선택Claude 4.5의 새로운 기능Claude 4.5로 마이그레이션모델 지원 중단가격
    Claude로 구축
    기능 개요Messages API 사용컨텍스트 윈도우프롬프트 작성 모범 사례
    기능
    프롬프트 캐싱컨텍스트 편집확장 사고노력메시지 스트리밍배치 처리인용다국어 지원토큰 계산임베딩비전PDF 지원Files API검색 결과구조화된 출력
    도구
    개요도구 사용 구현 방법세분화된 도구 스트리밍Bash 도구코드 실행 도구프로그래밍 방식 도구 호출컴퓨터 사용 도구텍스트 편집기 도구웹 가져오기 도구웹 검색 도구메모리 도구도구 검색 도구
    에이전트 스킬
    개요빠른 시작모범 사례API와 함께 스킬 사용
    에이전트 SDK
    개요빠른 시작TypeScript SDKTypeScript V2 (미리보기)Python SDK마이그레이션 가이드
    API의 MCP
    MCP 커넥터원격 MCP 서버
    타사 플랫폼의 Claude
    Amazon BedrockMicrosoft FoundryVertex AI
    프롬프트 엔지니어링
    개요프롬프트 생성기프롬프트 템플릿 사용프롬프트 개선기명확하고 직접적으로예제 사용 (다중 샷 프롬프팅)Claude가 생각하도록 하기 (CoT)XML 태그 사용Claude에게 역할 부여 (시스템 프롬프트)Claude의 응답 미리 채우기복잡한 프롬프트 연결긴 컨텍스트 팁확장 사고 팁
    테스트 및 평가
    성공 기준 정의테스트 케이스 개발평가 도구 사용지연 시간 감소
    가드레일 강화
    환각 감소출력 일관성 증가탈옥 완화거부 스트리밍프롬프트 유출 감소Claude를 캐릭터로 유지
    관리 및 모니터링
    Admin API 개요사용량 및 비용 APIClaude Code Analytics API
    Console
    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
    • Catalog
    • 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
    • Catalog
    • 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
    Documentation

    중지 이유 처리

    Claude의 응답에서 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
      }
    }

    중지 이유 값

    end_turn

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

    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-sonnet-4-20250514",
            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-sonnet-4-20250514",
                max_tokens=1024,
                messages=messages
            )
    
        return response

    모범 사례:

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

    max_tokens

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

    # Request with limited tokens
    response = client.messages.create(
        model="claude-sonnet-4-5",
        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

    stop_sequence

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

    response = client.messages.create(
        model="claude-sonnet-4-5",
        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가 도구를 호출하고 있으며 사용자가 이를 실행할 것으로 예상합니다.

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

    response = client.messages.create(
        model="claude-sonnet-4-5",
        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

    웹 검색과 같은 서버 도구와 함께 사용되며, Claude가 장시간 실행되는 작업을 일시 중지해야 할 때 사용됩니다.

    response = client.messages.create(
        model="claude-sonnet-4-5",
        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
        messages = [
            {"role": "user", "content": original_query},
            {"role": "assistant", "content": response.content}
        ]
        continuation = client.messages.create(
            model="claude-sonnet-4-5",
            messages=messages,
            tools=[{"type": "web_search_20250305", "name": "web_search"}]
        )

    refusal

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

    response = client.messages.create(
        model="claude-sonnet-4-5",
        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 중지 이유가 자주 발생하면, Sonnet 4 (claude-sonnet-4-20250514)를 사용하도록 API 호출을 업데이트할 수 있습니다. 이는 다른 사용 제한이 있습니다. Sonnet 4.5의 API 안전 필터 이해하기에 대해 자세히 알아보세요.

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

    model_context_window_exceeded

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

    # Request with maximum tokens to get as much as possible
    response = client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=64000,  # Model's maximum output tokens
        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-sonnet-4-5",
                max_tokens=1024,
                messages=messages + [{"role": "user", "content": "Please continue"}]
            )
            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-sonnet-4-5",
                messages=messages,
                tools=original_tools
            )
        
        return response

    중지 이유 대 오류

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

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

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

    오류 (실패한 요청)

    • HTTP 상태 코드 4xx 또는 5xx
    • 요청 처리 실패를 나타냅니다
    • 응답에 오류 세부 정보가 포함됩니다
    try:
        response = client.messages.create(...)
        
        # 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 이벤트에서 제공됩니다
    • 다른 이벤트에서는 제공되지 않습니다
    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"Stream ended with: {stop_reason}")

    일반적인 패턴

    도구 사용 워크플로우 처리

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

    def complete_tool_workflow(client, user_query, tools):
        messages = [{"role": "user", "content": user_query}]
    
        while True:
            response = client.messages.create(
                model="claude-sonnet-4-5",
                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-sonnet-4-5",
                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-sonnet-4-5",
            messages=[{"role": "user", "content": prompt}],
            max_tokens=64000  # Set to model's maximum output tokens
        )
    
        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 값을 적절하게 처리함으로써, 다양한 응답 시나리오를 우아하게 처리하고 더 나은 사용자 경험을 제공하는 더욱 견고한 애플리케이션을 구축할 수 있습니다.