Loading...
    • Guía para desarrolladores
    • Referencia de API
    • MCP
    • Recursos
    • Notas de la versión
    Search...
    ⌘K
    Primeros pasos
    Introducción a ClaudeInicio rápido
    Modelos y precios
    Descripción general de modelosElegir un modeloNovedades en Claude 4.6Guía de migraciónModelos deprecadosPrecios
    Crear con Claude
    Descripción general de característicasUsar la API de MessagesManejar razones de paradaMejores prácticas de prompting
    Gestión de contexto
    Ventanas de contextoCompactaciónEdición de contexto
    Capacidades
    Almacenamiento en caché de promptsPensamiento extendidoPensamiento adaptativoEsfuerzoStreaming de MessagesProcesamiento por lotesCitasSoporte multilingüeConteo de tokensEmbeddingsVisiónSoporte de PDFAPI de FilesResultados de búsquedaSalidas estructuradas
    Herramientas
    Descripción generalCómo implementar el uso de herramientasStreaming de herramientas de grano finoHerramienta BashHerramienta de ejecución de códigoLlamada de herramientas programáticaHerramienta de uso de computadoraHerramienta de editor de textoHerramienta de búsqueda webHerramienta de búsqueda webHerramienta de memoriaHerramienta de búsqueda de herramientas
    Agent Skills
    Descripción generalInicio rápidoMejores prácticasSkills para empresasUsar Skills con la API
    Agent SDK
    Descripción generalInicio rápidoSDK de TypeScriptTypeScript V2 (vista previa)SDK de PythonGuía de migración
    Entrada de streamingTransmitir respuestas en tiempo realManejar razones de paradaManejar permisosAprobaciones de usuario e entradaControlar la ejecución con hooksGestión de sesionesPunto de control de archivosSalidas estructuradas en el SDKAlojar el Agent SDKDesplegar agentes de IA de forma seguraModificar prompts del sistemaMCP en el SDKHerramientas personalizadasSubagentes en el SDKComandos de barra en el SDKAgent Skills en el SDKRastrear costos y usoListas de tareasPlugins en el SDK
    MCP en la API
    Conector MCPServidores MCP remotos
    Claude en plataformas de terceros
    Amazon BedrockMicrosoft FoundryVertex AI
    Ingeniería de prompts
    Descripción generalGenerador de promptsUsar plantillas de promptsMejorador de promptsSer claro y directoUsar ejemplos (prompting multishot)Dejar que Claude piense (CoT)Usar etiquetas XMLDar a Claude un rol (prompts del sistema)Encadenar prompts complejosConsejos de contexto largoConsejos de pensamiento extendido
    Probar y evaluar
    Definir criterios de éxitoDesarrollar casos de pruebaUsar la herramienta de evaluaciónReducir latencia
    Fortalecer protecciones
    Reducir alucinacionesAumentar consistencia de salidaMitigar ataques de jailbreakRechazos de streamingReducir fuga de promptsMantener a Claude en personaje
    Administración y monitoreo
    Descripción general de Admin APIResidencia de datosEspacios de trabajoAPI de uso y costosAPI de Claude Code AnalyticsRetención de datos cero
    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
    Guías

    Manejar aprobaciones e entrada del usuario

    Presenta las solicitudes de aprobación y preguntas aclaratorias de Claude a los usuarios, luego devuelve sus decisiones al SDK.

    Mientras trabaja en una tarea, Claude a veces necesita consultar con los usuarios. Podría necesitar permiso antes de eliminar archivos, o necesitar preguntar qué base de datos usar para un nuevo proyecto. Tu aplicación necesita presentar estas solicitudes a los usuarios para que Claude pueda continuar con su entrada.

    Claude solicita entrada del usuario en dos situaciones: cuando necesita permiso para usar una herramienta (como eliminar archivos o ejecutar comandos), y cuando tiene preguntas aclaratorias (a través de la herramienta AskUserQuestion). Ambas activan tu callback canUseTool, que pausa la ejecución hasta que devuelvas una respuesta. Esto es diferente de los turnos de conversación normales donde Claude termina y espera tu próximo mensaje.

    Para preguntas aclaratorias, Claude genera las preguntas y opciones. Tu rol es presentarlas a los usuarios y devolver sus selecciones. No puedes agregar tus propias preguntas a este flujo; si necesitas preguntarle algo a los usuarios tú mismo, hazlo por separado en la lógica de tu aplicación.

    Esta guía te muestra cómo detectar cada tipo de solicitud y responder apropiadamente.

    Detectar cuándo Claude necesita entrada

    Pasa un callback canUseTool en tus opciones de consulta. El callback se activa siempre que Claude necesita entrada del usuario, recibiendo el nombre de la herramienta y la entrada como argumentos:

    async def handle_tool_request(tool_name, input_data, context):
        # Solicita al usuario y devuelve permitir o denegar
        ...
    
    options = ClaudeAgentOptions(can_use_tool=handle_tool_request)

    El callback se activa en dos casos:

    1. La herramienta necesita aprobación: Claude quiere usar una herramienta que no está aprobada automáticamente por reglas de permiso o modos. Verifica tool_name para la herramienta (por ejemplo, "Bash", "Write").
    2. Claude hace una pregunta: Claude llama a la herramienta AskUserQuestion. Verifica si tool_name == "AskUserQuestion" para manejarlo de manera diferente. Si especificas un array tools, incluye AskUserQuestion para que esto funcione. Consulta Manejar preguntas aclaratorias para más detalles.

    Para permitir o denegar herramientas automáticamente sin solicitar a los usuarios, usa hooks en su lugar. Los hooks se ejecutan antes de canUseTool y pueden permitir, denegar o modificar solicitudes basadas en tu propia lógica. También puedes usar el hook PermissionRequest para enviar notificaciones externas (Slack, correo electrónico, push) cuando Claude está esperando aprobación.

    Manejar solicitudes de aprobación de herramientas

    Una vez que hayas pasado un callback canUseTool en tus opciones de consulta, se activa cuando Claude quiere usar una herramienta que no está aprobada automáticamente. Tu callback recibe dos argumentos:

    ArgumentoDescripción
    toolNameEl nombre de la herramienta que Claude quiere usar (por ejemplo, "Bash", "Write", "Edit")
    inputLos parámetros que Claude está pasando a la herramienta. El contenido varía según la herramienta.

    El objeto input contiene parámetros específicos de la herramienta. Ejemplos comunes:

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

    Consulta la referencia del SDK para esquemas de entrada completos: Python | TypeScript.

    Puedes mostrar esta información al usuario para que pueda decidir si permitir o rechazar la acción, luego devuelve la respuesta apropiada.

    El siguiente ejemplo le pide a Claude que cree y elimine un archivo de prueba. Cuando Claude intenta cada operación, el callback imprime la solicitud de herramienta en la terminal y solicita aprobación s/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:
        # Muestra la solicitud de herramienta
        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}")
    
        # Obtén aprobación del usuario
        response = input("Allow this action? (y/n): ")
    
        # Devuelve permitir o denegar basado en la respuesta del usuario
        if response.lower() == "y":
            # Permitir: la herramienta se ejecuta con la entrada original (o modificada)
            return PermissionResultAllow(updated_input=input_data)
        else:
            # Denegar: la herramienta no se ejecuta, Claude ve el mensaje
            return PermissionResultDeny(message="User denied this action")
    
    
    # Solución requerida: hook ficticio mantiene el flujo abierto 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())

    En Python, can_use_tool requiere modo de flujo y un hook PreToolUse que devuelva {"continue_": True} para mantener el flujo abierto. Sin este hook, el flujo se cierra antes de que se pueda invocar el callback de permiso.

    Este ejemplo usa un flujo s/n donde cualquier entrada que no sea y se trata como una denegación. En la práctica, podrías construir una interfaz de usuario más rica que permita a los usuarios modificar la solicitud, proporcionar retroalimentación o redirigir a Claude completamente. Consulta Responder a solicitudes de herramientas para todas las formas en que puedes responder.

    Responder a solicitudes de herramientas

    Tu callback devuelve uno de dos tipos de respuesta:

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

    Al permitir, pasa la entrada de la herramienta (original o modificada). Al denegar, proporciona un mensaje explicando por qué. Claude ve este mensaje y puede ajustar su enfoque.

    from claude_agent_sdk.types import PermissionResultAllow, PermissionResultDeny
    
    # Permite que la herramienta se ejecute
    return PermissionResultAllow(updated_input=input_data)
    
    # Bloquea la herramienta
    return PermissionResultDeny(message="User rejected this action")

    Más allá de permitir o denegar, puedes modificar la entrada de la herramienta o proporcionar contexto que ayude a Claude a ajustar su enfoque:

    • Aprobar: permite que la herramienta se ejecute como Claude solicitó
    • Aprobar con cambios: modifica la entrada antes de la ejecución (por ejemplo, desinfecta rutas, agrega restricciones)
    • Rechazar: bloquea la herramienta y dile a Claude por qué
    • Sugerir alternativa: bloquea pero guía a Claude hacia lo que el usuario quiere en su lugar
    • Redirigir completamente: usa entrada de flujo para enviar a Claude una instrucción completamente nueva

    Manejar preguntas aclaratorias

    Cuando Claude necesita más dirección en una tarea con múltiples enfoques válidos, llama a la herramienta AskUserQuestion. Esto activa tu callback canUseTool con toolName establecido en AskUserQuestion. La entrada contiene las preguntas de Claude como opciones de opción múltiple, que muestras al usuario y devuelves sus selecciones.

    Las preguntas aclaratorias son especialmente comunes en modo plan, donde Claude explora la base de código y hace preguntas antes de proponer un plan. Esto hace que el modo plan sea ideal para flujos de trabajo interactivos donde quieres que Claude recopile requisitos antes de hacer cambios.

    Los siguientes pasos muestran cómo manejar preguntas aclaratorias:

    1. 1

      Pasar un callback canUseTool

      Pasa un callback canUseTool en tus opciones de consulta. Por defecto, AskUserQuestion está disponible. Si especificas un array tools para restringir las capacidades de Claude (por ejemplo, un agente de solo lectura con solo Read, Glob y Grep), incluye AskUserQuestion en ese array. De lo contrario, Claude no podrá hacer preguntas aclaratorias:

      async for message in query(
          prompt="Analyze this codebase",
          options=ClaudeAgentOptions(
              # Incluye AskUserQuestion en tu lista de herramientas
              tools=["Read", "Glob", "Grep", "AskUserQuestion"],
              can_use_tool=can_use_tool,
          ),
      ):
          # ...
    2. 2

      Detectar AskUserQuestion

      En tu callback, verifica si toolName es igual a AskUserQuestion para manejarlo de manera diferente a otras herramientas:

      async def can_use_tool(tool_name: str, input_data: dict, context):
          if tool_name == "AskUserQuestion":
              # Tu implementación para recopilar respuestas del usuario
              return await handle_clarifying_questions(input_data)
          # Maneja otras herramientas normalmente
          return await prompt_for_approval(tool_name, input_data)
    3. 3

      Analizar la entrada de la pregunta

      La entrada contiene las preguntas de Claude en un array questions. Cada pregunta tiene una question (el texto a mostrar), options (las opciones) y multiSelect (si se permiten múltiples selecciones):

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

      Consulta Formato de pregunta para descripciones completas de campos.

    4. 4

      Recopilar respuestas del usuario

      Presenta las preguntas al usuario y recopila sus selecciones. Cómo lo hagas depende de tu aplicación: un aviso de terminal, un formulario web, un diálogo móvil, etc.

    5. 5

      Devolver respuestas a Claude

      Construye el objeto answers como un registro donde cada clave es el texto de question y cada valor es el label de la opción seleccionada:

      Del objeto de preguntaUsar como
      Campo question (por ejemplo, "How should I format the output?")Clave
      Campo label de la opción seleccionada (por ejemplo, "Summary")Valor

      Para preguntas de selección múltiple, une múltiples etiquetas con ", ". Si admites entrada de texto libre, usa el texto personalizado del usuario como 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"
              }
          }
      )

    Formato de pregunta

    La entrada contiene las preguntas generadas por Claude en un array questions. Cada pregunta tiene estos campos:

    CampoDescripción
    questionEl texto completo de la pregunta a mostrar
    headerEtiqueta corta para la pregunta (máximo 12 caracteres)
    optionsArray de 2-4 opciones, cada una con label y description
    multiSelectSi es true, los usuarios pueden seleccionar múltiples opciones

    Aquí hay un ejemplo de la estructura que recibirás:

    {
      "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 respuesta

    Devuelve un objeto answers que mapee cada campo question de la pregunta al label de la opción seleccionada:

    CampoDescripción
    questionsPasa el array de preguntas original (requerido para procesamiento de herramientas)
    answersObjeto donde las claves son texto de pregunta y los valores son etiquetas seleccionadas

    Para preguntas de selección múltiple, une múltiples etiquetas con ", ". Para entrada de texto libre, usa el texto personalizado del usuario directamente.

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

    Admitir entrada de texto libre

    Las opciones predefinidas de Claude no siempre cubrirán lo que los usuarios quieren. Para permitir que los usuarios escriban su propia respuesta:

    • Muestra una opción adicional "Otro" después de las opciones de Claude que acepte entrada de texto
    • Usa el texto personalizado del usuario como valor de respuesta (no la palabra "Otro")

    Consulta el ejemplo completo a continuación para una implementación completa.

    Ejemplo completo

    Claude hace preguntas aclaratorias cuando necesita entrada del usuario para proceder. Por ejemplo, cuando se le pide que ayude a decidir sobre una pila de tecnología para una aplicación móvil, Claude podría preguntar sobre multiplataforma vs nativo, preferencias de backend o plataformas objetivo. Estas preguntas ayudan a Claude a tomar decisiones que coincidan con las preferencias del usuario en lugar de adivinar.

    Este ejemplo maneja esas preguntas en una aplicación de terminal. Aquí está lo que sucede en cada paso:

    1. Enrutar la solicitud: El callback canUseTool verifica si el nombre de la herramienta es "AskUserQuestion" y enruta a un manejador dedicado
    2. Mostrar preguntas: El manejador recorre el array questions e imprime cada pregunta con opciones numeradas
    3. Recopilar entrada: El usuario puede ingresar un número para seleccionar una opción, o escribir texto libre directamente (por ejemplo, "jquery", "no sé")
    4. Mapear respuestas: El código verifica si la entrada es numérica (usa la etiqueta de la opción) o texto libre (usa el texto directamente)
    5. Devolver a Claude: La respuesta incluye tanto el array questions original como el mapeo 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:
        """Analiza la entrada del usuario como número(s) de opción o texto libre."""
        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:
        """Muestra las preguntas de Claude y recopila respuestas del usuario."""
        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:
        # Enruta AskUserQuestion a nuestro manejador de preguntas
        if tool_name == "AskUserQuestion":
            return await handle_ask_user_question(input_data)
        # Aprueba automáticamente otras herramientas para este ejemplo
        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"},
        }
    
    
    # Solución requerida: hook ficticio mantiene el flujo abierto 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())

    Limitaciones

    • Subagentos: AskUserQuestion no está disponible actualmente en subagentos generados a través de la herramienta Task
    • Límites de preguntas: cada llamada a AskUserQuestion admite 1-4 preguntas con 2-4 opciones cada una

    Otras formas de obtener entrada del usuario

    El callback canUseTool y la herramienta AskUserQuestion cubren la mayoría de escenarios de aprobación y aclaración, pero el SDK ofrece otras formas de obtener entrada de los usuarios:

    Entrada de flujo

    Usa entrada de flujo cuando necesites:

    • Interrumpir el agente a mitad de tarea: envía una señal de cancelación o cambia de dirección mientras Claude está trabajando
    • Proporcionar contexto adicional: agrega información que Claude necesita sin esperar a que la solicite
    • Construir interfaces de chat: permite que los usuarios envíen mensajes de seguimiento durante operaciones de larga duración

    La entrada de flujo es ideal para interfaces conversacionales donde los usuarios interactúan con el agente durante toda la ejecución, no solo en puntos de aprobación.

    Herramientas personalizadas

    Usa herramientas personalizadas cuando necesites:

    • Recopilar entrada estructurada: construye formularios, asistentes o flujos de trabajo de múltiples pasos que vayan más allá del formato de opción múltiple de AskUserQuestion
    • Integrar sistemas de aprobación externos: conecta a sistemas de ticketing, flujo de trabajo o plataformas de aprobación existentes
    • Implementar interacciones específicas del dominio: crea herramientas adaptadas a las necesidades de tu aplicación, como interfaces de revisión de código o listas de verificación de implementación

    Las herramientas personalizadas te dan control total sobre la interacción, pero requieren más trabajo de implementación que usar el callback canUseTool incorporado.

    Recursos relacionados

    • Configurar permisos: configura modos y reglas de permiso
    • Controlar la ejecución con hooks: ejecuta código personalizado en puntos clave del ciclo de vida del agente
    • Referencia del SDK de TypeScript: documentación completa de la API canUseTool

    Was this page helpful?

    • Detectar cuándo Claude necesita entrada
    • Manejar solicitudes de aprobación de herramientas
    • Responder a solicitudes de herramientas
    • Manejar preguntas aclaratorias
    • Formato de pregunta
    • Formato de respuesta
    • Ejemplo completo
    • Limitaciones
    • Otras formas de obtener entrada del usuario
    • Entrada de flujo
    • Herramientas personalizadas
    • Recursos relacionados