Loading...
    • 개발자 가이드
    • API 레퍼런스
    • MCP
    • 리소스
    • 릴리스 노트
    Search...
    ⌘K
    시작하기
    Claude 소개빠른 시작
    모델 및 가격
    모델 개요모델 선택Claude 4.6의 새로운 기능마이그레이션 가이드모델 지원 중단가격
    Claude로 구축하기
    기능 개요Messages API 사용중지 사유 처리프롬프트 모범 사례
    컨텍스트 관리
    컨텍스트 윈도우압축컨텍스트 편집
    기능
    프롬프트 캐싱확장 사고적응형 사고노력 수준메시지 스트리밍배치 처리인용다국어 지원토큰 카운팅임베딩비전PDF 지원Files API검색 결과구조화된 출력
    도구
    개요도구 사용 구현 방법세분화된 도구 스트리밍Bash 도구코드 실행 도구프로그래밍 방식 도구 호출컴퓨터 사용 도구텍스트 편집기 도구웹 페치 도구웹 검색 도구메모리 도구도구 검색 도구
    Agent Skills
    개요빠른 시작모범 사례엔터프라이즈용 SkillsAPI로 Skills 사용
    Agent SDK
    개요빠른 시작TypeScript SDKTypeScript V2 (미리보기)Python SDK마이그레이션 가이드
    API에서 MCP
    MCP 커넥터원격 MCP 서버
    서드파티 플랫폼의 Claude
    Amazon BedrockMicrosoft FoundryVertex AI
    프롬프트 엔지니어링
    개요프롬프트 생성기프롬프트 템플릿 사용프롬프트 개선기명확하고 직접적으로 작성예시 사용 (멀티샷 프롬프팅)Claude에게 생각하게 하기 (CoT)XML 태그 사용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
    Claude로 구축하기

    중단 사유 처리하기

    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가 자연스럽게 응답을 완료했음을 나타냅니다.

    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"  # 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"
            }
        ]}  # tool_result만, 추가 텍스트 없음
    ]
    
    # 위 방법을 적용한 후에도 빈 응답이 계속 발생하는 경우:
    def handle_empty_response(client, messages):
        response = client.messages.create(
            model="claude-opus-4-6",
            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-6",
                max_tokens=1024,
                messages=messages
            )
    
        return response

    모범 사례:

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

    max_tokens

    Claude가 요청에서 지정한 max_tokens 제한에 도달하여 중단되었습니다.

    # 토큰이 제한된 요청
    response = client.messages.create(
        model="claude-opus-4-6",
        max_tokens=10,
        messages=[{"role": "user", "content": "Explain quantum physics"}]
    )
    
    if response.stop_reason == "max_tokens":
        # 응답이 잘렸음
        print("Response was cut off at token limit")
        # 계속하기 위해 다른 요청을 보내는 것을 고려하세요

    stop_sequence

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

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

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

    response = client.messages.create(
        model="claude-opus-4-6",
        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-6",
            messages=messages,
            tools=[{"type": "web_search_20250305", "name": "web_search"}]
        )

    refusal

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

    response = client.messages.create(
        model="claude-opus-4-6",
        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 중단 사유를 자주 만나는 경우, API 호출을 Sonnet 4(claude-sonnet-4-20250514)로 업데이트해 보세요. 이 모델은 다른 사용 제한이 적용됩니다. Sonnet 4.5의 API 안전 필터 이해하기에서 자세히 알아보세요.

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

    model_context_window_exceeded

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

    # 가능한 한 많은 토큰을 얻기 위해 최대 토큰으로 요청
    response = client.messages.create(
        model="claude-opus-4-6",
        max_tokens=64000,  # 모델의 최대 출력 토큰
        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-6",
                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-opus-4-6",
                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("Response was truncated")
        
    except anthropic.APIError 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 이벤트에서 제공됨
    • 다른 이벤트에서는 제공되지 않음
    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-opus-4-6",
                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-6",
                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):
        """
        입력 토큰 수를 계산할 필요 없이
        모델의 컨텍스트 윈도우 내에서 가능한 한 많은 토큰을 얻습니다
        """
        response = client.messages.create(
            model="claude-opus-4-6",
            messages=[{"role": "user", "content": prompt}],
            max_tokens=64000  # 모델의 최대 출력 토큰으로 설정
        )
    
        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에 대한 재시도 로직 구현
    • 중단 사유 vs. 오류