AI Agents Claude

Claude Tool Use : Comment Je Donne des Capacités Réelles à Mes Agents IA

Alejandro Rioja
Alejandro Rioja
12 min de lecture
TL;DR

Claude tool use permet à votre agent de prendre des actions — pas seulement de générer du texte. Vous définissez des outils sous forme de schémas JSON, Claude décide quand les appeler, et votre code exécute l'action dans le monde réel. La boucle comprend trois étapes : envoyer un message → recevoir un bloc tool_use → exécuter et retourner le résultat. J'ai déployé ce pattern dans 15+ agents de production sur Cloudflare Workers. Le point de défaillance n'est presque jamais l'IA — ce sont les résultats ambigus qui reviennent des outils.

Newsletter gratuite

Chaque mercredi. 28 400+ opérateurs. Zéro superflu.

Table des matières

Mis à jour juillet 2026.

TL;DR : Claude tool use permet à votre agent de prendre des actions — pas seulement de générer du texte. Vous définissez des outils sous forme de schémas JSON, Claude décide quand les appeler, et votre code exécute l’action dans le monde réel. La boucle comprend trois étapes : envoyer un message → recevoir un bloc tool_use → exécuter et retourner le résultat. J’ai déployé ce pattern dans 15+ agents de production sur Cloudflare Workers. Le point de défaillance n’est presque jamais l’IA — ce sont les résultats ambigus qui reviennent des outils.

[Note de l’opérateur] Je gère 30+ agents IA en production entre une marque de conseil et Pickleland, une installation de pickleball à Pflugerville, TX. Environ la moitié utilise le tool use — la fonctionnalité de l’API Claude qui permet au modèle d’appeler des fonctions définies dans votre code. Voici le pattern sur lequel j’ai convergé après avoir déployé et itéré en production.

Pourquoi le tool use change ce qu’un agent peut faire

Sans outils, un agent ne peut que générer du texte. C’est utile pour la synthèse, la rédaction et la classification — mais ce n’est pas ce que la plupart des automatisations métier nécessitent vraiment. Les automatisations métier ont besoin de chercher des informations, d’écrire dans des bases de données, d’appeler des API, d’envoyer des messages.

Le tool use est la façon dont vous donnez cet accès à Claude. Vous définissez un ensemble d’outils sous forme de schémas JSON. Claude lit les schémas, décide quel outil appeler et avec quels arguments, et retourne un bloc de contenu tool_use structuré. Votre code exécute la fonction réelle. Claude obtient le résultat et décide quoi faire ensuite — y compris appeler un autre outil ou produire une réponse textuelle finale.

La clé : Claude décide quand et si appeler un outil. Vous définissez les capacités. Le modèle raisonne sur le moment de les utiliser.

Comment fonctionne le flux d’API

La boucle de tool use comporte trois étapes. Vous exécuterez cette boucle une ou plusieurs fois selon le nombre d’appels d’outils effectués par le modèle.

Étape 1 : Envoyez votre message avec les outils définis

typescript
const response = await anthropic.messages.create({
  model: "claude-haiku-4-5-20251001",
  max_tokens: 1024,
  tools: [
    {
      name: "check_court_availability",
      description:
        "Check if a court is available at a given date, time, and duration",
      input_schema: {
        type: "object",
        properties: {
          date: {
            type: "string",
            description: "Date in YYYY-MM-DD format",
          },
          time: {
            type: "string",
            description: "Start time in HH:MM format (24h)",
          },
          duration_minutes: {
            type: "number",
            description: "Duration of the booking in minutes",
          },
        },
        required: ["date", "time", "duration_minutes"],
      },
    },
  ],
  messages: [
    {
      role: "user",
      content: "Is a court available tomorrow at 2pm for 90 minutes?",
    },
  ],
});

Étape 2 : Vérifiez si Claude souhaite appeler un outil

typescript
if (response.stop_reason === "tool_use") {
  const toolUseBlock = response.content.find(
    (block): block is Anthropic.ToolUseBlock => block.type === "tool_use"
  );

  if (!toolUseBlock) throw new Error("Expected tool_use block");

  // Run your actual function
  const toolResult = await checkCourtAvailability(
    toolUseBlock.input as CourtAvailabilityInput
  );

  // Step 3: Return the result to Claude
  const finalResponse = await anthropic.messages.create({
    model: "claude-haiku-4-5-20251001",
    max_tokens: 1024,
    tools: [
      /* same tools as before */
    ],
    messages: [
      {
        role: "user",
        content: "Is a court available tomorrow at 2pm for 90 minutes?",
      },
      { role: "assistant", content: response.content },
      {
        role: "user",
        content: [
          {
            type: "tool_result",
            tool_use_id: toolUseBlock.id,
            content: JSON.stringify(toolResult),
          },
        ],
      },
    ],
  });

  // finalResponse.content now has the text answer
}

