Claude Platform Docs
  • Messages
  • Agents gérés
  • Administration

Search...
⌘K
Premiers pas
Introduction à ClaudeDémarrage rapide
Développer avec Claude
Aperçu des fonctionnalitésUtilisation de l'API MessagesRaisons d'arrêt et repliRefus et repliCrédit de repli
Capacités du modèle
Réflexion étendueRéflexion adaptativeEffortBudgets de tâches (bêta)Mode rapide (aperçu de recherche)Sorties structuréesCitationsStreaming des messagesTraitement par lotsRésultats de rechercheStreaming des refusPrise en charge multilingueEmbeddings
Outils
AperçuFonctionnement de l'utilisation d'outilsTutoriel : Créer un agent utilisant des outilsDéfinir des outilsGérer les appels d'outilsUtilisation d'outils en parallèleTool Runner (SDK)Utilisation d'outils stricteOutils serveurOutil de recherche webOutil de récupération webOutil d'exécution de codeOutil conseillerOutil de recherche d'outilsOutil de mémoireOutil BashOutil d'édition de texteOutil d'utilisation de l'ordinateurDépannage
Infrastructure des outils
Référence des outilsGérer le contexte des outilsCombinaisons d'outilsUtilisation d'outils avec mise en cache des promptsAppel d'outils programmatiqueStreaming d'outils granulaire
Gestion du contexte
Fenêtres de contexteCompactageÉdition du contexteMise en cache des promptsMessages système en cours de conversationCréer un mode d'orchestrationDiagnostics de cache (bêta)Comptage de tokens
Travailler avec des fichiers
API FilesPrise en charge des PDF
Compétences
AperçuDémarrage rapideBonnes pratiquesCompétences pour l'entrepriseCompétences dans l'API
MCP
Serveurs MCP distantsConnecteur MCP
Claude sur les plateformes cloud
Amazon BedrockAmazon Bedrock (ancienne version)Claude Platform sur AWSGoogle CloudMicrosoft Foundry

Log in
Tutoriel : Créer un agent utilisant des outils
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Claude Platform Docs

Solutions

  • AI agents
  • Code modernization
  • Coding
  • Customer support
  • Education
  • Financial services
  • Government
  • Life sciences

Partners

  • Claude on AWS
  • Claude on Google Cloud

Learn

  • Blog
  • 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
  • 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
Messages/Outils

Tutoriel : Créer un agent utilisant des outils

Un guide pas à pas, d'un simple appel d'outil à une boucle agentique prête pour la production.

Ce tutoriel construit un agent de gestion de calendrier en cinq anneaux concentriques. Chaque anneau est un programme complet et exécutable qui ajoute exactement un concept à l'anneau précédent. À la fin, vous aurez écrit la boucle agentique à la main, puis l'aurez remplacée par l'abstraction du SDK Tool Runner.

L'outil d'exemple est create_calendar_event. Son schéma utilise des objets imbriqués, des tableaux et des champs optionnels, afin que vous puissiez voir comment Claude gère des formes d'entrée réalistes plutôt qu'une simple chaîne plate.



Chaque anneau s'exécute de manière autonome. Copiez n'importe quel anneau dans un nouveau fichier et il s'exécutera sans le code des anneaux précédents.

Anneau 1 : Un seul outil, un seul tour

Le plus petit programme possible utilisant des outils : un outil, un message utilisateur, un appel d'outil, un résultat. Le code est abondamment commenté afin que vous puissiez associer chaque ligne au cycle de vie de l'utilisation d'outils.

La requête envoie un tableau tools avec le message utilisateur. Lorsque Claude décide d'appeler un outil, la réponse revient avec stop_reason: "tool_use" et un bloc de contenu tool_use contenant le nom de l'outil, un id unique et l'input structuré. Votre code exécute l'outil, puis renvoie le résultat dans un bloc tool_result dont le tool_use_id correspond à l'id de l'appel.

# Anneau 1 : un seul outil, un seul tour.

import json

import anthropic

# Créez un client. Il lit ANTHROPIC_API_KEY depuis l'environnement.
client = anthropic.Anthropic()

