Loading...
    • Guia do Desenvolvedor
    • Referência da API
    • MCP
    • Recursos
    • Notas de lançamento
    Search...
    ⌘K
    Primeiros passos
    Introdução ao ClaudeInício rápido
    Modelos e preços
    Visão geral dos modelosEscolhendo um modeloNovidades no Claude 4.6Guia de migraçãoDescontinuação de modelosPreços
    Construir com Claude
    Visão geral de recursosUsando a API MessagesTratando razões de paradaMelhores práticas de prompts
    Gerenciamento de contexto
    Janelas de contextoCompactaçãoEdição de contexto
    Capacidades
    Cache de promptsPensamento estendidoPensamento adaptativoEsforçoStreaming de mensagensProcessamento em loteCitaçõesSuporte multilíngueContagem de tokensEmbeddingsVisãoSuporte a PDFAPI de ArquivosResultados de pesquisaSaídas estruturadas
    Ferramentas
    Visão geralComo implementar o uso de ferramentasStreaming de ferramentas granularFerramenta BashFerramenta de execução de códigoChamada de ferramentas programáticaFerramenta de uso de computadorFerramenta de editor de textoFerramenta de busca na webFerramenta de pesquisa na webFerramenta de memóriaFerramenta de busca de ferramentas
    Habilidades de agente
    Visão geralInício rápidoMelhores práticasHabilidades para empresasUsando habilidades com a API
    Agent SDK
    Visão geralInício rápidoSDK TypeScriptTypeScript V2 (prévia)SDK PythonGuia de migração
    Entrada de streamingTransmitir respostas em tempo realTratando razões de paradaTratando permissõesAprovações de usuário e entradaControlar execução com hooksGerenciamento de sessãoPonto de verificação de arquivoSaídas estruturadas no SDKHospedando o Agent SDKImplantação segura de agentes de IAModificando prompts do sistemaMCP no SDKFerramentas personalizadasSubagentos no SDKComandos de barra no SDKHabilidades de agente no SDKRastreando custos e usoListas de tarefasPlugins no SDK
    MCP na API
    Conector MCPServidores MCP remotos
    Claude em plataformas de terceiros
    Amazon BedrockMicrosoft FoundryVertex AI
    Engenharia de prompts
    Visão geralGerador de promptsUsar modelos de promptsMelhorador de promptsSeja claro e diretoUse exemplos (prompting multishotshot)Deixe Claude pensar (CoT)Use tags XMLDê um papel ao Claude (prompts do sistema)Encadear prompts complexosDicas de contexto longoDicas de pensamento estendido
    Testar e avaliar
    Definir critérios de sucessoDesenvolver casos de testeUsando a ferramenta de avaliaçãoReduzindo latência
    Fortalecer proteções
    Reduzir alucinaçõesAumentar consistência de saídaMitigar jailbreaksRecusas de streamingReduzir vazamento de promptManter Claude em personagem
    Administração e monitoramento
    Visão geral da API AdminResidência de dadosEspaços de trabalhoAPI de uso e custoAPI de análise de código ClaudeRetenção zero de dados
    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
    Guias

    Lidar com aprovações e entrada do usuário

    Apresente as solicitações de aprovação e perguntas de esclarecimento do Claude aos usuários e retorne suas decisões ao SDK.

    Was this page helpful?

    • Detectar quando Claude precisa de entrada
    • Lidar com solicitações de aprovação de ferramenta
    • Responder a solicitações de ferramenta
    • Lidar com perguntas de esclarecimento
    • Formato de pergunta
    • Formato de resposta
    • Exemplo completo
    • Limitações
    • Outras maneiras de obter entrada do usuário
    • Entrada de streaming
    • Ferramentas personalizadas
    • Recursos relacionados

    Ao trabalhar em uma tarefa, Claude às vezes precisa verificar com os usuários. Pode precisar de permissão antes de deletar arquivos ou precisar perguntar qual banco de dados usar para um novo projeto. Seu aplicativo precisa apresentar essas solicitações aos usuários para que Claude possa continuar com sua entrada.

    Claude solicita entrada do usuário em duas situações: quando precisa de permissão para usar uma ferramenta (como deletar arquivos ou executar comandos) e quando tem perguntas de esclarecimento (via a ferramenta AskUserQuestion). Ambas acionam seu callback canUseTool, que pausa a execução até que você retorne uma resposta. Isso é diferente dos turnos de conversa normais onde Claude termina e aguarda sua próxima mensagem.

    Para perguntas de esclarecimento, Claude gera as perguntas e opções. Seu papel é apresentá-las aos usuários e retornar suas seleções. Você não pode adicionar suas próprias perguntas a este fluxo; se precisar perguntar algo aos usuários, faça isso separadamente na lógica do seu aplicativo.

    Este guia mostra como detectar cada tipo de solicitação e responder apropriadamente.

    Detectar quando Claude precisa de entrada

    Passe um callback canUseTool nas opções de sua consulta. O callback é acionado sempre que Claude precisa de entrada do usuário, recebendo o nome da ferramenta e a entrada como argumentos:

    async def handle_tool_request(tool_name, input_data, context):
        # Solicitar ao usuário e retornar permitir ou negar
        ...
    
    options = ClaudeAgentOptions(can_use_tool=handle_tool_request)

    O callback é acionado em dois casos:

    1. Ferramenta precisa de aprovação: Claude quer usar uma ferramenta que não é aprovada automaticamente por regras de permissão ou modos. Verifique tool_name para a ferramenta (por exemplo, "Bash", "Write").
    2. Claude faz uma pergunta: Claude chama a ferramenta AskUserQuestion. Verifique se tool_name == "AskUserQuestion" para tratá-la diferentemente. Se você especificar um array tools, inclua AskUserQuestion para que isso funcione. Veja Lidar com perguntas de esclarecimento para detalhes.

    Para permitir ou negar ferramentas automaticamente sem solicitar aos usuários, use hooks em vez disso. Os hooks são executados antes de canUseTool e podem permitir, negar ou modificar solicitações com base em sua própria lógica. Você também pode usar o hook PermissionRequest para enviar notificações externas (Slack, email, push) quando Claude está aguardando aprovação.

    Lidar com solicitações de aprovação de ferramenta

    Depois de passar um callback canUseTool nas opções de sua consulta, ele é acionado quando Claude quer usar uma ferramenta que não é aprovada automaticamente. Seu callback recebe dois argumentos:

    ArgumentoDescrição
    toolNameO nome da ferramenta que Claude quer usar (por exemplo, "Bash", "Write", "Edit")
    inputOs parâmetros que Claude está passando para a ferramenta. O conteúdo varia por ferramenta.

    O objeto input contém parâmetros específicos da ferramenta. Exemplos comuns:

    FerramentaCampos de entrada
    Bashcommand, description, timeout
    Writefile_path, content
    Editfile_path, old_string, new_string
    Readfile_path, offset, limit

    Veja a referência do SDK para esquemas de entrada completos: Python | TypeScript.

    Você pode exibir essas informações ao usuário para que ele possa decidir se permite ou rejeita a ação, e então retornar a resposta apropriada.

    O exemplo a seguir pede ao Claude para criar e deletar um arquivo de teste. Quando Claude tenta cada operação, o callback imprime a solicitação de ferramenta no terminal e solicita aprovação s/n.

    Em Python, can_use_tool requer modo de streaming e um hook PreToolUse que retorna {"continue_": True} para manter o stream aberto. Sem este hook, o stream fecha antes que o callback de permissão possa ser invocado.

    Este exemplo usa um fluxo s/n onde qualquer entrada diferente de y é tratada como uma negação. Na prática, você pode construir uma UI mais rica que permite aos usuários modificar a solicitação, fornecer feedback ou redirecionar Claude completamente. Veja Responder a solicitações de ferramenta para todas as maneiras que você pode responder.

    Responder a solicitações de ferramenta

    Seu callback retorna um de dois tipos de resposta:

    RespostaPythonTypeScript
    PermitirPermissionResultAllow(updated_input=...){ behavior: "allow", updatedInput }
    NegarPermissionResultDeny(message=...){ behavior: "deny", message }

    Ao permitir, passe a entrada da ferramenta (original ou modificada). Ao negar, forneça uma mensagem explicando por quê. Claude vê esta mensagem e pode ajustar sua abordagem.

    from claude_agent_sdk.types import PermissionResultAllow, PermissionResultDeny
    
    # Permitir que a ferramenta execute
    return PermissionResultAllow(updated_input=input_data)
    
    # Bloquear a ferramenta
    return PermissionResultDeny(message="User rejected this action")

    Além de permitir ou negar, você pode modificar a entrada da ferramenta ou fornecer contexto que ajude Claude a ajustar sua abordagem:

    • Aprovar: deixar a ferramenta executar conforme Claude solicitou
    • Aprovar com alterações: modificar a entrada antes da execução (por exemplo, sanitizar caminhos, adicionar restrições)
    • Rejeitar: bloquear a ferramenta e dizer ao Claude por quê
    • Sugerir alternativa: bloquear mas guiar Claude para o que o usuário quer em vez disso
    • Redirecionar completamente: usar entrada de streaming para enviar ao Claude uma instrução completamente nova

    Lidar com perguntas de esclarecimento

    Quando Claude precisa de mais direção em uma tarefa com múltiplas abordagens válidas, ele chama a ferramenta AskUserQuestion. Isso aciona seu callback canUseTool com toolName definido como AskUserQuestion. A entrada contém as perguntas de Claude como opções de múltipla escolha, que você exibe ao usuário e retorna suas seleções.

    Perguntas de esclarecimento são especialmente comuns no modo plan, onde Claude explora a base de código e faz perguntas antes de propor um plano. Isso torna o modo plan ideal para fluxos de trabalho interativos onde você quer que Claude reúna requisitos antes de fazer alterações.

    Os passos a seguir mostram como lidar com perguntas de esclarecimento:

    Formato de pergunta

    A entrada contém as perguntas geradas por Claude em um array questions. Cada pergunta tem estes campos:

    CampoDescrição
    questionO texto completo da pergunta a exibir
    headerRótulo curto para a pergunta (máximo 12 caracteres)
    optionsArray de 2-4 escolhas, cada uma com label e description
    multiSelectSe true, os usuários podem selecionar múltiplas opções

    Aqui está um exemplo da estrutura que você receberá:

    {
      "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
        }
      ]
    }

    Formato de resposta

    Retorne um objeto answers mapeando cada campo question da pergunta para o label da opção selecionada:

    CampoDescrição
    questionsPassar o array de perguntas original (obrigatório para processamento de ferramenta)
    answersObjeto onde as chaves são texto de pergunta e os valores são labels selecionados

    Para perguntas de seleção múltipla, junte múltiplos labels com ", ". Para entrada de texto livre, use o texto personalizado do usuário diretamente.

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

    Suportar entrada de texto livre

    As opções predefinidas de Claude nem sempre cobrem o que os usuários querem. Para deixar os usuários digitarem sua própria resposta:

    • Exiba uma escolha "Other" adicional após as opções de Claude que aceita entrada de texto
    • Use o texto personalizado do usuário como o valor da resposta (não a palavra "Other")

    Veja o exemplo completo abaixo para uma implementação completa.

    Exemplo completo

    Claude faz perguntas de esclarecimento quando precisa de entrada do usuário para prosseguir. Por exemplo, quando solicitado a ajudar a decidir sobre uma pilha de tecnologia para um aplicativo móvel, Claude pode perguntar sobre multiplataforma vs nativo, preferências de backend ou plataformas alvo. Essas perguntas ajudam Claude a tomar decisões que correspondem às preferências do usuário em vez de adivinhar.

    Este exemplo lida com essas perguntas em um aplicativo de terminal. Aqui está o que acontece em cada etapa:

    1. Rotear a solicitação: O callback canUseTool verifica se o nome da ferramenta é "AskUserQuestion" e roteia para um manipulador dedicado
    2. Exibir perguntas: O manipulador percorre o array questions e imprime cada pergunta com opções numeradas
    3. Coletar entrada: O usuário pode inserir um número para selecionar uma opção ou digitar texto livre diretamente (por exemplo, "jquery", "i don't know")
    4. Mapear respostas: O código verifica se a entrada é numérica (usa o label da opção) ou texto livre (usa o texto diretamente)
    5. Retornar ao Claude: A resposta inclui tanto o array questions original quanto o mapeamento answers

    Limitações

    • Subagentes: AskUserQuestion não está disponível em subagentes gerados via a ferramenta Task
    • Limites de pergunta: cada chamada AskUserQuestion suporta 1-4 perguntas com 2-4 opções cada

    Outras maneiras de obter entrada do usuário

    O callback canUseTool e a ferramenta AskUserQuestion cobrem a maioria dos cenários de aprovação e esclarecimento, mas o SDK oferece outras maneiras de obter entrada dos usuários:

    Entrada de streaming

    Use entrada de streaming quando você precisar:

    • Interromper o agente no meio da tarefa: enviar um sinal de cancelamento ou mudar de direção enquanto Claude está trabalhando
    • Fornecer contexto adicional: adicionar informações que Claude precisa sem esperar que ele pergunte
    • Construir interfaces de chat: deixar os usuários enviarem mensagens de acompanhamento durante operações de longa duração

    Entrada de streaming é ideal para UIs conversacionais onde os usuários interagem com o agente durante toda a execução, não apenas em pontos de aprovação.

    Ferramentas personalizadas

    Use ferramentas personalizadas quando você precisar:

    • Coletar entrada estruturada: construir formulários, assistentes ou fluxos de trabalho de múltiplas etapas que vão além do formato de múltipla escolha de AskUserQuestion
    • Integrar sistemas de aprovação externos: conectar a sistemas de ticketing, fluxo de trabalho ou aprovação existentes
    • Implementar interações específicas do domínio: criar ferramentas adaptadas às necessidades do seu aplicativo, como interfaces de revisão de código ou listas de verificação de implantação

    Ferramentas personalizadas lhe dão controle total sobre a interação, mas requerem mais trabalho de implementação do que usar o callback canUseTool integrado.

    Recursos relacionados

    • Configurar permissões: configurar modos e regras de permissão
    • Controlar execução com hooks: executar código personalizado em pontos-chave do ciclo de vida do agente
    • Referência do SDK TypeScript: documentação completa da API canUseTool
    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:
        # Exibir a solicitação de ferramenta
        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}")
    
        # Obter aprovação do usuário
        response = input("Allow this action? (y/n): ")
    
        # Retornar permitir ou negar com base na resposta do usuário
        if response.lower() == "y":
            # Permitir: ferramenta executa com a entrada original (ou modificada)
            return PermissionResultAllow(updated_input=input_data)
        else:
            # Negar: ferramenta não executa, Claude vê a mensagem
            return PermissionResultDeny(message="User denied this action")
    
    
    # Solução alternativa necessária: hook fictício mantém o stream aberto para 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())
    1. 1

      Passar um callback canUseTool

      Passe um callback canUseTool nas opções de sua consulta. Por padrão, AskUserQuestion está disponível. Se você especificar um array tools para restringir as capacidades do Claude (por exemplo, um agente somente leitura com apenas Read, Glob e Grep), inclua AskUserQuestion nesse array. Caso contrário, Claude não será capaz de fazer perguntas de esclarecimento:

      async for message in query(
          prompt="Analyze this codebase",
          options=ClaudeAgentOptions(
              # Incluir AskUserQuestion na sua lista de ferramentas
              tools=["Read", "Glob", "Grep", "AskUserQuestion"],
              can_use_tool=can_use_tool,
          ),
      ):
          # ...
    2. 2

      Detectar AskUserQuestion

      Em seu callback, verifique se toolName é igual a AskUserQuestion para tratá-lo diferentemente de outras ferramentas:

      async def can_use_tool(tool_name: str, input_data: dict, context):
          if tool_name == "AskUserQuestion":
              # Sua implementação para coletar respostas do usuário
              return await handle_clarifying_questions(input_data)
          # Lidar com outras ferramentas normalmente
          return await prompt_for_approval(tool_name, input_data)
    3. 3

      Analisar a entrada da pergunta

      A entrada contém as perguntas de Claude em um array questions. Cada pergunta tem uma question (o texto a exibir), options (as escolhas) e multiSelect (se múltiplas seleções são permitidas):

      {
        "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
          }
        ]
      }

      Veja Formato de pergunta para descrições completas de campos.

    4. 4

      Coletar respostas do usuário

      Apresente as perguntas ao usuário e colete suas seleções. Como você faz isso depende do seu aplicativo: um prompt de terminal, um formulário web, um diálogo móvel, etc.

    5. 5

      Retornar respostas ao Claude

      Construa o objeto answers como um registro onde cada chave é o texto question e cada valor é o label da opção selecionada:

      Do objeto de perguntaUse como
      Campo question (por exemplo, "How should I format the output?")Chave
      Campo label da opção selecionada (por exemplo, "Summary")Valor

      Para perguntas de seleção múltipla, junte múltiplos labels com ", ". Se você suportar entrada de texto livre, use o texto personalizado do usuário como o valor.

      return PermissionResultAllow(
          updated_input={
              "questions": input_data.get("questions", []),
              "answers": {
                  "How should I format the output?": "Summary",
                  "Which sections should I include?": "Introduction, Conclusion"
              }
          }
      )
    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:
        """Analisar entrada do usuário como número(s) de opção ou texto livre."""
        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:
        """Exibir as perguntas de Claude e coletar respostas do usuário."""
        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:
        # Rotear AskUserQuestion para nosso manipulador de perguntas
        if tool_name == "AskUserQuestion":
            return await handle_ask_user_question(input_data)
        # Auto-aprovar outras ferramentas para este exemplo
        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"},
        }
    
    
    # Solução alternativa necessária: hook fictício mantém o stream aberto para 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())