C’est l’intégralité du pattern. Trois interactions API par appel d’outil : définir les outils → recevoir le bloc tool_use → retourner le résultat.

Exemple réel : le vérificateur de disponibilité Pickleland

Pickleland est une installation de pickleball. Nous recevons des demandes de réservation sur Facebook Messenger, dans les commentaires et via un chatbot. La question est presque toujours une variation de « êtes-vous ouverts samedi à 15h ? » ou « puis-je réserver un court pour mon groupe de 8 personnes ? »

L’agent vérificateur de disponibilité utilise le tool use pour interroger le vrai système de réservation en temps réel plutôt que de donner une réponse standard.

Voici l’agent complet — simplifié mais fidèle à la production :

typescript
// workers/availability-checker.ts
import Anthropic from "@anthropic-ai/sdk";

const anthropic = new Anthropic();

const AVAILABILITY_TOOLS: Anthropic.Tool[] = [
  {
    name: "check_availability",
    description:
      "Check court availability for a date, time, and group size. Returns available courts and their prices.",
    input_schema: {
      type: "object",
      properties: {
        date: { type: "string", description: "YYYY-MM-DD" },
        start_time: { type: "string", description: "HH:MM (24h)" },
        duration_minutes: { type: "number" },
        players: { type: "number", description: "Number of players" },
      },
      required: ["date", "start_time", "duration_minutes"],
    },
  },
  {
    name: "get_pricing",
    description:
      "Get current pricing for court rentals and open play sessions",
    input_schema: {
      type: "object",
      properties: {
        session_type: {
          type: "string",
          enum: ["court_rental", "open_play", "clinics"],
        },
      },
      required: ["session_type"],
    },
  },
];

export async function handleInquiry(
  userMessage: string,
  env: Env
): Promise<string> {
  const messages: Anthropic.MessageParam[] = [
    { role: "user", content: userMessage },
  ];

  // Agentic loop — keep going until stop_reason is "end_turn"
  while (true) {
    const response = await anthropic.messages.create({
      model: "claude-haiku-4-5-20251001",
      max_tokens: 512,
      system:
        "You are the booking assistant for Pickleland, a pickleball facility in Pflugerville, TX. " +
        "Use the tools to look up real availability and pricing. Never make up availability or prices. " +
        "If the customer wants to book, direct them to pickleland.com/book.",
      tools: AVAILABILITY_TOOLS,
      messages,
    });

    // Push the assistant's response into message history
    messages.push({ role: "assistant", content: response.content });

    if (response.stop_reason === "end_turn") {
      const textBlock = response.content.find(
        (b): b is Anthropic.TextBlock => b.type === "text"
      );
      return (
        textBlock?.text ??
        "I wasn't able to answer that — please call us directly."
      );
    }

    if (response.stop_reason === "tool_use") {
      // Process ALL tool calls in this response (Claude can request multiple at once)
      const toolResults: Anthropic.ToolResultBlockParam[] = [];

      for (const block of response.content) {
        if (block.type !== "tool_use") continue;

        let result: unknown;

        switch (block.name) {
          case "check_availability":
            result = await checkAvailability(
              block.input as AvailabilityInput,
              env
            );
            break;
          case "get_pricing":
            result = await getPricing(block.input as PricingInput, env);
            break;
          default:
            result = { error: `Unknown tool: ${block.name}` };
        }

        toolResults.push({
          type: "tool_result",
          tool_use_id: block.id,
          content: JSON.stringify(result),
        });
      }

      // Return all tool results in a single user message
      messages.push({ role: "user", content: toolResults });
    }
  }
}

Deux points à souligner ici.

La boucle agentique. Je continue jusqu’à ce que stop_reason === "end_turn". Claude peut appeler check_availability, décider qu’il a aussi besoin des prix, appeler get_pricing, puis produire la réponse finale — soit trois appels API pour un seul message utilisateur. La boucle gère cela sans logique spéciale.

Plusieurs appels d’outils par tour. Claude peut retourner plusieurs blocs tool_use dans une seule réponse. Je les traite tous et retourne tous les résultats dans un seul message user. Si vous les traitez un par un et les retournez individuellement, vous brisez le flux de la conversation et gaspillez des tokens.

Exemple réel : l’agent de recherche de leads

Ma marque de conseil utilise un agent de recherche qui enrichit les prospects entrants avant que je ne leur parle. Quand quelqu’un remplit le formulaire de contact, l’agent recherche son entreprise et extrait ce que j’ai besoin de savoir avant l’appel.

