Chargement

Qu'est-ce que l'utilisation d'outils ?

Leçon 58 min
Chargement

Qu'est-ce que l'utilisation d'outils ?

Vos workflows existants reposent sur de nombreuses technologies différentes — logiciels de gestion de projet, bases de données, fichiers. Claude ne peut pas simplement vérifier ces éléments lui-même. Il s'appuie plutôt sur des outils, qui donnent à Claude accès à des données et des actions externes.

Qu'est-ce qu'un outil

En termes simples, un outil est une fonction que vous définissez et exposez à Claude. Vous décrivez ce qu'elle fait et quelles entrées elle prend, et Claude décide quand l'appeler.

Voici l'élément clé à intégrer : Claude n'exécute pas l'outil — c'est votre code qui le fait. Le flux se présente ainsi :

  1. Claude demande un appel d'outil.
  2. Votre code exécute la fonction.
  3. Le résultat revient à Claude, qui poursuit.

Comment les outils sont définis

Les outils sont des schémas JSON comportant trois parties : un nom, une description, et un schéma d'entrée. Vous les transmettez à Claude dans le corps de la requête sous forme de tableau tools.

La description est ce que Claude lit pour décider s'il doit appeler l'outil. Si vous rédigez une description vague, vous obtenez une mauvaise utilisation d'outils. C'est la raison numéro un pour laquelle les agents se trompent ou ne saisissent pas les outils qui sont à leur disposition. Soyez précis.

Voici à quoi ressemble une définition d'outil :

json
{
  "name": "lookup_building_code",
  "description": "Look up a specific building code section by its identifier. Returns the full text of that code section.",
  "input_schema": {
    "type": "object",
    "properties": {
      "section": {
        "type": "string",
        "description": "The building code section to look up"
      }
    },
    "required": ["section"]
  }
}

Alors que se passe-t-il lorsque nous utilisons cela ? Disons que nous envoyons à un agent un rapport de conformité. Au premier tour, Claude revient avec stop_reason: "tool_use" — c'est notre signal. Voici à quoi ressemble cette réponse :

Une réponse API avec stop_reason défini sur tool_use, contenant un bloc de contenu tool_use qui nomme l'outil et l'entrée avec laquelle Claude souhaite l'appeler

Notre boucle appelle lookup_building_code avec le paramètre demandé par Claude, puis renvoie le résultat sous forme de résultat d'outil — un message utilisateur contenant un bloc tool_result lié à l'id de l'appel d'outil :

Un message utilisateur contenant un bloc tool_result avec le tool_use_id et le texte du code du bâtiment recherché comme contenu

Et Claude continue. À ce stade, nous pouvons continuer à appeler des outils et à renvoyer des résultats à Claude jusqu'à ce qu'il ait ce dont il a besoin.

Plusieurs outils : laisser Claude choisir

Un seul outil est utile, mais la partie intéressante consiste à donner à Claude plusieurs outils et à observer lequel il choisit d'utiliser, et dans quel ordre.

Imaginez ce scénario : vous préparez vos bagages pour un voyage de trois jours à Denver, et vous voulez à la fois la météo du jour et les prévisions pour les jours suivants. Nous déclarons donc deux outils au lieu d'un :

typescript
const tools = [
  {
    name: "get_weather",
    description: "Get today's current weather for a city.",
    input_schema: {
      type: "object",
      properties: {
        city: { type: "string", description: "The city to check" }
      },
      required: ["city"]
    }
  },
  {
    name: "get_forecast",
    description: "Get the weather forecast for the next few days for a city.",
    input_schema: {
      type: "object",
      properties: {
        city: { type: "string", description: "The city to check" }
      },
      required: ["city"]
    }
  }
];

La boucle est identique aux boucles d'agent que nous avons déjà vues. Le seul élément nouveau est une fonction runTool qui se répartit selon le nom de l'outil avec une instruction switch — ce bloc de code est simplement l'endroit où votre code s'exécute réellement :

typescript
function runTool(name, input) {
  switch (name) {
    case "get_weather":
      return getWeather(input.city);
    case "get_forecast":
      return getForecast(input.city);
  }
}

while (true) {
  const response = await client.messages.create({
    model: "claude-sonnet-5",
    max_tokens: 1024,
    messages,
    tools,
  });

  if (response.stop_reason !== "tool_use") {
    // Claude a terminé — c'est la réponse finale
    break;
  }

  messages.push({ role: "assistant", content: response.content });

  const toolResults = response.content
    .filter((block) => block.type === "tool_use")
    .map((block) => ({
      type: "tool_result",
      tool_use_id: block.id,
      content: runTool(block.name, block.input),
    }));

  messages.push({ role: "user", content: toolResults });
}

Et c'est tout le schéma. Vous voulez un troisième outil ? Ajoutez-le au tableau, ajoutez un cas au switch, et c'est terminé.

Exécutez ceci, et vous verrez Claude appeler get_weather puis get_forecast — parfois dans le même tour, parfois l'un après l'autre. Puis il répond : prévoyez des couches, attendez-vous à des averses de neige aujourd'hui, avec un réchauffement au cours de la semaine.

