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마이그레이션 가이드
    스트리밍 입력실시간 응답 스트리밍중지 사유 처리권한 처리사용자 승인 및 입력훅으로 실행 제어세션 관리파일 체크포인팅SDK에서 구조화된 출력Agent SDK 호스팅AI 에이전트 안전한 배포시스템 프롬프트 수정SDK에서 MCP커스텀 도구SDK에서 서브에이전트SDK에서 슬래시 명령어SDK에서 Agent Skills비용 및 사용량 추적할 일 목록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의 승인 요청과 명확화 질문을 사용자에게 표시한 다음, 사용자의 결정을 SDK에 반환합니다.

    작업을 수행하는 동안 Claude는 때때로 사용자에게 확인이 필요합니다. 파일을 삭제하기 전에 권한이 필요하거나, 새 프로젝트에 어떤 데이터베이스를 사용할지 물어봐야 할 수 있습니다. 애플리케이션은 이러한 요청을 사용자에게 표시하여 Claude가 사용자의 입력으로 계속 진행할 수 있도록 해야 합니다.

    Claude는 두 가지 상황에서 사용자 입력을 요청합니다: 도구 사용 권한이 필요할 때(파일 삭제나 명령 실행 등)와 명확화 질문이 있을 때(AskUserQuestion 도구를 통해). 두 경우 모두 canUseTool 콜백을 트리거하며, 응답을 반환할 때까지 실행이 일시 중지됩니다. 이는 Claude가 작업을 완료하고 다음 메시지를 기다리는 일반적인 대화 턴과는 다릅니다.

    명확화 질문의 경우, Claude가 질문과 옵션을 생성합니다. 여러분의 역할은 이를 사용자에게 제시하고 선택 결과를 반환하는 것입니다. 이 흐름에 자체 질문을 추가할 수는 없습니다. 사용자에게 직접 무언가를 물어봐야 한다면, 애플리케이션 로직에서 별도로 처리하세요.

    이 가이드에서는 각 유형의 요청을 감지하고 적절하게 응답하는 방법을 보여줍니다.

    Claude가 입력을 필요로 하는 시점 감지

    쿼리 옵션에 canUseTool 콜백을 전달합니다. 이 콜백은 Claude가 사용자 입력을 필요로 할 때마다 실행되며, 도구 이름과 입력을 인수로 받습니다:

    async def handle_tool_request(tool_name, input_data, context):
        # Prompt user and return allow or deny
        ...
    
    options = ClaudeAgentOptions(can_use_tool=handle_tool_request)

    콜백은 두 가지 경우에 실행됩니다:

    1. 도구 승인 필요: Claude가 권한 규칙이나 모드에 의해 자동 승인되지 않은 도구를 사용하려고 합니다. tool_name에서 도구를 확인합니다(예: "Bash", "Write").
    2. Claude가 질문: Claude가 AskUserQuestion 도구를 호출합니다. tool_name == "AskUserQuestion"인지 확인하여 다르게 처리합니다. tools 배열을 지정하는 경우, 이 기능이 작동하려면 AskUserQuestion을 포함해야 합니다. 자세한 내용은 명확화 질문 처리를 참조하세요.

    사용자에게 프롬프트 없이 도구를 자동으로 허용하거나 거부하려면 대신 hooks를 사용하세요. Hooks는 canUseTool 전에 실행되며 자체 로직에 따라 요청을 허용, 거부 또는 수정할 수 있습니다. PermissionRequest hook을 사용하여 Claude가 승인을 기다리고 있을 때 외부 알림(Slack, 이메일, 푸시)을 보낼 수도 있습니다.

    도구 승인 요청 처리

    쿼리 옵션에 canUseTool 콜백을 전달하면, Claude가 자동 승인되지 않은 도구를 사용하려고 할 때 실행됩니다. 콜백은 두 개의 인수를 받습니다:

    인수설명
    toolNameClaude가 사용하려는 도구의 이름(예: "Bash", "Write", "Edit")
    inputClaude가 도구에 전달하는 매개변수. 내용은 도구에 따라 다릅니다.

    input 객체에는 도구별 매개변수가 포함됩니다. 일반적인 예시:

    도구입력 필드
    Bashcommand, description, timeout
    Writefile_path, content
    Editfile_path, old_string, new_string
    Readfile_path, offset, limit

    전체 입력 스키마는 SDK 레퍼런스를 참조하세요: Python | TypeScript.

    이 정보를 사용자에게 표시하여 작업을 허용할지 거부할지 결정하게 한 다음, 적절한 응답을 반환할 수 있습니다.

    다음 예시는 Claude에게 테스트 파일을 생성하고 삭제하도록 요청합니다. Claude가 각 작업을 시도할 때, 콜백은 도구 요청을 터미널에 출력하고 y/n 승인을 요청합니다.

    import asyncio
    
    from claude_agent_sdk import ClaudeAgentOptions, query
    from claude_agent_sdk.types import (
        HookMatcher,
        PermissionResultAllow,
        PermissionResultDeny,
        ToolPermissionContext,
    )
    
    
    async def can_use_tool(
        tool_name: str, input_data: dict, context: ToolPermissionContext
    ) -> PermissionResultAllow | PermissionResultDeny:
        # Display the tool request
        print(f"\nTool: {tool_name}")
        if tool_name == "Bash":
            print(f"Command: {input_data.get('command')}")
            if input_data.get("description"):
                print(f"Description: {input_data.get('description')}")
        else:
            print(f"Input: {input_data}")
    
        # Get user approval
        response = input("Allow this action? (y/n): ")
    
        # Return allow or deny based on user's response
        if response.lower() == "y":
            # Allow: tool executes with the original (or modified) input
            return PermissionResultAllow(updated_input=input_data)
        else:
            # Deny: tool doesn't execute, Claude sees the message
            return PermissionResultDeny(message="User denied this action")
    
    
    # Required workaround: dummy hook keeps the stream open for can_use_tool
    async def dummy_hook(input_data, tool_use_id, context):
        return {"continue_": True}
    
    
    async def prompt_stream():
        yield {
            "type": "user",
            "message": {
                "role": "user",
                "content": "Create a test file in /tmp and then delete it",
            },
        }
    
    
    async def main():
        async for message in query(
            prompt=prompt_stream(),
            options=ClaudeAgentOptions(
                can_use_tool=can_use_tool,
                hooks={"PreToolUse": [HookMatcher(matcher=None, hooks=[dummy_hook])]},
            ),
        ):
            if hasattr(message, "result"):
                print(message.result)
    
    
    asyncio.run(main())

    Python에서 can_use_tool은 스트리밍 모드와 {"continue_": True}를 반환하는 PreToolUse hook이 필요합니다. 이 hook이 없으면 권한 콜백이 호출되기 전에 스트림이 닫힙니다.

    이 예시는 y 이외의 입력을 거부로 처리하는 y/n 흐름을 사용합니다. 실제로는 사용자가 요청을 수정하거나, 피드백을 제공하거나, Claude를 완전히 다른 방향으로 안내할 수 있는 더 풍부한 UI를 구축할 수 있습니다. 응답할 수 있는 모든 방법은 도구 요청에 응답하기를 참조하세요.

    도구 요청에 응답하기

    콜백은 두 가지 응답 유형 중 하나를 반환합니다:

    응답PythonTypeScript
    허용PermissionResultAllow(updated_input=...){ behavior: "allow", updatedInput }
    거부PermissionResultDeny(message=...){ behavior: "deny", message }

    허용할 때는 도구 입력(원본 또는 수정된)을 전달합니다. 거부할 때는 이유를 설명하는 메시지를 제공합니다. Claude는 이 메시지를 보고 접근 방식을 조정할 수 있습니다.

    from claude_agent_sdk.types import PermissionResultAllow, PermissionResultDeny
    
    # Allow the tool to execute
    return PermissionResultAllow(updated_input=input_data)
    
    # Block the tool
    return PermissionResultDeny(message="User rejected this action")

    허용이나 거부 외에도, 도구의 입력을 수정하거나 Claude가 접근 방식을 조정하는 데 도움이 되는 컨텍스트를 제공할 수 있습니다:

    • 승인: Claude가 요청한 대로 도구를 실행합니다
    • 변경 사항과 함께 승인: 실행 전에 입력을 수정합니다(예: 경로 정리, 제약 조건 추가)
    • 거부: 도구를 차단하고 Claude에게 이유를 알립니다
    • 대안 제안: 차단하되 사용자가 원하는 방향으로 Claude를 안내합니다
    • 완전히 방향 전환: 스트리밍 입력을 사용하여 Claude에게 완전히 새로운 지시를 보냅니다

    명확화 질문 처리

    Claude가 여러 유효한 접근 방식이 있는 작업에서 더 많은 방향이 필요할 때, AskUserQuestion 도구를 호출합니다. 이는 toolName이 AskUserQuestion으로 설정된 canUseTool 콜백을 트리거합니다. 입력에는 Claude의 질문이 객관식 옵션으로 포함되어 있으며, 이를 사용자에게 표시하고 선택 결과를 반환합니다.

    명확화 질문은 plan 모드에서 특히 자주 발생합니다. 이 모드에서 Claude는 코드베이스를 탐색하고 계획을 제안하기 전에 질문합니다. 이는 Claude가 변경을 수행하기 전에 요구 사항을 수집하도록 하려는 대화형 워크플로에 plan 모드가 이상적인 이유입니다.

    다음 단계는 명확화 질문을 처리하는 방법을 보여줍니다:

    1. 1

      canUseTool 콜백 전달

      쿼리 옵션에 canUseTool 콜백을 전달합니다. 기본적으로 AskUserQuestion은 사용 가능합니다. Claude의 기능을 제한하기 위해 tools 배열을 지정하는 경우(예: Read, Glob, Grep만 있는 읽기 전용 에이전트), 해당 배열에 AskUserQuestion을 포함하세요. 그렇지 않으면 Claude가 명확화 질문을 할 수 없습니다:

      async for message in query(
          prompt="Analyze this codebase",
          options=ClaudeAgentOptions(
              # Include AskUserQuestion in your tools list
              tools=["Read", "Glob", "Grep", "AskUserQuestion"],
              can_use_tool=can_use_tool,
          ),
      ):
          # ...
    2. 2

      AskUserQuestion 감지

      콜백에서 toolName이 AskUserQuestion과 같은지 확인하여 다른 도구와 다르게 처리합니다:

      async def can_use_tool(tool_name: str, input_data: dict, context):
          if tool_name == "AskUserQuestion":
              # Your implementation to collect answers from the user
              return await handle_clarifying_questions(input_data)
          # Handle other tools normally
          return await prompt_for_approval(tool_name, input_data)
    3. 3

      질문 입력 파싱

      입력에는 Claude의 질문이 questions 배열에 포함되어 있습니다. 각 질문에는 question(표시할 텍스트), options(선택지), multiSelect(복수 선택 허용 여부)가 있습니다:

      {
        "questions": [
          {
            "question": "How should I format the output?",
            "header": "Format",
            "options": [
              { "label": "Summary", "description": "Brief overview" },
              { "label": "Detailed", "description": "Full explanation" }
            ],
            "multiSelect": false
          },
          {
            "question": "Which sections should I include?",
            "header": "Sections",
            "options": [
              { "label": "Introduction", "description": "Opening context" },
              { "label": "Conclusion", "description": "Final summary" }
            ],
            "multiSelect": true
          }
        ]
      }

      전체 필드 설명은 질문 형식을 참조하세요.

    4. 4

      사용자로부터 답변 수집

      질문을 사용자에게 제시하고 선택을 수집합니다. 이를 수행하는 방법은 애플리케이션에 따라 다릅니다: 터미널 프롬프트, 웹 폼, 모바일 대화 상자 등.

    5. 5

      Claude에게 답변 반환

      answers 객체를 각 키가 question 텍스트이고 각 값이 선택된 옵션의 label인 레코드로 구성합니다:

      질문 객체에서용도
      question 필드 (예: "How should I format the output?")키
      선택된 옵션의 label 필드 (예: "Summary")값

      복수 선택 질문의 경우, 여러 레이블을 ", "로 결합합니다. 자유 텍스트 입력을 지원하는 경우, 사용자의 커스텀 텍스트를 값으로 사용합니다.

      return PermissionResultAllow(
          updated_input={
              "questions": input_data.get("questions", []),
              "answers": {
                  "How should I format the output?": "Summary",
                  "Which sections should I include?": "Introduction, Conclusion"
              }
          }
      )

    질문 형식

    입력에는 Claude가 생성한 질문이 questions 배열에 포함되어 있습니다. 각 질문에는 다음 필드가 있습니다:

    필드설명
    question표시할 전체 질문 텍스트
    header질문의 짧은 레이블 (최대 12자)
    options2-4개의 선택지 배열, 각각 label과 description 포함
    multiSelecttrue이면 사용자가 여러 옵션을 선택할 수 있음

    다음은 받게 될 구조의 예시입니다:

    {
      "questions": [
        {
          "question": "How should I format the output?",
          "header": "Format",
          "options": [
            { "label": "Summary", "description": "Brief overview of key points" },
            { "label": "Detailed", "description": "Full explanation with examples" }
          ],
          "multiSelect": false
        }
      ]
    }

    응답 형식

    각 질문의 question 필드를 선택된 옵션의 label에 매핑하는 answers 객체를 반환합니다:

    필드설명
    questions원본 질문 배열을 그대로 전달 (도구 처리에 필요)
    answers키가 질문 텍스트이고 값이 선택된 레이블인 객체

    복수 선택 질문의 경우, 여러 레이블을 ", "로 결합합니다. 자유 텍스트 입력의 경우, 사용자의 커스텀 텍스트를 직접 사용합니다.

    {
      "questions": [...],
      "answers": {
        "How should I format the output?": "Summary",
        "Which sections should I include?": "Introduction, Conclusion"
      }
    }

    자유 텍스트 입력 지원

    Claude의 사전 정의된 옵션이 항상 사용자가 원하는 것을 다루지는 않습니다. 사용자가 직접 답변을 입력할 수 있도록 하려면:

    • Claude의 옵션 뒤에 텍스트 입력을 받는 추가 "Other" 선택지를 표시합니다
    • 사용자의 커스텀 텍스트를 답변 값으로 사용합니다("Other"라는 단어가 아닌)

    전체 구현은 아래의 전체 예시를 참조하세요.

    전체 예시

    Claude는 진행하기 위해 사용자 입력이 필요할 때 명확화 질문을 합니다. 예를 들어, 모바일 앱의 기술 스택을 결정하는 데 도움을 요청받으면, Claude는 크로스 플랫폼 vs 네이티브, 백엔드 선호도 또는 대상 플랫폼에 대해 질문할 수 있습니다. 이러한 질문은 Claude가 추측하지 않고 사용자의 선호도에 맞는 결정을 내리는 데 도움이 됩니다.

    이 예시는 터미널 애플리케이션에서 이러한 질문을 처리합니다. 각 단계에서 일어나는 일은 다음과 같습니다:

    1. 요청 라우팅: canUseTool 콜백이 도구 이름이 "AskUserQuestion"인지 확인하고 전용 핸들러로 라우팅합니다
    2. 질문 표시: 핸들러가 questions 배열을 순회하며 각 질문을 번호가 매겨진 옵션과 함께 출력합니다
    3. 입력 수집: 사용자는 옵션을 선택하기 위해 번호를 입력하거나, 자유 텍스트를 직접 입력할 수 있습니다(예: "jquery", "i don't know")
    4. 답변 매핑: 코드가 입력이 숫자인지(옵션의 레이블 사용) 자유 텍스트인지(텍스트를 직접 사용) 확인합니다
    5. Claude에게 반환: 응답에는 원본 questions 배열과 answers 매핑이 모두 포함됩니다
    import asyncio
    
    from claude_agent_sdk import ClaudeAgentOptions, query
    from claude_agent_sdk.types import HookMatcher, PermissionResultAllow
    
    
    def parse_response(response: str, options: list) -> str:
        """Parse user input as option number(s) or free text."""
        try:
            indices = [int(s.strip()) - 1 for s in response.split(",")]
            labels = [options[i]["label"] for i in indices if 0 <= i < len(options)]
            return ", ".join(labels) if labels else response
        except ValueError:
            return response
    
    
    async def handle_ask_user_question(input_data: dict) -> PermissionResultAllow:
        """Display Claude's questions and collect user answers."""
        answers = {}
    
        for q in input_data.get("questions", []):
            print(f"\n{q['header']}: {q['question']}")
    
            options = q["options"]
            for i, opt in enumerate(options):
                print(f"  {i + 1}. {opt['label']} - {opt['description']}")
            if q.get("multiSelect"):
                print("  (Enter numbers separated by commas, or type your own answer)")
            else:
                print("  (Enter a number, or type your own answer)")
    
            response = input("Your choice: ").strip()
            answers[q["question"]] = parse_response(response, options)
    
        return PermissionResultAllow(
            updated_input={
                "questions": input_data.get("questions", []),
                "answers": answers,
            }
        )
    
    
    async def can_use_tool(tool_name: str, input_data: dict, context) -> PermissionResultAllow:
        # Route AskUserQuestion to our question handler
        if tool_name == "AskUserQuestion":
            return await handle_ask_user_question(input_data)
        # Auto-approve other tools for this example
        return PermissionResultAllow(updated_input=input_data)
    
    
    async def prompt_stream():
        yield {
            "type": "user",
            "message": {"role": "user", "content": "Help me decide on the tech stack for a new mobile app"},
        }
    
    
    # Required workaround: dummy hook keeps the stream open for can_use_tool
    async def dummy_hook(input_data, tool_use_id, context):
        return {"continue_": True}
    
    
    async def main():
        async for message in query(
            prompt=prompt_stream(),
            options=ClaudeAgentOptions(
                can_use_tool=can_use_tool,
                hooks={"PreToolUse": [HookMatcher(matcher=None, hooks=[dummy_hook])]},
            ),
        ):
            if hasattr(message, "result"):
                print(message.result)
    
    
    asyncio.run(main())

    제한 사항

    • 서브에이전트: AskUserQuestion은 현재 Task 도구를 통해 생성된 서브에이전트에서 사용할 수 없습니다
    • 질문 제한: 각 AskUserQuestion 호출은 1-4개의 질문과 각각 2-4개의 옵션을 지원합니다

    사용자 입력을 받는 다른 방법

    canUseTool 콜백과 AskUserQuestion 도구는 대부분의 승인 및 명확화 시나리오를 다루지만, SDK는 사용자로부터 입력을 받는 다른 방법도 제공합니다:

    스트리밍 입력

    다음이 필요할 때 스트리밍 입력을 사용하세요:

    • 작업 중 에이전트 중단: Claude가 작업 중일 때 취소 신호를 보내거나 방향을 변경합니다
    • 추가 컨텍스트 제공: Claude가 요청하기를 기다리지 않고 필요한 정보를 추가합니다
    • 채팅 인터페이스 구축: 장시간 실행되는 작업 중에 사용자가 후속 메시지를 보낼 수 있게 합니다

    스트리밍 입력은 승인 체크포인트에서만이 아니라 실행 전반에 걸쳐 사용자가 에이전트와 상호작용하는 대화형 UI에 이상적입니다.

    커스텀 도구

    다음이 필요할 때 커스텀 도구를 사용하세요:

    • 구조화된 입력 수집: AskUserQuestion의 객관식 형식을 넘어서는 폼, 마법사 또는 다단계 워크플로를 구축합니다
    • 외부 승인 시스템 통합: 기존 티켓팅, 워크플로 또는 승인 플랫폼에 연결합니다
    • 도메인별 상호작용 구현: 코드 리뷰 인터페이스나 배포 체크리스트와 같이 애플리케이션의 요구에 맞는 도구를 만듭니다

    커스텀 도구는 상호작용에 대한 완전한 제어를 제공하지만, 내장 canUseTool 콜백을 사용하는 것보다 더 많은 구현 작업이 필요합니다.

    관련 리소스

    • 권한 구성: 권한 모드 및 규칙 설정
    • hooks로 실행 제어: 에이전트 라이프사이클의 주요 지점에서 커스텀 코드 실행
    • TypeScript SDK 레퍼런스: 전체 canUseTool API 문서

    Was this page helpful?

    • Claude가 입력을 필요로 하는 시점 감지