# Définissez un outil. Le input_schema est un objet JSON Schema décrivant
# les arguments que Claude doit passer lorsqu'il appelle cet outil. Ce schéma
# inclut des objets imbriqués (recurrence), des tableaux (attendees) et des champs
# optionnels, ce qui est plus proche des outils réels qu'un simple argument chaîne.
tools = [
    {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
            "type": "object",
            "properties": {
                "title": {"type": "string"},
                "start": {"type": "string", "format": "date-time"},
                "end": {"type": "string", "format": "date-time"},
                "attendees": {
                    "type": "array",
                    "items": {"type": "string", "format": "email"},
                },
                "recurrence": {
                    "type": "object",
                    "properties": {
                        "frequency": {"enum": ["daily", "weekly", "monthly"]},
                        "count": {"type": "integer", "minimum": 1},
                    },
                },
            },
            "required": ["title", "start", "end"],
        },
    }
]

# Envoyez la requête de l'utilisateur avec la définition de l'outil. Claude décide
# d'appeler ou non l'outil selon la requête et la description de l'outil.
response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "auto", "disable_parallel_tool_use": True},
    messages=[
        {
            "role": "user",
            "content": "Schedule a 30-minute sync with [email protected] and [email protected] next Monday at 10am.",
        }
    ],
)

# Quand Claude appelle un outil, la réponse a pour stop_reason "tool_use"
# et le tableau content contient un bloc tool_use à côté de tout texte éventuel.
print(f"stop_reason: {response.stop_reason}")

# Trouvez le bloc tool_use. Une réponse peut contenir des blocs de texte avant le
# bloc tool_use ; parcourez donc le tableau content au lieu de supposer sa position.
tool_use = next(block for block in response.content if block.type == "tool_use")
print(f"Tool: {tool_use.name}")
print(f"Input: {tool_use.input}")

# Exécutez l'outil. Dans un système réel, ceci appellerait votre API de calendrier.
# Ici, le résultat est codé en dur pour que l'exemple reste autonome.
result = {"event_id": "evt_123", "status": "created"}

# Renvoyez le résultat. Le bloc tool_result va dans un message utilisateur et
# son tool_use_id doit correspondre à l'id du bloc tool_use ci-dessus. La
# réponse précédente de l'assistant est incluse pour que Claude ait tout l'historique.
followup = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "auto", "disable_parallel_tool_use": True},
    messages=[
        {
            "role": "user",
            "content": "Schedule a 30-minute sync with [email protected] and [email protected] next Monday at 10am.",
        },
        {"role": "assistant", "content": response.content},
        {
            "role": "user",
            "content": [
                {
                    "type": "tool_result",
                    "tool_use_id": tool_use.id,
                    "content": json.dumps(result),
                }
            ],
        },
    ],
)

# Avec le résultat de l'outil en main, Claude produit une réponse finale en langage
# naturel et stop_reason devient "end_turn".
print(f"stop_reason: {followup.stop_reason}")
final_text = next(block for block in followup.content if block.type == "text")
print(final_text.text)

Résultat attendu

Output
stop_reason: tool_use
Tool: create_calendar_event
Input: {'title': 'Sync', 'start': '2026-03-30T10:00:00', 'end': '2026-03-30T10:30:00', 'attendees': ['[email protected]', '[email protected]']}
stop_reason: end_turn
I've scheduled your 30-minute sync with Alice and Bob for next Monday at 10am.

Le premier stop_reason est tool_use car Claude attend le résultat du calendrier. Après avoir envoyé le résultat, le second stop_reason est end_turn et le contenu est du langage naturel destiné à l'utilisateur.

Anneau 2 : La boucle agentique

L'anneau 1 supposait que Claude appellerait l'outil exactement une fois. Les tâches réelles nécessitent souvent plusieurs appels : Claude pourrait créer un événement, lire la confirmation, puis en créer un autre. La solution est une boucle while qui continue d'exécuter les outils et de renvoyer les résultats jusqu'à ce que stop_reason ne soit plus "tool_use".

L'autre changement concerne l'historique de conversation. Au lieu de reconstruire le tableau messages à partir de zéro à chaque requête, conservez une liste courante et ajoutez-y des éléments. Chaque tour voit l'intégralité du contexte précédent.

# Anneau 2 : la boucle agentique.

import json

import anthropic

client = anthropic.Anthropic()