Remarquez maintenant comment Claude a choisi. Il a lu les descriptions, a associé votre prompt à « la météo du jour » et « les prochains jours », et a choisi le bon outil pour chacun. C'est pourquoi vos descriptions d'outils comptent vraiment.

L'exécuteur d'outils : évitez le code répétitif

Vous avez probablement déjà repéré deux signaux d'alerte dans ce que nous venons d'écrire :

  • C'est beaucoup de code pour deux simples recherches.
  • Dans une base de code réelle, vous ne voulez pas écrire à la main des schémas JSON pour chaque fonction que vous avez. C'est comme écrire votre code deux fois.

C'est là qu'intervient l'exécuteur d'outils (tool runner). Il est disponible en version bêta dans les SDK Claude : TypeScript, Python, Ruby, C#, Go, Java et PHP. Vous définissez chaque outil une seule fois, et l'exécuteur gère en interne toute la boucle d'utilisation d'outils / résultat d'outil.

En TypeScript, l'assistant recommandé de l'exécuteur, betaZodTool(), décrit chaque outil avec un court schéma écrit en Zod, une bibliothèque TypeScript pour déclarer et valider la forme des données. L'assistant nécessite Zod 3.25.0 ou une version ultérieure, ce qu'une installation récente vous procure :

bash
npm install zod

Votre code se réduit à : décrire l'outil, envoyer le prompt, attendre le résultat. Voici la même démo météo à deux outils, câblée via l'exécuteur d'outils :

typescript
import { betaZodTool } from "@anthropic-ai/sdk/helpers/beta/zod";
import { z } from "zod";

// Encapsule les deux mêmes recherches effectuées manuellement, chacune avec un court schéma Zod.
const weatherTool = betaZodTool({
  name: "get_weather",
  description: "Get today's current weather for a city.",
  inputSchema: z.object({
    city: z.string().describe("The city to check"),
  }),
  run: async ({ city }) => getWeather(city),
});

const forecastTool = betaZodTool({
  name: "get_forecast",
  description: "Get the weather forecast for the next few days for a city.",
  inputSchema: z.object({
    city: z.string().describe("The city to check"),
  }),
  run: async ({ city }) => getForecast(city),
});

const runner = client.beta.messages.toolRunner({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  messages: [
    {
      role: "user",
      content:
        "I'm packing for a three-day trip to Denver. What's the weather today and over the next few days?",
    },
  ],
  tools: [weatherTool, forecastTool],
});

// Attend le runner pour obtenir le message final une fois que tous les échanges d'outils se sont stabilisés.
const finalMessage = await runner;

Même scénario, une fraction du code :

  • Pas de boucle while, pas d'instruction switch sur la raison d'arrêt, pas de renvoi manuel des résultats d'outils dans les messages — l'exécuteur gère tout cela.
  • Pas de schémas JSON écrits à la main, juste un court schéma Zod par outil, qui valide également l'entrée envoyée par Claude.
  • Chaque fonction run enveloppe la même recherche que nous avons effectuée manuellement il y a un instant.
  • Attendre l'exécuteur renvoie le message final de l'assistant une fois que tout s'est stabilisé.

Exécutez-le, et vous obtenez la même réponse.

Les outils réels enveloppent votre code existant

Dans la vraie vie, vos outils ne seraient pas des données météo codées en dur. Ils envelopperaient des fonctions réelles que vous avez déjà dans votre application.

Prenez un agent de révision de conformité : ses outils sont de minces enveloppes autour des fonctions lookup_building_code et search_building_code qui existent déjà dans la base de code. Avec l'exécuteur d'outils, vous enveloppez chacune de ces fonctions dans une courte définition d'outil avec son propre schéma Zod, et l'agent cite des sections de code spécifiques dans chaque constat qu'il rédige :

Une application de révision de conformité montrant un rapport structurel aux côtés des constats de l'agent, chaque élément signalé citant la section spécifique du code du bâtiment qu'il a vérifiée

Récapitulatif

  • Les outils donnent à Claude accès à vos systèmes. Un outil est une fonction que vous définissez et exposez ; Claude décide quand l'appeler, et votre code l'exécute.
  • Les outils sont des schémas JSON avec un nom, une description, et un schéma d'entrée, transmis dans la requête sous forme de tableau tools.
  • Rédigez des descriptions précises. Les descriptions vagues sont la raison numéro un pour laquelle les agents se trompent.
  • stop_reason: "tool_use" est votre signal pour exécuter l'outil et renvoyer le résultat sous forme de résultat d'outil.
  • Pour plusieurs outils, répartissez selon le nom de l'outil. Ajouter un outil signifie l'ajouter au tableau et ajouter un cas.
  • L'exécuteur d'outils du SDK (disponible en bêta dans tous les SDK Claude) gère toute la boucle, et en TypeScript chaque outil est une courte définition avec un schéma Zod. Ou vous pouvez exécuter la boucle vous-même.
  • Vous exécutez, ou vous déléguez la boucle. À l'extrémité de ce spectre, les agents gérés délèguent l'agent entier à Anthropic.