Les définitions d’outils pour celui-ci incluent un outil d’écriture — et c’est là que le pattern devient intéressant :

typescript
const RESEARCH_TOOLS: Anthropic.Tool[] = [
  {
    name: "search_company",
    description: "Search for information about a company",
    input_schema: {
      type: "object",
      properties: {
        company_name: { type: "string" },
        website: { type: "string", description: "Company website if known" },
      },
      required: ["company_name"],
    },
  },
  {
    name: "save_research",
    description:
      "Save the completed research summary to Airtable. Call this when all research is complete.",
    input_schema: {
      type: "object",
      properties: {
        company_summary: { type: "string" },
        estimated_size: {
          type: "string",
          enum: ["1-10", "11-50", "51-200", "200+"],
        },
        likely_use_case: { type: "string" },
        priority: { type: "string", enum: ["high", "medium", "low"] },
        notes: { type: "string" },
      },
      required: [
        "company_summary",
        "estimated_size",
        "likely_use_case",
        "priority",
      ],
    },
  },
];

save_research est ce que j’appelle un outil d’écriture — son but n’est pas d’obtenir des informations, mais de valider la sortie de Claude dans une base de données sous forme structurée. J’utilise ce pattern au lieu d’essayer de parser du JSON d’une réponse textuelle. Claude sait quand la recherche est terminée et appelle save_research avec des champs correctement typés. Je n’écris jamais de parser.

C’est l’application la plus propre du tool use : définissez un outil d’« action finale » avec le schéma exact que vous voulez, et Claude livre une sortie structurée via l’appel d’outil. Pas d’analyse de texte, pas de regex, pas de validation JSONSchema d’une sortie en texte libre.

Un outil vs. plusieurs

L’instinct en commençant avec le tool use est de construire un outil géant qui fait tout. Résistez à cela. Les outils petits et ciblés sont meilleurs pour trois raisons :

  1. Claude raisonne mieux sur les petits outils. Un outil appelé get_court_status qui retourne la disponibilité est plus facile à raisonner pour le modèle qu’un outil appelé manage_facility qui prend un paramètre mode et branche en interne.

  2. Les petits outils sont plus faciles à tester. Chaque outil est une fonction TypeScript que vous pouvez tester unitairement indépendamment du LLM. Vous devriez le faire — les bugs d’outils sont difficiles à déboguer dans une conversation active.

  3. Claude peut paralléliser les petits outils. Si deux outils ne dépendent pas l’un de l’autre, Claude peut les appeler dans la même réponse et vous les traitez en parallèle. Cela ne fonctionne que si les outils sont genuinement indépendants.

L’exception : les outils qui ont besoin d’accéder à beaucoup d’état interne partagé. Si la fonction a besoin de 10 variables de la même source de données, un outil avec un schéma plus riche bat 10 outils qui accèdent chacun séparément à la base de données.

Ma règle empirique : commencez avec un outil par capacité distincte. Fusionnez les outils uniquement quand vous voyez Claude les appeler ensemble à chaque requête.

Implications en termes de coûts

Le tool use ajoute des tokens. Chaque définition d’outil va dans le contexte du prompt système. Chaque bloc tool_use et tool_result consomme des tokens dans l’historique de la conversation. Pour une boucle agentique multi-tours, cela s’accumule rapidement.

Pour le vérificateur de disponibilité Pickleland, une conversation typique exécute 3–4 appels API au total (message initial + 1–2 appels d’outils + réponse finale), chacun traitant 600–900 tokens. Au tarif Haiku, cela revient à moins de 0,001 $ par demande. Comme je l’explique dans le post sur le calcul des coûts des agents IA, Haiku gère les tâches d’appel d’outils bien définies de manière fiable et est 10× moins cher que Sonnet pour le même volume de tokens.

L’agent de recherche de leads fonctionne sur Sonnet parce que les décisions de jugement — prioriser un prospect, évaluer l’adéquation — nécessitent plus de capacité de raisonnement que ce que Haiku offre de manière fiable sur des inputs ouverts. Le calcul fonctionne toujours parce qu’il s’exécute rarement (quelques fois par semaine, pas des milliers par jour). Le choix du modèle suit la complexité de la tâche, pas la préférence personnelle.

Le point de défaillance dont personne ne parle

Le point de défaillance le plus courant que je vois dans le tool use en production n’est pas Claude qui appelle le mauvais outil. C’est l’outil qui retourne quelque chose que Claude ne peut pas raisonner clairement.