tools = [
    {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
            "type": "object",
            "properties": {
                "title": {"type": "string"},
                "start": {"type": "string", "format": "date-time"},
                "end": {"type": "string", "format": "date-time"},
                "attendees": {
                    "type": "array",
                    "items": {"type": "string", "format": "email"},
                },
                "recurrence": {
                    "type": "object",
                    "properties": {
                        "frequency": {"enum": ["daily", "weekly", "monthly"]},
                        "count": {"type": "integer", "minimum": 1},
                    },
                },
            },
            "required": ["title", "start", "end"],
        },
    }
]


def run_tool(name, tool_input):
    if name == "create_calendar_event":
        return {"event_id": "evt_123", "status": "created", "title": tool_input["title"]}
    return {"error": f"Unknown tool: {name}"}


# Conservez l'historique complet de la conversation dans une liste pour que chaque tour voie le contexte précédent.
messages = [
    {
        "role": "user",
        "content": "Schedule a weekly team standup every Monday at 9am for the next 4 weeks. Invite the whole team: [email protected], [email protected], [email protected].",
    }
]

response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=tools,
    tool_choice={"type": "auto", "disable_parallel_tool_use": True},
    messages=messages,
)

# Bouclez jusqu'à ce que Claude cesse de demander des outils. Chaque itération exécute l'outil
# demandé, ajoute le résultat à l'historique, puis demande à Claude de continuer.
while response.stop_reason == "tool_use":
    tool_use = next(block for block in response.content if block.type == "tool_use")
    result = run_tool(tool_use.name, tool_use.input)

    messages.append({"role": "assistant", "content": response.content})
    messages.append(
        {
            "role": "user",
            "content": [
                {
                    "type": "tool_result",
                    "tool_use_id": tool_use.id,
                    "content": json.dumps(result),
                }
            ],
        }
    )

    response = client.messages.create(
        model="claude-opus-4-8",
        max_tokens=1024,
        tools=tools,
        tool_choice={"type": "auto", "disable_parallel_tool_use": True},
        messages=messages,
    )

final_text = next(block for block in response.content if block.type == "text")
print(final_text.text)

Résultat attendu

Output
I've set up your weekly team standup for the next 4 Mondays at 9am with Alice, Bob, and Carol invited.

La boucle peut s'exécuter une ou plusieurs fois selon la manière dont Claude décompose la tâche. Votre code n'a plus besoin de le savoir à l'avance.

Anneau 3 : Plusieurs outils, appels parallèles

Les agents ont rarement une seule capacité. Ajoutez un second outil, list_calendar_events, afin que Claude puisse vérifier le planning existant avant de créer quelque chose de nouveau.

Lorsque Claude a plusieurs appels d'outils indépendants à effectuer, il peut renvoyer plusieurs blocs tool_use dans une seule réponse. Votre boucle doit tous les traiter et renvoyer tous les résultats ensemble dans un seul message utilisateur. Itérez sur chaque bloc tool_use dans response.content, pas seulement le premier.

# Anneau 3 : Plusieurs outils, appels parallèles.

import json

import anthropic

client = anthropic.Anthropic()

tools = [
    {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
            "type": "object",
            "properties": {
                "title": {"type": "string"},
                "start": {"type": "string", "format": "date-time"},
                "end": {"type": "string", "format": "date-time"},
                "attendees": {
                    "type": "array",
                    "items": {"type": "string", "format": "email"},
                },
                "recurrence": {
                    "type": "object",
                    "properties": {
                        "frequency": {"enum": ["daily", "weekly", "monthly"]},
                        "count": {"type": "integer", "minimum": 1},
                    },
                },
            },
            "required": ["title", "start", "end"],
        },
    },
    {
        "name": "list_calendar_events",
        "description": "List all calendar events on a given date.",
        "input_schema": {
            "type": "object",
            "properties": {
                "date": {"type": "string", "format": "date"},
            },
            "required": ["date"],
        },
    },
]


def run_tool(name, tool_input):
    if name == "create_calendar_event":
        return {"event_id": "evt_123", "status": "created", "title": tool_input["title"]}
    if name == "list_calendar_events":
        return {"events": [{"title": "Existing meeting", "start": "14:00", "end": "15:00"}]}
    return {"error": f"Unknown tool: {name}"}


messages = [
    {
        "role": "user",
        "content": "Check what I have next Monday, then schedule a planning session that avoids any conflicts.",
    }
]

