La boucle en un coup d’œil
Chaque session d’agent suit le même cycle :- Recevoir le prompt. Claude reçoit votre prompt, ainsi que le prompt système, les définitions d’outils et l’historique de conversation. Le SDK produit un
SystemMessageavec le sous-type"init"contenant les métadonnées de session. - Évaluer et répondre. Claude évalue l’état actuel et détermine comment procéder. Il peut répondre avec du texte, demander un ou plusieurs appels d’outils, ou les deux. Le SDK produit un
AssistantMessagecontenant le texte et toutes les demandes d’appels d’outils. - Exécuter les outils. Le SDK exécute chaque outil demandé et collecte les résultats. Chaque ensemble de résultats d’outils est renvoyé à Claude pour la décision suivante. Vous pouvez utiliser des hooks pour intercepter, modifier ou bloquer les appels d’outils avant qu’ils ne s’exécutent.
- Répéter. Les étapes 2 et 3 se répètent en cycle. Chaque cycle complet est un tour. Claude continue à appeler les outils et à traiter les résultats jusqu’à ce qu’il produise une réponse sans appels d’outils.
- Retourner le résultat. Le SDK produit un
AssistantMessagefinal avec la réponse textuelle (sans appels d’outils), suivi d’unResultMessageavec le texte final, l’utilisation des tokens, le coût et l’ID de session.
Glob et de réponse avec les résultats. Une tâche complexe (« refactorisez le module d’authentification et mettez à jour les tests ») peut enchaîner des dizaines d’appels d’outils sur plusieurs tours, en lisant des fichiers, en modifiant du code et en exécutant des tests, avec Claude ajustant son approche en fonction de chaque résultat.
Tours et messages
Un tour est un aller-retour dans la boucle : Claude produit une sortie qui inclut des appels d’outils, le SDK exécute ces outils, et les résultats sont renvoyés à Claude automatiquement. Cela se produit sans rendre le contrôle à votre code. Les tours continuent jusqu’à ce que Claude produise une sortie sans appels d’outils, auquel point la boucle se termine et le résultat final est livré. Considérez ce qu’une session complète pourrait ressembler pour le prompt « Corrigez les tests défaillants dans auth.ts ». D’abord, le SDK envoie votre prompt à Claude et produit unSystemMessage avec les métadonnées de session. Ensuite, la boucle commence :
- Tour 1 : Claude appelle
Bashpour exécuternpm test. Le SDK produit unAssistantMessageavec l’appel d’outil, exécute la commande, puis produit unUserMessageavec la sortie (trois défaillances). - Tour 2 : Claude appelle
Readsurauth.tsetauth.test.ts. Le SDK retourne le contenu des fichiers et produit unAssistantMessage. - Tour 3 : Claude appelle
Editpour corrigerauth.ts, puis appelleBashpour relancernpm test. Les trois tests réussissent. Le SDK produit unAssistantMessage. - Tour final : Claude produit une réponse textuelle uniquement sans appels d’outils : « Correction du bug d’authentification, les trois tests réussissent maintenant. » Le SDK produit un
AssistantMessagefinal avec ce texte, puis unResultMessageavec le même texte plus le coût et l’utilisation.
max_turns / maxTurns, qui compte uniquement les tours d’utilisation d’outils. Par exemple, max_turns=2 dans la boucle ci-dessus aurait arrêté avant l’étape d’édition. Vous pouvez également utiliser max_budget_usd / maxBudgetUsd pour limiter les tours en fonction d’un seuil de dépense.
Sans limites, la boucle s’exécute jusqu’à ce que Claude termine de lui-même, ce qui est correct pour les tâches bien délimitées mais peut s’exécuter longtemps sur des prompts ouverts (« améliorez cette base de code »). Définir un budget est une bonne valeur par défaut pour les agents de production. Voir Tours et budget ci-dessous pour la référence des options.
Types de messages
Lorsque la boucle s’exécute, le SDK produit un flux de messages. Chaque message porte un type qui vous indique à quel stade de la boucle il provient. Les cinq types principaux sont :-
SystemMessage: événements du cycle de vie de la session. Le champsubtypeles distingue :"init": métadonnées de session pour l’exécution. Lorsqu’un hookSessionStartouSetups’exécute au démarrage de la session, ses messages du cycle de vie du hook arrivent avant le messageinit"compact_boundary": se déclenche après compaction"informational": bannières de statut en texte brut de la boucle"worker_shutting_down": la boucle se terminera après le tour actuel car l’hôte se ferme ou Remote Control s’est déconnecté
"init"est son propre type dans l’unionSDKMessageplutôt qu’un sous-type deSDKSystemMessage. -
AssistantMessage: émis après chaque réponse de Claude, y compris la réponse textuelle finale. Contient les blocs de contenu textuel et les blocs d’appels d’outils de ce tour. -
UserMessage: émis après chaque exécution d’outil avec le résultat d’outil renvoyé à Claude. Également émis pour toute entrée utilisateur que vous diffusez en boucle. -
StreamEvent: émis uniquement lorsque les messages partiels sont activés. Contient les événements de diffusion API bruts (deltas de texte, chunks d’entrée d’outil). Voir Réponses en flux. -
ResultMessage: marque la fin de la boucle d’agent. Contient le résultat textuel final, l’utilisation des tokens, le coût et l’ID de session. Vérifiez le champsubtypepour déterminer si la tâche a réussi ou a atteint une limite. Un petit nombre d’événements système de fin, tels queprompt_suggestion, peuvent arriver après, donc itérez le flux jusqu’à la fin plutôt que de vous arrêter au résultat. Voir Gérer le résultat.
Gérer les messages
Les messages que vous gérez dépendent de ce que vous construisez :- Résultats finaux uniquement : gérez
ResultMessagepour obtenir la sortie, le coût et si la tâche a réussi ou a atteint une limite. - Mises à jour de progression : gérez
AssistantMessagepour voir ce que Claude fait à chaque tour, y compris les outils qu’il a appelés. - Diffusion en direct : activez les messages partiels (
include_partial_messagesen Python,includePartialMessagesen TypeScript) pour obtenir les messagesStreamEventen temps réel. Voir Réponses en flux en temps réel.
- Python : vérifiez les types de messages avec
isinstance()par rapport aux classes importées declaude_agent_sdk(par exemple,isinstance(message, ResultMessage)). - TypeScript : vérifiez le champ de chaîne
type(par exemple,message.type === "result").AssistantMessageetUserMessageenveloppent le message API brut dans un champ.message, donc les blocs de contenu sont àmessage.message.content, pasmessage.content.
Exemple : Vérifier les types de messages et gérer les résultats
Exemple : Vérifier les types de messages et gérer les résultats
Exécution des outils
Les outils donnent à votre agent la capacité d’agir. Sans outils, Claude ne peut que répondre avec du texte. Avec les outils, Claude peut lire des fichiers, exécuter des commandes, rechercher du code et interagir avec des services externes.Outils intégrés
Le SDK inclut les mêmes outils qui alimentent Claude Code :
Au-delà des outils intégrés, vous pouvez :
- Connecter des services externes avec des serveurs MCP (bases de données, navigateurs, API)
- Définir des outils personnalisés avec des gestionnaires d’outils personnalisés
- Charger les compétences du projet via des sources de paramètres pour des flux de travail réutilisables
Permissions des outils
Claude détermine les outils à appeler en fonction de la tâche, mais vous contrôlez si ces appels sont autorisés à s’exécuter. Vous pouvez approuver automatiquement des outils spécifiques, en bloquer d’autres entièrement, ou exiger une approbation pour tout. Trois options fonctionnent ensemble pour déterminer ce qui s’exécute :allowed_tools/allowedToolsapprouve automatiquement les outils listés. Un agent en lecture seule avec["Read", "Glob", "Grep"]dans sa liste d’outils autorisés exécute ces outils sans demander. Les outils non listés sont toujours disponibles mais nécessitent une permission.disallowed_tools/disallowedToolsbloque les outils listés, indépendamment des autres paramètres. Voir Permissions pour l’ordre dans lequel les règles sont vérifiées avant qu’un outil s’exécute.permission_mode/permissionModecontrôle ce qui se passe pour les outils qui ne sont pas couverts par les règles d’autorisation ou de refus. Voir Mode de permission pour les modes disponibles.
"Bash(npm *)" pour autoriser uniquement des commandes spécifiques. Voir Permissions pour la syntaxe complète des règles.
Lorsqu’un outil est refusé, Claude reçoit un message de rejet comme résultat d’outil et tente généralement une approche différente ou signale qu’il ne pouvait pas procéder.
Exécution parallèle des outils
Lorsque Claude demande plusieurs appels d’outils en un seul tour, les deux SDK peuvent les exécuter de manière concurrente ou séquentielle selon l’outil. Les outils en lecture seule (commeRead, Glob, Grep et les outils MCP marqués comme en lecture seule) peuvent s’exécuter de manière concurrente. Les outils qui modifient l’état (comme Edit, Write et Bash) s’exécutent séquentiellement pour éviter les conflits.
Les outils personnalisés s’exécutent par défaut de manière séquentielle. Pour activer l’exécution parallèle pour un outil personnalisé, définissez readOnlyHint dans ses annotations. Les deux SDK TypeScript et Python utilisent ce nom de champ du SDK MCP.
Contrôler le fonctionnement de la boucle
Vous pouvez limiter le nombre de tours que la boucle prend, combien elle coûte, la profondeur du raisonnement de Claude et si les outils nécessitent une approbation avant de s’exécuter. Tous ces éléments sont des champs surClaudeAgentOptions (Python) / Options (TypeScript).
Tours et budget
Lorsque l’une de ces limites est atteinte, le SDK retourne un
ResultMessage avec un sous-type d’erreur correspondant (error_max_turns ou error_max_budget_usd). Voir Gérer le résultat pour savoir comment vérifier ces sous-types et ClaudeAgentOptions / Options pour la syntaxe.
Avec l’entrée en streaming, un message que vous envoyez pendant qu’un tour est encore en cours reste en attente lorsque ce tour se termine à la limite de tours max, et il démarre son propre tour avec sa propre limite de tours max. Avant la v2.1.205, un message qui arrivait à l’itération finale du tour pouvait être consommé dans le tour qui se termine et perdu sans jamais atteindre le modèle.
Niveau d’effort
L’optioneffort contrôle la profondeur du raisonnement que Claude applique. Les niveaux d’effort inférieur utilisent moins de tokens par tour et réduisent le coût. Tous les modèles ne supportent pas le paramètre d’effort. Voir Effort pour savoir quels modèles le supportent.
Si vous ne définissez pas
effort, les deux SDK laissent le paramètre non défini et s’en remettent au comportement par défaut du modèle.
effort échange la latence et le coût des tokens pour la profondeur du raisonnement dans chaque réponse. Extended thinking est une fonctionnalité distincte qui produit des blocs de chaîne de pensée visibles dans la sortie. Ils sont indépendants : vous pouvez définir effort: "low" avec extended thinking activé, ou effort: "max" sans lui.effort dans les options de niveau supérieur query() pour la session entière, ou par sous-agent avec le champ effort sur AgentDefinition pour remplacer le niveau de session.
Mode de permission
L’option de mode de permission (permission_mode en Python, permissionMode en TypeScript) contrôle si l’agent demande une approbation avant d’utiliser les outils :
Pour les applications interactives, utilisez
"default" avec un rappel d’approbation d’outil pour afficher les invites d’approbation. Pour les agents autonomes sur une machine de développement, "acceptEdits" approuve automatiquement les éditions de fichiers et les commandes communes du système de fichiers (mkdir, touch, mv, cp, etc.) tout en gardant les autres commandes Bash derrière les règles d’autorisation. Réservez "bypassPermissions" pour CI, les conteneurs ou d’autres environnements isolés. Voir Permissions pour les détails complets.
Modèle
Si vous ne définissez pasmodel, le SDK utilise la valeur par défaut de Claude Code, qui dépend de votre méthode d’authentification et de votre abonnement. Définissez-le explicitement (par exemple, model="claude-sonnet-5") pour épingler un modèle spécifique ou pour utiliser un modèle plus petit pour des agents plus rapides et moins chers. Voir modèles pour les ID disponibles.
La fenêtre de contexte
La fenêtre de contexte est la quantité totale d’informations disponibles pour Claude pendant une session. Elle ne se réinitialise pas entre les tours au sein d’une session. Tout s’accumule : le prompt système, les définitions d’outils, l’historique de conversation, les entrées d’outils et les sorties d’outils. Le contenu qui reste le même entre les tours (prompt système, définitions d’outils, CLAUDE.md) est automatiquement mis en cache par prompt, ce qui réduit le coût et la latence pour les préfixes répétés.Ce qui consomme du contexte
Voici comment chaque composant affecte le contexte dans le SDK :
Les grandes sorties d’outils consomment un contexte significatif. Lire un gros fichier ou exécuter une commande avec une sortie détaillée peut utiliser des milliers de tokens en un seul tour. Le contexte s’accumule au fil des tours, donc les sessions plus longues avec de nombreux appels d’outils accumulent beaucoup plus de contexte que les courtes.
Compaction automatique
Lorsque la fenêtre de contexte approche de sa limite, le SDK compacte automatiquement la conversation : il résume l’historique plus ancien pour libérer de l’espace, en gardant vos échanges les plus récents et les décisions clés intacts. Le SDK émet un message avectype: "system" et subtype: "compact_boundary" dans le flux lorsque cela se produit (en Python c’est un SystemMessage ; en TypeScript c’est un type SDKCompactBoundaryMessage distinct).
La compaction remplace les messages plus anciens par un résumé, donc les instructions spécifiques du début de la conversation peuvent ne pas être préservées. Les règles persistantes appartiennent à CLAUDE.md (chargé via settingSources) plutôt qu’au prompt initial, car le contenu CLAUDE.md est réinjecté à chaque requête.
Vous pouvez personnaliser le comportement de compaction de plusieurs façons :
- Instructions de résumé dans CLAUDE.md : Le compacteur lit votre CLAUDE.md comme tout autre contexte, donc vous pouvez inclure une section lui indiquant ce qu’il faut préserver lors de la résumé. L’en-tête de section est libre (pas une chaîne magique) ; le compacteur correspond sur l’intention.
- Hook
PreCompact: Exécutez une logique personnalisée avant la compaction, par exemple pour archiver la transcription complète. Le hook reçoit un champtrigger(manualouauto). Voir hooks. - Compaction manuelle : Envoyez
/compactcomme chaîne de prompt pour déclencher la compaction à la demande. Les commandes envoyées de cette façon sont des entrées SDK, pas des raccourcis CLI uniquement. Voir commandes dans le SDK.
Exemple : Instructions de résumé dans CLAUDE.md
Exemple : Instructions de résumé dans CLAUDE.md
Ajoutez une section au CLAUDE.md de votre projet indiquant au compacteur ce qu’il faut préserver. Le nom d’en-tête n’est pas spécial ; utilisez n’importe quel label clair.
CLAUDE.md
Garder le contexte efficace
Quelques stratégies pour les agents de longue durée :- Utilisez des sous-agents pour les sous-tâches. Chaque sous-agent commence avec une conversation fraîche (pas d’historique de messages antérieurs, bien qu’il charge son propre prompt système et le contexte au niveau du projet comme CLAUDE.md). Il ne voit pas les tours du parent, et seule sa réponse finale retourne au parent comme résultat d’outil. Le contexte de l’agent principal croît par ce résumé, pas par la transcription complète de la sous-tâche. Voir Ce que les sous-agents héritent pour les détails.
- Soyez sélectif avec les outils. Chaque définition d’outil prend de l’espace de contexte. Utilisez le champ
toolssurAgentDefinitionpour délimiter les sous-agents à l’ensemble minimum dont ils ont besoin. - Surveillez les coûts des serveurs MCP. La recherche d’outils MCP diffère les schémas d’outils MCP par défaut et les charge à la demande. Lorsque la recherche d’outils est désactivée, sur Google Cloud’s Agent Platform, ou derrière une
ANTHROPIC_BASE_URLnon-propriétaire, chaque serveur MCP ajoute tous ses schémas d’outils à chaque requête, donc quelques serveurs avec de nombreux outils peuvent consommer un contexte significatif avant que l’agent ne fasse aucun travail. - Utilisez un effort inférieur pour les tâches de routine. Définissez effort à
"low"pour les agents qui n’ont besoin que de lire des fichiers ou de lister des répertoires. Cela réduit l’utilisation des tokens et le coût.
Sessions et continuité
Chaque interaction avec le SDK crée ou continue une session. Capturez l’ID de session deResultMessage.session_id (disponible dans les deux SDK) pour reprendre plus tard. Le SDK TypeScript l’expose également comme un champ direct sur le SystemMessage init ; en Python, il est imbriqué dans SystemMessage.data.
Lorsque vous reprenez, le contexte complet des tours précédents est restauré : les fichiers qui ont été lus, l’analyse qui a été effectuée et les actions qui ont été prises. Vous pouvez également forcer une session pour vous brancher dans une approche différente sans modifier l’original.
Voir Gestion des sessions pour le guide complet sur les modèles de reprise, de continuation et de bifurcation.
En Python,
ClaudeSDKClient gère automatiquement les ID de session sur plusieurs appels. Voir la référence du SDK Python pour les détails.Gérer le résultat
Lorsque la boucle se termine, leResultMessage vous indique ce qui s’est passé et vous donne la sortie. Le champ subtype (disponible dans les deux SDK) est le moyen principal de vérifier l’état de terminaison.
Le champ
result (la sortie textuelle finale) n’est présent que sur la variante success, donc vérifiez toujours le sous-type avant de le lire. Tous les sous-types de résultat portent total_cost_usd, usage, num_turns et session_id afin que vous puissiez suivre le coût et reprendre même après des erreurs. En Python, total_cost_usd et usage sont typés comme optionnels et peuvent être None sur certains chemins d’erreur, donc gardez-les avant de les formater. Voir Suivi des coûts et de l’utilisation pour les détails sur l’interprétation des champs usage.
Lorsqu’une requête se termine sur un résultat d’erreur :
- Un appel
query()unique produit le message de résultat final, puis lève une erreur qui inclut le texte d’échec, tel queReached maximum number of turns. La levée est intentionnelle — enveloppez la boucle dans un bloc try si votre code doit continuer au-delà. Le processus Claude Code sous-jacent se termine également avec un code non nul. - Une session d’entrée en streaming reste active, et vous pouvez continuer à envoyer des messages.
stop_reason (string | null en TypeScript, str | None en Python) indiquant pourquoi le modèle a arrêté de générer sur son tour final. Les valeurs courantes sont end_turn (le modèle a terminé normalement), max_tokens (limite de token de sortie atteinte) et refusal (le modèle a refusé la requête). Sur les sous-types de résultat d’erreur, stop_reason porte la valeur de la dernière réponse d’assistant avant la fin de la boucle. Pour détecter les refus, vérifiez stop_reason === "refusal" (TypeScript) ou stop_reason == "refusal" (Python). Voir SDKResultMessage (TypeScript) ou ResultMessage (Python) pour le type complet.
Hooks
Les Hooks sont des rappels qui se déclenchent à des points spécifiques de la boucle : avant qu’un outil s’exécute, après son retour, lorsque l’agent termine, et ainsi de suite. Certains hooks couramment utilisés sont :
Les hooks s’exécutent dans le processus de votre application, pas à l’intérieur de la fenêtre de contexte de l’agent, donc ils ne consomment pas de contexte. Les hooks peuvent également court-circuiter la boucle : un hook
PreToolUse qui rejette un appel d’outil l’empêche de s’exécuter, et Claude reçoit le message de rejet à la place.
Les deux SDK supportent tous les événements ci-dessus. Le SDK TypeScript inclut des événements supplémentaires que Python ne supporte pas encore. Voir Contrôler l’exécution avec des hooks pour la liste complète des événements, la disponibilité par SDK et l’API de rappel complète.
Tout mettre ensemble
Cet exemple combine les concepts clés de cette page dans un seul agent qui corrige les tests défaillants. Il configure l’agent avec les outils autorisés (approuvés automatiquement afin que l’agent s’exécute de manière autonome), les paramètres du projet et les limites de sécurité sur les tours et l’effort de raisonnement. Lorsque la boucle s’exécute, elle capture l’ID de session pour une reprise potentielle, gère le résultat final et imprime le coût total. Parce qu’un appel uniquequery() lève une exception après avoir produit un résultat d’erreur, la boucle est enveloppée dans un bloc try afin que le script se termine proprement lorsqu’une limite est atteinte.
Étapes suivantes
Maintenant que vous comprenez la boucle, voici où aller en fonction de ce que vous construisez :- Vous n’avez pas encore exécuté un agent ? Commencez par le démarrage rapide pour obtenir le SDK installé et voir un exemple complet s’exécutant de bout en bout.
- Prêt à vous connecter à votre projet ? Chargez CLAUDE.md, les compétences et les hooks du système de fichiers afin que l’agent suive automatiquement les conventions de votre projet.
- Construisez une interface utilisateur interactive ? Activez la diffusion pour afficher le texte en direct et les appels d’outils lorsque la boucle s’exécute.
- Avez-vous besoin d’un contrôle plus strict sur ce que l’agent peut faire ? Verrouillez l’accès aux outils avec les permissions et utilisez les hooks pour auditer, bloquer ou transformer les appels d’outils avant qu’ils ne s’exécutent.
- Exécutez des tâches longues ou coûteuses ? Déléguez le travail isolé aux sous-agents pour garder votre contexte principal maigre.