Guide enseignant â Niveau AvancĂ©, Session 2
« Tool use avancé »
Programme : Applied AI â Yann Isola Public : Architectes de solutions prĂ©parant la certification Claude Certified Architect DurĂ©e : 2 heures PrĂ©requis : Session 1 (architecture API Messages, gestion du contexte), Python intermĂ©diaire, JSON Schema de base
Objectifs pédagogiques
Ă la fin de la session, chaque participant doit ĂȘtre capable de :
- DĂ©crire le cycle de vie complet dâun appel dâoutil (tool use) : message utilisateur â bloc
tool_useâ exĂ©cution cĂŽtĂ© client â messagetool_resultâ poursuite du modĂšle. - Concevoir une dĂ©finition dâoutil de qualitĂ© certification : nommage, description-prompt,
input_schemadocumenté champ par champ. - Choisir le bon
tool_choice(auto,any,toolciblĂ©) selon le cas dâusage. - Forcer une sortie structurĂ©e via le pattern du « faux outil » (fake tool).
- Distinguer et traiter les erreurs syntaxiques et sémantiques, y compris via
is_error: true. - Appliquer les patterns avancĂ©s : chaĂźnage dâoutils, sĂ©lection conditionnelle, mise en cache des rĂ©sultats.
- Répondre aux questions de certification sur
stop_reason: "tool_use"et les cas limites du flux de messages.
Plan de la session (120 min)
| Bloc | Durée | Contenu | Format |
|---|---|---|---|
| 0 | 5 min | Accueil, rappel Session 1, objectifs | PléniÚre |
| 1 | 20 min | Le cycle de vie tool_use, pas à pas | Démo live + slides |
| 2 | 20 min | Anatomie dâune dĂ©finition dâoutil | Slides + code review |
| 3 | 10 min | tool_choice : les trois modes |
Slides + mini-démo |
| 4 | 15 min | Sortie structurée : le pattern « faux outil » | Démo live |
| 5 | 15 min | Gestion des erreurs (syntaxiques, sémantiques, is_error) |
Slides + démo |
| â | 5 min | Pause | â |
| 6 | 10 min | Multi-outils et patterns avancés | Slides |
| 7 | 15 min | Atelier : débogueur de flux (page web interactive) | TP guidé |
| 8 | 5 min | Points de certification et piÚges | PléniÚre |
Les exercices (fichier exercises.md) sont donnĂ©s en travail dirigĂ© ou Ă la maison selon le temps restant. Le quiz clĂŽture la session ou sert dâĂ©valuation asynchrone.
Bloc 1 â Le cycle de vie tool_use (20 min)
Message clé à faire passer
Le modĂšle nâexĂ©cute jamais rien. Il demande une exĂ©cution en produisant un bloc de contenu
tool_use. Câest VOTRE code, avec VOS identifiants et VOS permissions, qui exĂ©cute. Le modĂšle ne voit que ce que vous lui renvoyez.
Câest le point de sĂ©curitĂ© le plus important de toute la session â et une question quasi certaine en certification.
Le cycle en 5 étapes (à dessiner au tableau)
âââââââââââââââ 1. RequĂȘte + tools[] âââââââââââââââ
â â âââââââââââââââââââââââââââââș â â
â VOTRE CODE â 2. stop_reason:"tool_use" â MODĂLE â
â (client) â âââââââââââââââââââââââââââââ â (Claude) â
â â â â
â 3. Vous â 4. tool_result (role:user) â â
â exĂ©cutez â âââââââââââââââââââââââââââââș â â
â l'outil â 5. RĂ©ponse finale â â
â â âââââââââââââââââââââââââââââ â â
âââââââââââââââ stop_reason:"end_turn" âââââââââââââââ
- RequĂȘte : vous envoyez les messages + le tableau
tools(définitions). - Décision du modÚle : si le modÚle veut utiliser un outil, la réponse contient un bloc
tool_useet le champstop_reasonvaut"tool_use". - Exécution cÎté client : votre code lit
nameetinputdu bloc, exécute la fonction correspondante. - Renvoi du résultat : vous ajoutez à la conversation un message
role: "user"contenant un bloctool_resultavec letool_use_idcorrespondant. - Poursuite : le modĂšle intĂšgre le rĂ©sultat et rĂ©pond (ou demande un autre outil â boucle).
DĂ©mo live â API brute (JSON)
Montrer la requĂȘte HTTP (Application Programming Interface â interface de programmation applicative â au format REST) :
POST https://api.anthropic.com/v1/messages
{
"model": "claude-sonnet-4-5",
"max_tokens": 1024,
"tools": [
{
"name": "get_weather",
"description": "RécupÚre la météo actuelle pour une ville donnée. Retourne la température en Celsius et les conditions. à utiliser dÚs que l'utilisateur pose une question sur la météo actuelle ou demande s'il doit prendre un parapluie, un manteau, etc.",
"input_schema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "Nom de la ville, en français, sans le pays. Exemple : \"Paris\", \"GenÚve\"."
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Unité de température. Par défaut : celsius."
}
},
"required": ["city"]
}
}
],
"messages": [
{"role": "user", "content": "Il fait combien Ă Lyon ?"}
]
}
Réponse du modÚle (à décortiquer ligne par ligne) :
{
"id": "msg_01AbC...",
"role": "assistant",
"stop_reason": "tool_use",
"content": [
{
"type": "text",
"text": "Je vérifie la météo à Lyon."
},
{
"type": "tool_use",
"id": "toolu_01XyZ...",
"name": "get_weather",
"input": {"city": "Lyon", "unit": "celsius"}
}
]
}
Points dâattention Ă verbaliser :
stop_reason: "tool_use"â câest LE signal que votre boucle doit dĂ©tecter.- Le bloc
contentpeut contenir du texte avant le bloctool_use(chaĂźne de pensĂ©e visible). Ne jamais supposer quecontent[0]est letool_use. - Lâ
iddu bloctool_use(toolu_...) est obligatoire pour corréler le résultat.
Puis le renvoi du résultat :
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01XyZ...",
"content": "18°C, nuageux avec éclaircies"
}
]
}
PiĂšge certification : le tool_result est envoyĂ© dans un message role: "user", PAS role: "tool" (contrairement Ă lâAPI dâOpenAI). Le message assistant contenant le tool_use doit ĂȘtre renvoyĂ© tel quel dans lâhistorique, sinon erreur 400.
DĂ©mo live â SDK Python
SDK = Software Development Kit (kit de développement logiciel).
import anthropic
client = anthropic.Anthropic() # clé lue dans ANTHROPIC_API_KEY
tools = [{
"name": "get_weather",
"description": (
"RécupÚre la météo actuelle pour une ville donnée. "
"Retourne la température en Celsius et les conditions. "
"à utiliser dÚs que l'utilisateur pose une question météo."
),
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string",
"description": "Nom de la ville, ex. \"Paris\"."},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"],
"description": "Unité. Défaut : celsius."},
},
"required": ["city"],
},
}]
def get_weather(city: str, unit: str = "celsius") -> str:
# Ici : appel à une vraie API météo, avec VOTRE clé d'API météo.
return f"18°{'C' if unit == 'celsius' else 'F'}, nuageux"
messages = [{"role": "user", "content": "Il fait combien Ă Lyon ?"}]
# Boucle agentique minimale
while True:
response = client.messages.create(
model="claude-sonnet-4-5", # â nom de modĂšle volatile, vĂ©rifier la doc
max_tokens=1024,
tools=tools,
messages=messages,
)
if response.stop_reason != "tool_use":
break # réponse finale
# 1. Renvoyer le message assistant TEL QUEL dans l'historique
messages.append({"role": "assistant", "content": response.content})
# 2. Exécuter chaque bloc tool_use (il peut y en avoir plusieurs !)
results = []
for block in response.content:
if block.type == "tool_use":
if block.name == "get_weather":
output = get_weather(**block.input)
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": output,
})
# 3. Les résultats repartent dans UN message user
messages.append({"role": "user", "content": results})
print(response.content[0].text)
Ă souligner :
- La boucle
while: câest le squelette de tout agent. Le modĂšle peut enchaĂźner plusieurs tours dâoutils avant de rĂ©pondre. for block in response.content: gĂšre nativement le cas multi-outils.- Tous les
tool_resultdâun mĂȘme tour vont dans un seul messageuser.
Bloc 2 â Anatomie dâune dĂ©finition dâoutil (20 min)
La description EST un prompt
Insister lourdement : la description nâest pas de la documentation pour les humains, câest un prompt injectĂ© dans le contexte du modĂšle. Elle conditionne :
- quand le modĂšle choisit lâoutil (dĂ©clenchement),
- comment il remplit les paramĂštres,
- ce quâil attend en retour.
Bonne heuristique de rédaction (3-4 phrases) :
- Ce que fait lâoutil (une phrase, verbe dâaction).
- Quand lâutiliser (dĂ©clencheurs explicites, y compris formulations indirectes).
- Quand ne PAS lâutiliser (frontiĂšres avec les autres outils).
- Ce quâil retourne (format, unitĂ©s, cas vides).
Contre-exemple vs bon exemple (code review collective)
Mauvais :
{
"name": "search",
"description": "Recherche",
"input_schema": {
"type": "object",
"properties": {"q": {"type": "string"}},
"required": ["q"]
}
}
ProblÚmes à faire identifier par le groupe : nom générique (recherche de quoi ?), description inutile, paramÚtre q non documenté (quelle syntaxe ? quelle langue ? opérateurs booléens ?).
Bon :
{
"name": "search_client_contracts",
"description": "Recherche en texte intégral dans la base des contrats clients signés. à utiliser quand l'utilisateur mentionne un contrat, une clause, un client ou une échéance contractuelle. Ne couvre PAS les devis ni les factures (utiliser search_invoices). Retourne au maximum 10 contrats avec id, titre, client et extrait pertinent ; retourne une liste vide si aucun résultat.",
"input_schema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Termes de recherche en langage naturel. Pas d'opérateurs booléens. Exemple : \"clause de résiliation Acme 2025\"."
},
"client_id": {
"type": "string",
"description": "Optionnel. Identifiant client (format CLI-XXXX) pour restreindre la recherche Ă un seul client."
},
"max_results": {
"type": "integer",
"minimum": 1,
"maximum": 10,
"description": "Nombre maximal de résultats. Défaut : 5."
}
},
"required": ["query"]
}
}
Principes de conception (Ă retenir pour la certification)
- Responsabilité unique : un outil = une action. Pas de
manage_database(action, ...)fourre-tout : le modĂšle se trompe plus souvent sur les outils polymorphes. - Nommage clair :
snake_case, verbe + objet (create_invoice,get_user_profile). Le nom seul doit suffire Ă deviner la fonction. - Documenter les cas limites : que se passe-t-il si vide, si trop de rĂ©sultats, si lâentitĂ© nâexiste pas ? Le modĂšle gĂšre mieux ce quâil anticipe.
- Minimum de champs
required: chaque champ obligatoire est une occasion dâerreur ou dâhallucination de valeur. Rendre optionnel tout ce qui a un dĂ©faut raisonnable â et documenter ce dĂ©faut. enumet contraintes JSON Schema (minimum,maximum,format) plutĂŽt que des consignes en prose : le schĂ©ma contraint mieux que la description.
JSON Schema â rappel express
JSON Schema (JavaScript Object Notation Schema â schĂ©ma de description de donnĂ©es JSON) : input_schema doit ĂȘtre un objet ("type": "object") au niveau racine. Sous-ensemble utile en certification : type, properties, required, enum, description, items (tableaux), objets imbriquĂ©s, minimum/maximum, format (indicatif, non strictement validĂ©).
Bloc 3 â tool_choice : les trois modes (10 min)
| Mode | Syntaxe | Comportement | Cas dâusage |
|---|---|---|---|
| auto (défaut) | {"type": "auto"} |
Le modÚle décide : outil ou réponse texte | Assistant conversationnel général |
| any | {"type": "any"} |
Le modĂšle DOIT appeler un outil, mais choisit lequel | Routeur dâintentions, dispatch |
| tool | {"type": "tool", "name": "extract_data"} |
Le modÚle DOIT appeler CET outil | Extraction structurée, pipeline déterministe |
Points de certification :
- Avec
anyoutool, la réponse contient toujours untool_useetstop_reasonvaut"tool_use". - Avec
any/tool, le modĂšle ne produit pas de raisonnement en texte libre avant lâappel de la mĂȘme maniĂšre quâenautoâ les paramĂštres peuvent ĂȘtre lĂ©gĂšrement moins rĂ©flĂ©chis. Pour les tĂąches complexes,auto+ prompt directif est parfois plus fiable quetoolforcĂ©. - â Interaction avec le « thinking » Ă©tendu : les modes forcĂ©s (
any,tool) sont incompatibles avec la rĂ©flexion Ă©tendue (extended thinking) au moment de la rĂ©daction de ce guide â vĂ©rifier la documentation courante. - Il existe aussi
{"type": "none"}pour interdire tout appel dâoutil tout en gardant les dĂ©finitions dans le contexte.
Mini-dĂ©mo : mĂȘme question (« Analyse ce ticket support ») lancĂ©e avec auto puis tool forcĂ© sur un outil dâextraction, comparer les sorties.
Bloc 4 â Sortie structurĂ©e : le pattern « faux outil » (15 min)
Le problĂšme
Vous voulez du JSON garanti et conforme Ă un schĂ©ma (pour insĂ©rer en base, alimenter un pipelineâŠ). Demander « rĂ©ponds en JSON » dans le prompt fonctionne souvent, mais sans garantie : texte parasite autour, champ manquant, clĂ© renommĂ©e.
La solution
DĂ©finir un outil qui nâexĂ©cute rien â il ne sert quâĂ contraindre la forme de la sortie â et forcer son appel avec tool_choice.
extraction_tool = {
"name": "record_ticket_analysis",
"description": "Enregistre l'analyse structurée d'un ticket de support client.",
"input_schema": {
"type": "object",
"properties": {
"sentiment": {
"type": "string",
"enum": ["positif", "neutre", "negatif"],
"description": "Sentiment global du client."
},
"urgence": {
"type": "integer", "minimum": 1, "maximum": 5,
"description": "Urgence de 1 (faible) Ă 5 (critique)."
},
"categorie": {
"type": "string",
"enum": ["facturation", "technique", "commercial", "autre"],
"description": "Catégorie principale du ticket."
},
"resume": {
"type": "string",
"description": "Résumé en une phrase, max 25 mots."
}
},
"required": ["sentiment", "urgence", "categorie", "resume"]
}
}
response = client.messages.create(
model="claude-sonnet-4-5", # â volatile
max_tokens=1024,
tools=[extraction_tool],
tool_choice={"type": "tool", "name": "record_ticket_analysis"},
messages=[{"role": "user", "content": f"Analyse ce ticket :\n{ticket}"}],
)
data = next(b for b in response.content if b.type == "tool_use").input
# data est un dict Python déjà parsé : {"sentiment": "negatif", "urgence": 4, ...}
Ă souligner :
- Pas besoin de renvoyer un
tool_result: on ne continue pas la conversation, on rĂ©cupĂšre justeinput. Câest un « appel Ă sens unique ». - Le SDK parse le JSON pour vous â
block.inputest déjà un dictionnaire. - Les
enum+minimum/maximumdonnent une validation structurelle forte, mais pas sĂ©mantique (le modĂšle peut se tromper de catĂ©gorie tout en respectant lâenum) â transition parfaite vers le Bloc 5. - â Mentionner que des modes de sortie structurĂ©e natifs Ă©voluent rapidement cĂŽtĂ© API ; le pattern « faux outil » reste la technique de rĂ©fĂ©rence portable et au programme de la certification.
Bloc 5 â Gestion des erreurs (15 min)
Taxonomie : syntaxique vs sémantique
| Type | Définition | Exemple | RemÚde |
|---|---|---|---|
| Syntaxique | La sortie viole le format attendu | JSON tronqué (max_tokens trop bas), champ requis absent, type incorrect |
Réessayer (retry), augmenter max_tokens, valider puis re-demander |
| Sémantique | Le format est valide mais le contenu est faux | Mauvaise catégorie, ville hallucinée, montant erroné | Affiner le prompt : meilleure description, exemples, enum plus stricts, découpage de la tùche |
RĂšgle mnĂ©motechnique : syntaxique â retry ; sĂ©mantique â réécriture. Un retry sur une erreur sĂ©mantique redonnera souvent la mĂȘme erreur (le modĂšle est cohĂ©rent avec sa comprĂ©hension) ; réécrire le prompt sur une erreur syntaxique traite le symptĂŽme, pas la cause (souvent max_tokens ou schĂ©ma trop complexe).
Cause frĂ©quente dâerreur syntaxique Ă connaĂźtre pour la certification : stop_reason: "max_tokens" au milieu dâun bloc tool_use â le JSON dâinput est tronquĂ©. DĂ©tection : vĂ©rifier stop_reason AVANT de parser.
Renvoyer une erreur au modĂšle : is_error: true
Quand VOTRE outil Ă©choue (exception, 404, timeout), ne cassez pas la boucle : renvoyez lâerreur au modĂšle, il sait souvent se rattraper (reformuler, changer de paramĂštre, essayer un autre outil, ou expliquer lâĂ©chec Ă lâutilisateur).
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01XyZ...",
"content": "Erreur : ville \"Lyno\" introuvable. Villes proches : Lyon, Lens.",
"is_error": true
}
]
}
En Python :
try:
output = get_weather(**block.input)
result = {"type": "tool_result", "tool_use_id": block.id,
"content": output}
except CityNotFoundError as e:
result = {"type": "tool_result", "tool_use_id": block.id,
"content": f"Erreur : {e}. Vérifie l'orthographe de la ville.",
"is_error": True}
Bonnes pratiques du message dâerreur :
- Rédigé pour le modÚle, pas pour un log : actionnable, avec suggestion de correction.
- Ne jamais renvoyer une stack trace brute complĂšte (bruit, tokens gaspillĂ©s, fuite dâinformation).
- Toujours renvoyer UN
tool_resultpartool_usereçu, mĂȘme en cas dâĂ©chec â untool_useorphelin sanstool_resultprovoque une erreur 400 Ă la requĂȘte suivante.
Anecdote dâarchitecte
Un pattern robuste en production : valider block.input avec Pydantic (bibliothĂšque Python de validation de donnĂ©es) AVANT dâexĂ©cuter, et renvoyer les erreurs de validation en is_error: true. Le modĂšle corrige ses paramĂštres au tour suivant dans la grande majoritĂ© des cas.
Bloc 6 â Multi-outils et patterns avancĂ©s (10 min)
Plusieurs outils dans un tour
Le modĂšle peut Ă©mettre plusieurs blocs tool_use dans une mĂȘme rĂ©ponse (appels parallĂšles) ou enchaĂźner sur plusieurs tours (appels sĂ©quentiels). Votre code doit :
- itérer sur TOUS les blocs
tool_usede la réponse, - renvoyer TOUS les
tool_resultcorrespondants dans le messageusersuivant, chacun avec le bontool_use_id.
Trois patterns dâarchitecture
- ChaĂźnage dâoutils (tool chaining) : la sortie de lâoutil A nourrit lâentrĂ©e de lâoutil B, orchestrĂ© par le modĂšle sur plusieurs tours. Exemple :
search_clientâget_client_contractsâsummarize_contract. Conception : faire en sorte que la sortie de A contienne exactement les identifiants dont B a besoin (ex. A retourneclient_id, B prendclient_iden paramĂštre). - SĂ©lection conditionnelle : exposer des outils diffĂ©rents selon lâĂ©tat de la session (utilisateur authentifiĂ© ou non, module actifâŠ). Le tableau
toolsest envoyĂ© Ă CHAQUE requĂȘte : vous pouvez le faire varier dynamiquement. Câest un contrĂŽle dâaccĂšs cĂŽtĂ© client, plus fiable que « ne lâutilise pas » en prompt. - Cache de rĂ©sultats (tool result caching) : mĂ©moĂŻser cĂŽtĂ© client les appels identiques (mĂȘme outil, mĂȘmes paramĂštres) pendant une session. Ăconomise latence et coĂ»ts dâAPI externes. Attention Ă lâinvalidation (TTL â Time To Live, durĂ©e de vie â courte pour les donnĂ©es volatiles). Ne pas confondre avec le prompt caching de lâAPI, qui cache le prĂ©fixe du contexte (dont les dĂ©finitions dâoutils) cĂŽtĂ© Anthropic.
SĂ©curitĂ© â le point non nĂ©gociable
- Les outils sâexĂ©cutent dans votre code, avec vos authentifications. Le modĂšle ne dĂ©tient aucune clĂ© et nâexĂ©cute rien.
- ConsĂ©quence : toute validation, autorisation et limitation doit ĂȘtre dans votre code. Traiter chaque
inputdâoutil comme une entrĂ©e non fiable (au mĂȘme titre quâun formulaire web) : injection SQL, chemins de fichiers (../), montants, permissions. - Principe du moindre privilĂšge : lâoutil
get_invoiceinterroge la base avec un compte en lecture seule, restreint au tenant de lâutilisateur courant â pas avec le compte admin. - Actions irrĂ©versibles (paiement, suppression, envoi dâemail) : confirmation humaine (human-in-the-loop) cĂŽtĂ© client avant exĂ©cution.
Bloc 7 â Atelier : dĂ©bogueur de flux (15 min)
Ouvrir webpage/index.html (fonctionne hors ligne). Deux modules :
- DĂ©bogueur de flux tool_use : les participants avancent pas Ă pas dans une conversation complĂšte (requĂȘte â
tool_useâ exĂ©cution âtool_resultâ rĂ©ponse finale), voient le JSON exact Ă chaque Ă©tape, et peuvent injecter des erreurs (JSON tronquĂ©,tool_use_idincorrect, erreur dâexĂ©cution) pour observer le traitement attendu. - Validateur de schĂ©ma dâoutil : coller une dĂ©finition dâoutil, obtenir une validation contre la spĂ©cification + suggestions de qualitĂ© (description trop courte, champs non documentĂ©s, etc.).
Consigne dâatelier : chaque binĂŽme doit (a) dĂ©rouler le scĂ©nario nominal, (b) injecter les 3 erreurs et noter pour chacune si elle est syntaxique ou sĂ©mantique et le remĂšde, © faire passer au validateur le schĂ©ma de lâexercice 1 sâil est dĂ©jĂ rĂ©digĂ©.
Bloc 8 â Points de certification et piĂšges (5 min)
Check-list à faire réciter :
-
stop_reason: "tool_use"= le modĂšle attend des rĂ©sultats dâoutils. -
tool_resultpart dans un messagerole: "user", avectool_use_idobligatoire. - Le message assistant contenant le(s)
tool_usedoit ĂȘtre conservĂ© intact dans lâhistorique. - Un
tool_resultpartool_use, tous dans le mĂȘme message user, sinon erreur 400. - La description dâoutil est un prompt ;
input_schemaest du JSON Schema avec racineobject. -
tool_choice:auto/any/toolciblé /none;anyettoolgarantissent un appel. - Faux outil +
tool_choice: tool= sortie structurĂ©e garantie syntaxiquement. - Syntaxique â retry ; sĂ©mantique â affiner le prompt.
-
is_error: truepour signaler un Ă©chec dâexĂ©cution sans casser la boucle. - SĂ©curitĂ© : exĂ©cution cĂŽtĂ© client, moindre privilĂšge, validation des inputs, human-in-the-loop pour lâirrĂ©versible.
Matériel et logistique
- Projeter :
slides/slides.md(format Marp/compatible markdown). - Démos : compte API avec clé de test, Python ℠3.10,
pip install anthropic pydantic. â Les noms de modĂšles et tarifs Ă©voluent : vĂ©rifier https://docs.anthropic.com avant la session. - Page interactive :
webpage/index.htmlâ aucun serveur requis. - PrĂ©voir un plan B hors ligne : captures dâĂ©cran des rĂ©ponses API si le rĂ©seau de la salle est dĂ©faillant.
Erreurs fréquentes des participants (retours de terrain)
- Oublier de renvoyer le message assistant dans lâhistorique â erreur 400 incomprise. Faire reproduire lâerreur volontairement, câest le meilleur vaccin.
- Chercher
response.content[0]au lieu dâitĂ©rer sur les blocs. - Confondre
is_error: true(erreur dâexĂ©cution renvoyĂ©e AU modĂšle) avec une erreur HTTP de lâAPI Anthropic. - Ăcrire des descriptions dâoutils pour des humains (« Cette fonction permet de⊠») au lieu de prompts opĂ©rationnels.
- Mettre tous les champs en
required« par sĂ©curitĂ© » â câest lâinverse dâune sĂ©curitĂ©.