response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=tools,
    messages=messages,
)

while response.stop_reason == "tool_use":
    # Une seule réponse peut contenir plusieurs blocs tool_use. Traitez-les
    # tous et renvoyez tous les résultats ensemble dans un seul message utilisateur.
    tool_results = []
    for block in response.content:
        if block.type == "tool_use":
            result = run_tool(block.name, block.input)
            tool_results.append(
                {
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": json.dumps(result),
                }
            )

    messages.append({"role": "assistant", "content": response.content})
    messages.append({"role": "user", "content": tool_results})

    response = client.messages.create(
        model="claude-opus-4-8",
        max_tokens=1024,
        tools=tools,
        messages=messages,
    )

final_text = next(block for block in response.content if block.type == "text")
print(final_text.text)

Résultat attendu

Output
I checked your calendar for next Monday and found an existing meeting from 2pm to 3pm. I've scheduled the planning session for 10am to 11am to avoid the conflict.

Pour en savoir plus sur l'exécution concurrente et les garanties d'ordonnancement, consultez Utilisation d'outils en parallèle.

Anneau 4 : Gestion des erreurs

Les outils échouent. Une API de calendrier peut rejeter un événement comportant trop de participants, ou une date peut être mal formée. Lorsqu'un outil lève une erreur, renvoyez le message d'erreur avec is_error: true au lieu de planter. Claude lit l'erreur et peut réessayer avec une entrée corrigée, demander des précisions à l'utilisateur ou expliquer la limitation.

# Anneau 4 : Gestion des erreurs.

import json

import anthropic

client = anthropic.Anthropic()

tools = [
    {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
            "type": "object",
            "properties": {
                "title": {"type": "string"},
                "start": {"type": "string", "format": "date-time"},
                "end": {"type": "string", "format": "date-time"},
                "attendees": {
                    "type": "array",
                    "items": {"type": "string", "format": "email"},
                },
                "recurrence": {
                    "type": "object",
                    "properties": {
                        "frequency": {"enum": ["daily", "weekly", "monthly"]},
                        "count": {"type": "integer", "minimum": 1},
                    },
                },
            },
            "required": ["title", "start", "end"],
        },
    },
    {
        "name": "list_calendar_events",
        "description": "List all calendar events on a given date.",
        "input_schema": {
            "type": "object",
            "properties": {
                "date": {"type": "string", "format": "date"},
            },
            "required": ["date"],
        },
    },
]


def run_tool(name, tool_input):
    if name == "create_calendar_event":
        if "attendees" in tool_input and len(tool_input["attendees"]) > 10:
            raise ValueError("Too many attendees (max 10)")
        return {"event_id": "evt_123", "status": "created", "title": tool_input["title"]}
    if name == "list_calendar_events":
        return {"events": [{"title": "Existing meeting", "start": "14:00", "end": "15:00"}]}
    raise ValueError(f"Unknown tool: {name}")


messages = [
    {
        "role": "user",
        "content": "Schedule an all-hands with everyone: " + ", ".join(f"user{i}@example.com" for i in range(15)),
    }
]

response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=tools,
    messages=messages,
)

while response.stop_reason == "tool_use":
    tool_results = []
    for block in response.content:
        if block.type == "tool_use":
            try:
                result = run_tool(block.name, block.input)
                tool_results.append(
                    {"type": "tool_result", "tool_use_id": block.id, "content": json.dumps(result)}
                )
            except Exception as exc:
                # Signaler l'échec pour que Claude puisse réessayer ou demander des précisions.
                tool_results.append(
                    {
                        "type": "tool_result",
                        "tool_use_id": block.id,
                        "content": str(exc),
                        "is_error": True,
                    }
                )

    messages.append({"role": "assistant", "content": response.content})
    messages.append({"role": "user", "content": tool_results})

    response = client.messages.create(
        model="claude-opus-4-8",
        max_tokens=1024,
        tools=tools,
        messages=messages,
    )

final_text = next(block for block in response.content if block.type == "text")
print(final_text.text)

Résultat attendu

Output
I tried to schedule the all-hands but the calendar only allows 10 attendees per event. I can split this into two sessions, or you can let me know which 10 people to prioritize.

