Loading...
    • Guide du développeur
    • Référence API
    • MCP
    • Ressources
    • Notes de version
    Search...
    ⌘K
    Premiers pas
    Introduction à ClaudeDémarrage rapide
    Modèles et tarification
    Aperçu des modèlesChoisir un modèleNouveautés dans Claude 4.6Guide de migrationDépréciation des modèlesTarification
    Créer avec Claude
    Aperçu des fonctionnalitésUtiliser l'API MessagesGérer les raisons d'arrêtMeilleures pratiques de prompting
    Gestion du contexte
    Fenêtres de contexteCompactionÉdition du contexte
    Capacités
    Mise en cache des promptsRéflexion étendueRéflexion adaptativeEffortStreaming de messagesTraitement par lotsCitationsSupport multilingueComptage des tokensEmbeddingsVisionSupport PDFAPI FilesRésultats de rechercheSorties structurées
    Outils
    AperçuComment implémenter l'utilisation d'outilsStreaming d'outils granulaireOutil BashOutil d'exécution de codeAppel d'outils programmatiqueOutil Computer useOutil Éditeur de texteOutil Web fetchOutil Web searchOutil MémoireOutil Tool search
    Compétences d'agent
    AperçuDémarrage rapideMeilleures pratiquesCompétences pour l'entrepriseUtiliser les compétences avec l'API
    SDK Agent
    AperçuDémarrage rapideSDK TypeScriptTypeScript V2 (aperçu)SDK PythonGuide de migration
    Streaming d'entréeDiffuser les réponses en temps réelGérer les raisons d'arrêtGérer les permissionsApprobations et entrées utilisateurContrôler l'exécution avec des hooksGestion des sessionsSauvegarde de fichiersSorties structurées dans le SDKHéberger le SDK AgentDéployer les agents IA de manière sécuriséeModifier les prompts systèmeMCP dans le SDKOutils personnalisésSous-agents dans le SDKCommandes slash dans le SDKCompétences d'agent dans le SDKSuivi des coûts et de l'utilisationListes de tâchesPlugins dans le SDK
    MCP dans l'API
    Connecteur MCPServeurs MCP distants
    Claude sur les plateformes tierces
    Amazon BedrockMicrosoft FoundryVertex AI
    Ingénierie des prompts
    AperçuGénérateur de promptsUtiliser les modèles de promptsAméliorateur de promptsÊtre clair et directUtiliser des exemples (prompting multi-coups)Laisser Claude réfléchir (CoT)Utiliser les balises XMLDonner un rôle à Claude (prompts système)Enchaîner les prompts complexesConseils pour le contexte longConseils pour la réflexion étendue
    Tester et évaluer
    Définir les critères de succèsDévelopper des cas de testUtiliser l'outil d'évaluationRéduire la latence
    Renforcer les garde-fous
    Réduire les hallucinationsAugmenter la cohérence des résultatsAtténuer les jailbreaksRefus en streamingRéduire les fuites de promptsGarder Claude dans le rôle
    Administration et surveillance
    Aperçu de l'API AdminRésidence des donnéesEspaces de travailAPI d'utilisation et de coûtsAPI Claude Code AnalyticsRétention zéro des données
    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
    Guides

    Gérer les approbations et les entrées utilisateur

    Présentez les demandes d'approbation et les questions de clarification de Claude aux utilisateurs, puis renvoyez leurs décisions au SDK.

    Was this page helpful?

    • Détecter quand Claude a besoin d'une entrée
    • Gérer les demandes d'approbation d'outil
    • Répondre aux demandes d'outil
    • Gérer les questions de clarification
    • Format de question
    • Format de réponse
    • Exemple complet
    • Limitations
    • Autres façons d'obtenir une entrée utilisateur
    • Entrée streaming
    • Outils personnalisés
    • Ressources connexes

    Lors du travail sur une tâche, Claude a parfois besoin de vérifier auprès des utilisateurs. Il peut avoir besoin d'une permission avant de supprimer des fichiers, ou avoir besoin de demander quelle base de données utiliser pour un nouveau projet. Votre application doit présenter ces demandes aux utilisateurs afin que Claude puisse continuer avec leurs entrées.

    Claude demande une entrée utilisateur dans deux situations : lorsqu'il a besoin d'une permission pour utiliser un outil (comme supprimer des fichiers ou exécuter des commandes), et lorsqu'il a des questions de clarification (via l'outil AskUserQuestion). Les deux déclenchent votre rappel canUseTool, qui met en pause l'exécution jusqu'à ce que vous renvoyiez une réponse. C'est différent des tours de conversation normaux où Claude termine et attend votre prochain message.

    Pour les questions de clarification, Claude génère les questions et les options. Votre rôle est de les présenter aux utilisateurs et de retourner leurs sélections. Vous ne pouvez pas ajouter vos propres questions à ce flux ; si vous avez besoin de poser une question aux utilisateurs vous-même, faites-le séparément dans votre logique d'application.

    Ce guide vous montre comment détecter chaque type de demande et répondre de manière appropriée.

    Détecter quand Claude a besoin d'une entrée

    Passez un rappel canUseTool dans vos options de requête. Le rappel se déclenche chaque fois que Claude a besoin d'une entrée utilisateur, en recevant le nom de l'outil et l'entrée comme arguments :

    async def handle_tool_request(tool_name, input_data, context):
        # Demander à l'utilisateur et retourner autoriser ou refuser
        ...
    
    options = ClaudeAgentOptions(can_use_tool=handle_tool_request)

    Le rappel se déclenche dans deux cas :

    1. L'outil a besoin d'approbation : Claude veut utiliser un outil qui n'est pas auto-approuvé par les règles de permission ou les modes. Vérifiez tool_name pour l'outil (par exemple, "Bash", "Write").
    2. Claude pose une question : Claude appelle l'outil AskUserQuestion. Vérifiez si tool_name == "AskUserQuestion" pour le gérer différemment. Si vous spécifiez un tableau tools, incluez AskUserQuestion pour que cela fonctionne. Voir Gérer les questions de clarification pour plus de détails.

    Pour autoriser ou refuser automatiquement les outils sans inviter les utilisateurs, utilisez plutôt les hooks. Les hooks s'exécutent avant canUseTool et peuvent autoriser, refuser ou modifier les demandes en fonction de votre propre logique. Vous pouvez également utiliser le hook PermissionRequest pour envoyer des notifications externes (Slack, e-mail, push) lorsque Claude attend une approbation.

    Gérer les demandes d'approbation d'outil

    Une fois que vous avez passé un rappel canUseTool dans vos options de requête, il se déclenche lorsque Claude veut utiliser un outil qui n'est pas auto-approuvé. Votre rappel reçoit deux arguments :

    ArgumentDescription
    toolNameLe nom de l'outil que Claude veut utiliser (par exemple, "Bash", "Write", "Edit")
    inputLes paramètres que Claude passe à l'outil. Le contenu varie selon l'outil.

    L'objet input contient des paramètres spécifiques à l'outil. Exemples courants :

    OutilChamps d'entrée
    Bashcommand, description, timeout
    Writefile_path, content
    Editfile_path, old_string, new_string
    Readfile_path, offset, limit

    Consultez la référence du SDK pour les schémas d'entrée complets : Python | TypeScript.

    Vous pouvez afficher ces informations à l'utilisateur afin qu'il puisse décider d'autoriser ou de rejeter l'action, puis retourner la réponse appropriée.

    L'exemple suivant demande à Claude de créer et de supprimer un fichier de test. Lorsque Claude tente chaque opération, le rappel imprime la demande d'outil sur le terminal et demande une approbation o/n.

    En Python, can_use_tool nécessite le mode streaming et un hook PreToolUse qui retourne {"continue_": True} pour garder le flux ouvert. Sans ce hook, le flux se ferme avant que le rappel de permission puisse être invoqué.

    Cet exemple utilise un flux o/n où toute entrée autre que o est traitée comme un refus. En pratique, vous pourriez construire une interface utilisateur plus riche qui permet aux utilisateurs de modifier la demande, de fournir des commentaires ou de rediriger Claude entièrement. Voir Répondre aux demandes d'outil pour tous les moyens de répondre.

    Répondre aux demandes d'outil

    Votre rappel retourne l'un de deux types de réponse :

    RéponsePythonTypeScript
    AutoriserPermissionResultAllow(updated_input=...){ behavior: "allow", updatedInput }
    RefuserPermissionResultDeny(message=...){ behavior: "deny", message }

    Lors de l'autorisation, passez l'entrée de l'outil (originale ou modifiée). Lors du refus, fournissez un message expliquant pourquoi. Claude voit ce message et peut ajuster son approche.

    from claude_agent_sdk.types import PermissionResultAllow, PermissionResultDeny
    
    # Autoriser l'outil à s'exécuter
    return PermissionResultAllow(updated_input=input_data)
    
    # Bloquer l'outil
    return PermissionResultDeny(message="User rejected this action")

    Au-delà d'autoriser ou de refuser, vous pouvez modifier l'entrée de l'outil ou fournir un contexte qui aide Claude à ajuster son approche :

    • Approuver : laisser l'outil s'exécuter comme Claude l'a demandé
    • Approuver avec des modifications : modifier l'entrée avant l'exécution (par exemple, assainir les chemins, ajouter des contraintes)
    • Rejeter : bloquer l'outil et dire à Claude pourquoi
    • Suggérer une alternative : bloquer mais guider Claude vers ce que l'utilisateur veut à la place
    • Rediriger entièrement : utiliser l'entrée streaming pour envoyer à Claude une instruction complètement nouvelle

    Gérer les questions de clarification

    Lorsque Claude a besoin de plus de direction sur une tâche avec plusieurs approches valides, il appelle l'outil AskUserQuestion. Cela déclenche votre rappel canUseTool avec toolName défini sur AskUserQuestion. L'entrée contient les questions de Claude sous forme d'options à choix multiples, que vous affichez à l'utilisateur et retournez ses sélections.

    Les questions de clarification sont particulièrement courantes en mode plan, où Claude explore la base de code et pose des questions avant de proposer un plan. Cela rend le mode plan idéal pour les flux de travail interactifs où vous voulez que Claude rassemble les exigences avant de faire des modifications.

    Les étapes suivantes montrent comment gérer les questions de clarification :

    Format de question

    L'entrée contient les questions générées par Claude dans un tableau questions. Chaque question a ces champs :

    ChampDescription
    questionLe texte complet de la question à afficher
    headerÉtiquette courte pour la question (max 12 caractères)
    optionsTableau de 2-4 choix, chacun avec label et description
    multiSelectSi true, les utilisateurs peuvent sélectionner plusieurs options

    Voici un exemple de la structure que vous recevrez :

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

    Format de réponse

    Retournez un objet answers mappant le champ question de chaque question au label de l'option sélectionnée :

    ChampDescription
    questionsPassez le tableau de questions original (requis pour le traitement de l'outil)
    answersObjet où les clés sont le texte de la question et les valeurs sont les labels sélectionnés

    Pour les questions à sélection multiple, joignez plusieurs labels avec ", ". Pour l'entrée de texte libre, utilisez le texte personnalisé de l'utilisateur directement.

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

    Supporter l'entrée de texte libre

    Les options prédéfinies de Claude ne couvriront pas toujours ce que les utilisateurs veulent. Pour permettre aux utilisateurs de taper leur propre réponse :

    • Affichez un choix "Autre" supplémentaire après les options de Claude qui accepte l'entrée de texte
    • Utilisez le texte personnalisé de l'utilisateur comme valeur de réponse (pas le mot "Autre")

    Voir l'exemple complet ci-dessous pour une implémentation complète.

    Exemple complet

    Claude pose des questions de clarification lorsqu'il a besoin d'une entrée utilisateur pour continuer. Par exemple, lorsqu'on lui demande d'aider à décider d'une pile technologique pour une application mobile, Claude peut poser des questions sur le cross-plateforme par rapport au natif, les préférences de backend ou les plates-formes cibles. Ces questions aident Claude à prendre des décisions qui correspondent aux préférences de l'utilisateur plutôt que de deviner.

    Cet exemple gère ces questions dans une application de terminal. Voici ce qui se passe à chaque étape :

    1. Router la demande : Le rappel canUseTool vérifie si le nom de l'outil est "AskUserQuestion" et route vers un gestionnaire dédié
    2. Afficher les questions : Le gestionnaire boucle sur le tableau questions et imprime chaque question avec des options numérotées
    3. Collecter l'entrée : L'utilisateur peut entrer un numéro pour sélectionner une option, ou taper du texte libre directement (par exemple, "jquery", "i don't know")
    4. Mapper les réponses : Le code vérifie si l'entrée est numérique (utilise le label de l'option) ou du texte libre (utilise le texte directement)
    5. Retourner à Claude : La réponse inclut à la fois le tableau questions original et le mapping answers

    Limitations

    • Sous-agents : AskUserQuestion n'est actuellement pas disponible dans les sous-agents générés via l'outil Task
    • Limites de questions : chaque appel AskUserQuestion supporte 1-4 questions avec 2-4 options chacune

    Autres façons d'obtenir une entrée utilisateur

    Le rappel canUseTool et l'outil AskUserQuestion couvrent la plupart des scénarios d'approbation et de clarification, mais le SDK offre d'autres façons d'obtenir une entrée des utilisateurs :

    Entrée streaming

    Utilisez l'entrée streaming lorsque vous avez besoin de :

    • Interrompre l'agent en milieu de tâche : envoyer un signal d'annulation ou changer de direction pendant que Claude travaille
    • Fournir un contexte supplémentaire : ajouter des informations dont Claude a besoin sans attendre qu'il les demande
    • Construire des interfaces de chat : permettre aux utilisateurs d'envoyer des messages de suivi pendant les opérations longues

    L'entrée streaming est idéale pour les interfaces conversationnelles où les utilisateurs interagissent avec l'agent tout au long de l'exécution, pas seulement aux points d'approbation.

    Outils personnalisés

    Utilisez les outils personnalisés lorsque vous avez besoin de :

    • Collecter une entrée structurée : construire des formulaires, des assistants ou des flux de travail multi-étapes qui vont au-delà du format à choix multiples de AskUserQuestion
    • Intégrer des systèmes d'approbation externes : se connecter à des plates-formes de ticketing, de flux de travail ou d'approbation existantes
    • Implémenter des interactions spécifiques au domaine : créer des outils adaptés aux besoins de votre application, comme des interfaces d'examen de code ou des listes de contrôle de déploiement

    Les outils personnalisés vous donnent un contrôle total sur l'interaction, mais nécessitent plus de travail d'implémentation que d'utiliser le rappel canUseTool intégré.

    Ressources connexes

    • Configurer les permissions : configurer les modes et les règles de permission
    • Contrôler l'exécution avec les hooks : exécuter du code personnalisé à des points clés du cycle de vie de l'agent
    • Référence du SDK TypeScript : documentation complète de l'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:
        # Afficher la demande d'outil
        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}")
    
        # Obtenir l'approbation de l'utilisateur
        response = input("Allow this action? (y/n): ")
    
        # Retourner autoriser ou refuser en fonction de la réponse de l'utilisateur
        if response.lower() == "y":
            # Autoriser : l'outil s'exécute avec l'entrée originale (ou modifiée)
            return PermissionResultAllow(updated_input=input_data)
        else:
            # Refuser : l'outil ne s'exécute pas, Claude voit le message
            return PermissionResultDeny(message="User denied this action")
    
    
    # Contournement requis : un hook factice garde le flux ouvert pour 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

      Passer un rappel canUseTool

      Passez un rappel canUseTool dans vos options de requête. Par défaut, AskUserQuestion est disponible. Si vous spécifiez un tableau tools pour restreindre les capacités de Claude (par exemple, un agent en lecture seule avec seulement Read, Glob et Grep), incluez AskUserQuestion dans ce tableau. Sinon, Claude ne pourra pas poser de questions de clarification :

      async for message in query(
          prompt="Analyze this codebase",
          options=ClaudeAgentOptions(
              # Inclure AskUserQuestion dans votre liste d'outils
              tools=["Read", "Glob", "Grep", "AskUserQuestion"],
              can_use_tool=can_use_tool,
          ),
      ):
          # ...
    2. 2

      Détecter AskUserQuestion

      Dans votre rappel, vérifiez si toolName est égal à AskUserQuestion pour le gérer différemment des autres outils :

      async def can_use_tool(tool_name: str, input_data: dict, context):
          if tool_name == "AskUserQuestion":
              # Votre implémentation pour collecter les réponses de l'utilisateur
              return await handle_clarifying_questions(input_data)
          # Gérer les autres outils normalement
          return await prompt_for_approval(tool_name, input_data)
    3. 3

      Analyser l'entrée de la question

      L'entrée contient les questions de Claude dans un tableau questions. Chaque question a une question (le texte à afficher), des options (les choix) et multiSelect (si plusieurs sélections sont autorisées) :

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

      Voir Format de question pour les descriptions complètes des champs.

    4. 4

      Collecter les réponses de l'utilisateur

      Présentez les questions à l'utilisateur et collectez ses sélections. La façon dont vous le faites dépend de votre application : une invite de terminal, un formulaire web, une boîte de dialogue mobile, etc.

    5. 5

      Retourner les réponses à Claude

      Construisez l'objet answers comme un enregistrement où chaque clé est le texte de question et chaque valeur est le label de l'option sélectionnée :

      De l'objet questionUtiliser comme
      Champ question (par exemple, "How should I format the output?")Clé
      Champ label de l'option sélectionnée (par exemple, "Summary")Valeur

      Pour les questions à sélection multiple, joignez plusieurs labels avec ", ". Si vous supportez l'entrée de texte libre, utilisez le texte personnalisé de l'utilisateur comme valeur.

      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:
        """Analyser l'entrée de l'utilisateur comme numéro(s) d'option ou texte 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:
        """Afficher les questions de Claude et collecter les réponses de l'utilisateur."""
        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:
        # Router AskUserQuestion vers notre gestionnaire de questions
        if tool_name == "AskUserQuestion":
            return await handle_ask_user_question(input_data)
        # Auto-approuver les autres outils pour cet exemple
        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"},
        }
    
    
    # Contournement requis : un hook factice garde le flux ouvert pour 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())