Si votre outil retourne un objet de base de données brut avec 40 champs, Claude est confus sur les champs importants. Si votre outil lance une exception (qui apparaît comme un crash de Worker plutôt qu’un résultat d’outil), la boucle se brise silencieusement. Si votre outil retourne null quand il veut dire « pas de résultats », Claude ne sait pas s’il doit réessayer ou abandonner.

Trois règles pour les résultats d’outils :

Retournez des résultats concis et explicites. { available: true, courts: ["Court 3", "Court 5"], price_per_hour: 20 } — pas la ligne complète de la base de données.

Capturez les erreurs dans la fonction de l’outil et retournez-les comme résultats structurés. { error: "booking system timeout", retry: true } — pas une exception lancée qui crashe le Worker.

Rendez « pas de résultats » explicite. { available: false, next_available: "2026-07-23T14:00:00Z" } — pas null ni un tableau vide sans contexte.

Claude raisonne beaucoup mieux sur des signaux clairs que sur des valeurs de retour ambiguës. Chaque heure passée à déboguer le tool use en production a concerné des résultats peu clairs, pas le raisonnement du modèle.

La conclusion de l’opérateur

Le tool use est la fonctionnalité qui transforme Claude d’un générateur de texte en opérateur. Définissez des outils ciblés avec des schémas d’entrée clairs. Gérez tous les blocs tool_use dans une seule réponse au modèle. Exécutez la boucle agentique jusqu’à ce que stop_reason === "end_turn". Retournez des résultats propres et concis depuis vos fonctions d’outils — pas des objets de données bruts, pas des exceptions lancées, pas des nulls ambigus.

Le modèle gère le raisonnement. Votre code gère les actions dans le monde réel. Gardez ces deux rôles clairement séparés et l’architecture reste maintenable même quand vous ajoutez des outils.

Si vous construisez votre premier agent tool use, commencez avec le pattern du vérificateur de disponibilité ci-dessus — un outil, un objectif, une boucle agentique. Déployez ça. Ensuite ajoutez le deuxième outil.


Connexes : Le stack d’agents que j’utilise pour gérer 30+ agents en production · Haiku vs Sonnet : le calcul des coûts pour les tâches d’agents · Agents déclenchés par événements vs planifiés : quel pattern pour quel travail

Vous construisez un agent tool use et vous êtes bloqué ? Contactez-moi — je conçois et construis des architectures d’agents de production pour les équipes d’opérateurs.

FAQ

Le tool use de Claude fonctionne-t-il avec tous les modèles ?

Oui — le tool use est pris en charge par tous les modèles Claude actuels. Claude Haiku gère les outils bien définis avec des schémas clairs de manière fiable et est l’option la moins chère pour les types de tâches à haut volume. Sonnet gère mieux les décisions d’appel d’outils plus ambiguës ou ouvertes. Commencez avec Haiku ; montez en gamme si la qualité de sortie n’est pas suffisante.

Quelle est la différence entre le tool use de Claude et le function calling d’OpenAI ?

Mécaniquement identiques. OpenAI a inventé « function calling » ; Anthropic l’appelle « tool use ». Dans les deux cas : vous définissez des schémas JSON, le modèle retourne des appels structurés, votre code exécute la fonction. La forme de l’API diffère mais le concept est le même.

Claude peut-il appeler plusieurs outils dans une seule réponse ?

Oui. Claude peut retourner plusieurs blocs tool_use dans une seule réponse assistant. Traitez-les tous et retournez tous les résultats dans un seul message user. Consultez le pattern de boucle agentique dans l’exemple Pickleland ci-dessus — la boucle for sur response.content gère cela correctement.

Combien d’outils dois-je définir par agent ?

Je reste en dessous de 8–10 outils par agent. Au-delà, j’ai vu Claude choisir occasionnellement le mauvais outil au premier essai, ce qui gaspille des tokens dans une boucle de correction. Si vous avez besoin de plus de 10 capacités, divisez l’agent en plusieurs agents avec des ensembles d’outils spécialisés plutôt que de construire un agent qui sait tout.

Dois-je utiliser le tool use pour obtenir une sortie structurée ?

Oui — le pattern d’outil d’écriture save_research est plus propre que demander à Claude de retourner du JSON dans un bloc textuel et de le parser ensuite. Définissez un outil d’« action finale » avec le schéma exact que vous voulez. Claude l’appellera avec des champs correctement typés quand il a terminé. Pas de parser nécessaire.

Continuer à lire

Articles liés

Continuer à lire

Recevez le guide IA dans votre boîte mail

Chaque mercredi. 28 400+ opérateurs. Zéro superflu.

↵ pour voir tous les résultats esc esc pour fermer