L'indicateur is_error est la seule différence par rapport à un résultat réussi. Claude voit l'indicateur et le texte de l'erreur, et répond en conséquence. Consultez Gérer les appels d'outils pour la référence complète sur la gestion des erreurs.

Anneau 5 : L'abstraction du SDK Tool Runner

Les anneaux 2 à 4 écrivaient la même boucle à la main : appeler l'API, vérifier stop_reason, exécuter les outils, ajouter les résultats, recommencer. Le Tool Runner fait cela pour vous. Définissez chaque outil comme une fonction, passez la liste à tool_runner et récupérez le message final une fois la boucle terminée. L'encapsulation des erreurs, le formatage des résultats et la gestion de la conversation sont gérés en interne.

Le SDK Python utilise le décorateur @beta_tool pour déduire le schéma à partir des annotations de type et de la docstring. Le SDK TypeScript utilise betaZodTool avec un schéma Zod. Les autres SDK suivent le même modèle avec leurs propres utilitaires : BetaRunnableTool en C# et PHP, des classes d'outils typées en Java et Ruby, et toolrunner.NewBetaToolFromJSONSchema en Go.



Tool Runner est disponible dans les sept SDK : Python, TypeScript, C#, Go, Java, PHP et Ruby. Consultez Tool Runner pour la référence complète. Les onglets cURL et CLI affichent une note au lieu de code ; conservez la boucle de l'anneau 4 pour les scripts basés sur curl ou la CLI.

# Anneau 5 : L'abstraction du SDK Tool Runner.

import json

import anthropic
from anthropic import beta_tool

client = anthropic.Anthropic()


@beta_tool
def create_calendar_event(
    title: str,
    start: str,
    end: str,
    attendees: list[str] | None = None,
    recurrence: dict | None = None,
) -> str:
    """Create a calendar event with attendees and optional recurrence.

    Args:
        title: Event title.
        start: Start time in ISO 8601 format.
        end: End time in ISO 8601 format.
        attendees: Email addresses to invite.
        recurrence: Dict with 'frequency' (daily, weekly, monthly) and 'count'.
    """
    if attendees and len(attendees) > 10:
        raise ValueError("Too many attendees (max 10)")
    return json.dumps({"event_id": "evt_123", "status": "created", "title": title})


@beta_tool
def list_calendar_events(date: str) -> str:
    """List all calendar events on a given date.

    Args:
        date: Date in YYYY-MM-DD format.
    """
    return json.dumps({"events": [{"title": "Existing meeting", "start": "14:00", "end": "15:00"}]})


final_message = client.beta.messages.tool_runner(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=[create_calendar_event, list_calendar_events],
    messages=[
        {
            "role": "user",
            "content": "Check what I have next Monday, then schedule a planning session that avoids any conflicts.",
        }
    ],
).until_done()

for block in final_message.content:
    if block.type == "text":
        print(block.text)

Résultat attendu

Output
I checked your calendar for next Monday and found an existing meeting from 2pm to 3pm. I've scheduled the planning session for 10am to 11am to avoid the conflict.

La sortie est identique à celle de l'anneau 3. La différence réside dans le code : environ moitié moins de lignes, pas de boucle manuelle, et le schéma se trouve à côté de l'implémentation.

Ce que vous avez construit

Vous avez commencé avec un seul appel d'outil codé en dur et terminé avec un agent de qualité production qui gère plusieurs outils, des appels parallèles et des erreurs, puis vous avez condensé tout cela dans le Tool Runner. En cours de route, vous avez vu chaque élément du protocole d'utilisation d'outils : les blocs tool_use, les blocs tool_result, la correspondance tool_use_id, la vérification de stop_reason et la signalisation is_error.

Prochaines étapes

Définir des outils

Spécification de schéma et bonnes pratiques.

Tool Runner en détail

La référence complète de l'abstraction du SDK.

Dépannage

Corriger les erreurs courantes d'utilisation d'outils.

Was this page helpful?

  • Anneau 1 : Un seul outil, un seul tour
  • Anneau 2 : La boucle agentique
  • Anneau 3 : Plusieurs outils, appels parallèles
  • Anneau 4 : Gestion des erreurs
  • Anneau 5 : L'abstraction du SDK Tool Runner
  • Ce que vous avez construit
  • Prochaines étapes