Claude Platform Docs
MessagesGestion du contexte

Messages système et changements d'outils en cours de conversation

Modifiez les instructions système ou la disponibilité des outils en cours de conversation sans invalider le préfixe mis en cache qui les précède.

Les instructions système se trouvent normalement dans le champ system de premier niveau, avant chaque message de la conversation. Cette position est idéale pour le « prompt caching » (mise en cache des prompts) : le « system prompt » (invite système) fait partie du préfixe stable, de sorte que les tours suivants atteignent le cache. C'est en revanche une mauvaise position pour les instructions dont vous ne découvrez le besoin qu'en cours de session, car modifier le champ system de premier niveau change le tout début du prompt et invalide le cache pour tout ce qui suit.

Les messages système en cours de conversation comblent cette lacune. Vous ajoutez un message {"role": "system"} à l'endroit de la conversation où la nouvelle instruction devient pertinente, au lieu de modifier le champ system de premier niveau. Le préfixe mis en cache reste identique, de sorte que la requête suivante le lit toujours depuis le cache, et la nouvelle instruction est toujours appliquée en tant qu'instruction système plutôt qu'en tant que texte utilisateur ordinaire.

Modifications d'outils en cours de conversation

Le tableau tools se situe encore plus tôt dans le préfixe haché de la requête que le champ system de premier niveau, de sorte que le modifier invalide le cache des prompts pour l'ensemble de la conversation. Les modifications d'outils en cours de conversation sont l'équivalent, pour les outils, des messages système en cours de conversation. Au lieu de figer la liste d'outils pour toute la durée de la conversation, vous modifiez les outils proposés au modèle entre les tours : déclarez l'ensemble complet des outils dans tools dès le départ, puis utilisez des blocs tool_addition et tool_removal pour proposer un outil au modèle, ou le retirer, à partir d'un point précis de la conversation. Le tableau tools lui-même ne change jamais, de sorte que le préfixe mis en cache reste intact. Les modifications d'outils en cours de conversation sont en bêta et utilisent l'en-tête bêta inline-tools-2026-09-15 sur l'API Claude.

tool_addition et tool_removal sont des blocs de contenu du tableau content d'un message role: "system", et ils peuvent être combinés avec des blocs text dans le même message. Le message suit les règles de placement de tout message système en cours de conversation, avec une restriction supplémentaire après un tour mis en pause (voir Limitations), et la modification s'applique à partir de ce point de la conversation. Le champ tool de chaque bloc référence un outil plutôt que d'en définir un : {"type": "tool_reference", "name": "..."} désigne un outil déclaré dans le tableau tools de la requête, et les outils du connecteur MCP peuvent être référencés individuellement avec mcp_tool_reference (server_name et name) ou en tant qu'ensemble d'outils complet avec mcp_toolset_reference (server_name). Référencer un nom qui n'est pas déclaré dans tools renvoie une erreur 400 (sur l'API Claude, avec error.details.error_code défini sur tool_reference_unresolved). Un bloc tool_addition peut à la place contenir la définition complète de l'outil, ce que l'en-tête mid-conversation-tool-changes-2026-07-01 ne prend pas en charge.

Chaque outil déclaré dans tools est proposé au modèle dès le début de la conversation, sauf s'il est déclaré avec defer_loading: true, ce qui le maintient en retrait jusqu'à ce qu'un bloc tool_addition le fasse apparaître. tool_addition propose également à nouveau un outil qu'un tool_removal antérieur a retiré.

La requête suivante déclare get_weather dans tools, puis le retire après le premier tour utilisateur avec un bloc tool_removal. La requête envoie l'en-tête bêta inline-tools-2026-09-15.

client = anthropic.Anthropic()

response = client.beta.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    betas=["inline-tools-2026-09-15"],
    # L'ensemble complet des outils est déclaré dès le départ et ne change jamais, donc le
    # préfixe mis en cache reste intact.
    tools=[
        {
            "name": "get_weather",
            "description": "Get the current weather for a location.",
            "input_schema": {
                "type": "object",
                "properties": {
                    "location": {"type": "string", "description": "City name"},
                },
                "required": ["location"],
            },
        },
    ],
    messages=[
        {
            "role": "user",
            "content": "Say OK.",
        },
        # Retirez get_weather à partir de ce point. Le bloc référence
        # l'outil par son nom au lieu de modifier `tools`, donc les tours précédents restent
        # identiques à l'octet près et le cache est toujours atteint.
        {
            "role": "system",
            "content": [
                {
                    "type": "tool_removal",
                    "tool": {"type": "tool_reference", "name": "get_weather"},
                },
            ],
        },
    ],
)

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

Définir des outils dans un message (bêta)

Avec l'en-tête bêta inline-tools-2026-09-15, un bloc tool_addition peut définir un outil par valeur, en contenant sa définition complète, au lieu de le désigner par référence. Cela vous permet d'introduire un outil inconnu au début de la conversation, ou dont le schéma change ultérieurement, en ajoutant un message role: "system". Le tableau tools et tous les messages antérieurs restent exactement tels qu'ils ont été envoyés, de sorte que le cache des prompts est toujours atteint et que seul le message ajouté est traité comme une nouvelle entrée. La seule exception, un tableau tools sans aucun outil non différé, est traitée dans les règles ci-dessous. L'en-tête couvre également l'ajout et le retrait d'outils par référence, vous n'avez donc pas besoin d'envoyer également mid-conversation-tool-changes-2026-07-01.

Encapsulez la définition dans un objet tool de type tool_definition. La definition est une entrée de tools, comme un outil personnalisé ou un outil client ou serveur défini par Anthropic, avec sa configuration habituelle, y compris cache_control et defer_loading. Pendant la bêta, certains types d'outils (dont l'outil d'utilisation de l'ordinateur) ne peuvent pas encore être définis dans un message et renvoient une erreur 400 qui l'indique ; déclarez-les dans tools et ajoutez-les par référence. Par exemple, pour définir un outil personnalisé en cours de conversation :

{
  "role": "system",
  "content": [
    {
      "type": "tool_addition",
      "tool": {
        "type": "tool_definition",
        "definition": {
          "name": "db_query",
          "description": "Run a read-only SQL query against the analytics database.",
          "input_schema": {
            "type": "object",
            "properties": { "sql": { "type": "string" } },
            "required": ["sql"]
          }
        }
      }
    }
  ]
}

À partir de cette position, le modèle peut appeler l'outil de la même manière qu'il appelle un outil déclaré dans tools. Renvoyer une définition identique ne change rien, de sorte qu'un client peut la renvoyer sans risque, par exemple lors d'une nouvelle tentative.

La requête suivante conserve get_weather dans tools et définit db_query après le premier tour utilisateur :

client = anthropic.Anthropic()

response = client.beta.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    betas=["inline-tools-2026-09-15"],
    # Conservez au moins un outil non différé dans `tools`, afin qu'un outil défini
    # plus tard ne modifie pas le début du prompt rendu.
    tools=[
        {
            "name": "get_weather",
            "description": "Get the current weather for a location.",
            "input_schema": {
                "type": "object",
                "properties": {
                    "location": {"type": "string", "description": "City name"},
                },
                "required": ["location"],
            },
        },
    ],
    messages=[
        {"role": "user", "content": "How many orders shipped yesterday?"},
        # À partir d'ici, définissez db_query par valeur. `tools` et les
        # messages précédents restent identiques à l'envoi, donc le cache est toujours atteint.
        {
            "role": "system",
            "content": [
                {
                    "type": "tool_addition",
                    "tool": {
                        "type": "tool_definition",
                        "definition": {
                            "name": "db_query",
                            "description": "Run a read-only SQL query against the analytics database.",
                            "input_schema": {
                                "type": "object",
                                "properties": {"sql": {"type": "string"}},
                                "required": ["sql"],
                            },
                        },
                    },
                },
            ],
        },
    ],
)

for block in response.content:
    if block.type == "tool_use":
        print(block.name, block.input)

Le content de la réponse inclut un bloc tool_use pour le nouvel outil, par exemple :

{
  "type": "tool_use",
  "id": "toolu_01A09q90qw90lq917835lq9",
  "name": "db_query",
  "input": {
    "sql": "SELECT COUNT(*) FROM orders WHERE shipped_at::date = CURRENT_DATE - 1"
  }
}

Pour modifier le schéma d'un outil, ou pour faire passer un outil serveur à une version plus récente, envoyez une définition différente sous le même nom. La nouvelle définition remplace l'ancienne à partir de cette position. Une définition qui réutilise le nom d'un outil d'un type différent renvoie une erreur 400 avec error.details.error_code défini sur tool_name_conflict. Une version plus récente du même outil ne compte pas comme un type différent. tool_removal prend toujours une référence, et un outil retiré peut être défini ou proposé à nouveau ultérieurement.

Quelques règles découlent de l'endroit où la définition est rendue :

  • Déclarez dès le départ ce que vous connaissez. Un outil que vous connaissez dès la première requête a sa place dans tools, avec defer_loading: true et une référence tool_addition ultérieure si le modèle ne doit pas encore le voir. Ne définissez par valeur que ce qui est inconnu lors de la première requête ou qui change ultérieurement.
  • Conservez au moins un outil non différé dans tools. Une conversation dont le tableau tools ne contient aucun outil non différé est acceptée, mais le premier outil qu'elle définit par valeur modifie le début du prompt rendu, ce qui coûte un « cache miss » (échec de cache) complet sur cette requête. Un outil de recherche d'outils compte comme non différé.
  • Les types d'outils datés conservent leurs propres en-têtes bêta. Si un outil serveur que vous définissez par valeur nécessite son propre en-tête bêta, envoyez cet en-tête sur chaque requête ultérieure de la conversation.
  • cache_control se place sur le bloc ou dans la définition, pas les deux, et compte dans la limite de points d'arrêt de la requête. Une définition différée ne peut pas porter cache_control.

Une requête renvoie une erreur 400 avec error.details.error_code défini sur available_tools_limit_exceeded lorsque l'une de ces limites est dépassée :

  • Plus de 10 000 outils différés sont disponibles après un message quelconque.
  • Plus de 10 000 outils définis après le premier message utilisateur sont disponibles après un message quelconque.
  • Les définitions d'outils envoyées après le premier message utilisateur qui sont encore disponibles après un message quelconque totalisent plus de 4 Mo (4 194 304 octets).
  • Le texte d'outils rendu dépasse 4 Mo (4 194 304 octets).

Ajouter un serveur MCP en cours de conversation (bêta)

Pour ajouter un serveur du connecteur MCP en cours de conversation, envoyez l'en-tête bêta mcp-client-2026-09-15 avec inline-tools-2026-09-15. La definition d'un bloc tool_addition peut alors être un mcp_toolset, de sorte que les outils du serveur deviennent disponibles sans modifier tools. Indiquez les détails de connexion du serveur dans mcp_servers comme d'habitude, puis ajoutez l'ensemble d'outils à l'endroit où le serveur est devenu disponible :

{
  "role": "system",
  "content": [
    {
      "type": "tool_addition",
      "tool": {
        "type": "tool_definition",
        "definition": { "type": "mcp_toolset", "mcp_server_name": "calendar" }
      }
    }
  ]
}

L'objet mcp_toolset est le même que celui que vous placeriez dans tools, y compris default_config et configs. Un bloc tool_addition ne contient jamais d'URL de serveur ni de jeton. Ceux-ci restent dans mcp_servers.

La requête suivante conserve get_weather dans tools, liste le serveur de calendrier dans mcp_servers et ajoute l'ensemble d'outils du serveur après le premier tour utilisateur :

client = anthropic.Anthropic()

response = client.beta.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    betas=["inline-tools-2026-09-15", "mcp-client-2026-09-15"],
    mcp_servers=[
        {
            "type": "url",
            "url": "https://mcp.example.com/calendar",
            "name": "calendar",
            "authorization_token": "YOUR_TOKEN",
        },
    ],
    tools=[
        {
            "name": "get_weather",
            "description": "Get the current weather for a location.",
            "input_schema": {
                "type": "object",
                "properties": {
                    "location": {"type": "string", "description": "City name"},
                },
                "required": ["location"],
            },
        },
    ],
    messages=[
        {"role": "user", "content": "What's on my calendar tomorrow?"},
        # Rendre les outils du serveur de calendrier disponibles à partir de ce point.
        # Le bloc nomme le serveur ; il ne contient jamais d'URL ni de jeton.
        {
            "role": "system",
            "content": [
                {
                    "type": "tool_addition",
                    "tool": {
                        "type": "tool_definition",
                        "definition": {
                            "type": "mcp_toolset",
                            "mcp_server_name": "calendar",
                        },
                    },
                },
            ],
        },
    ],
)

# La réponse commence par un bloc mcp_tool_listing pour le serveur de calendrier,
# vérifiez donc le type de chaque bloc au lieu de lire content[0].
for block in response.content:
    match block.type:
        case "mcp_tool_listing":
            print(block.mcp_server_name, [tool.name for tool in block.tools])
        case "text":
            print(block.text)

Avec mcp-client-2026-09-15, une réponse pour laquelle l'API a récupéré la liste d'outils d'un serveur commence par un bloc mcp_tool_listing, un pour chaque serveur récupéré. Si votre code lit content[0], ignorez ces blocs. Renvoyez le message de l'assistant sans modification, ce bloc compris, et continuez à envoyer mcp-client-2026-09-15 sur chaque requête qui le contient. Les requêtes ultérieures utilisent alors la liste enregistrée au lieu d'interroger à nouveau le serveur. Pour figer vous-même un ensemble d'outils, copiez cette liste dans le champ tools du mcp_toolset, comme décrit dans Figer la liste d'outils d'un serveur MCP.

mcp-client-2026-09-15 inclut tout ce que fait mcp-client-2025-11-20, vous n'avez donc pas besoin d'envoyer les deux. Ces fonctionnalités sont disponibles sur l'API Claude. Les requêtes qui utilisent le connecteur MCP conservent ses conditions de conservation des données.

Quand utiliser un message système en cours de conversation

La mise en cache des prompts hache le préfixe de la requête dans l'ordre : tools, puis system, puis messages. Un « cache hit » (succès de cache) nécessite que le préfixe corresponde exactement à une requête récente, octet par octet, jusqu'au point d'arrêt du cache.

Cet ordre signifie que le champ system de premier niveau se situe tout au début du préfixe haché. Toute modification de ce champ, même l'ajout d'une phrase, produit un hachage différent, et la requête manque le cache pour l'invite système et pour chaque message mis en cache qui la suit.

Les messages système en cours de conversation vous permettent plutôt d'ajouter l'instruction à la fin de l'historique des messages. Tout ce qui précède la nouvelle instruction reste inchangé, de sorte que l'entrée de cache existante correspond toujours, et seul le nouveau message est traité comme une nouvelle entrée.

Quelques situations où cela compte :

  • Changements de politique ou de persona en cours de session. Une longue session agentique nécessite une nouvelle contrainte (« à partir de maintenant, écrivez toutes les requêtes SQL sous forme de requêtes paramétrées ») après des dizaines de tours mis en cache. L'ajouter au champ system de premier niveau entraînerait le retraitement de tout l'historique.
  • Contexte par tour qui doit faire autorité. Vous souhaitez injecter une note de fraîcheur, une échéance de session ou un changement de disponibilité des outils avec un poids de niveau système, et cela change trop souvent pour figurer dans le préfixe mis en cache.
  • Rappels par tour qui ne doivent pas s'accumuler. Un harnais relance le modèle après chaque lot de résultats d'outils (« demandez les lectures indépendantes ensemble », « l'utilisateur n'a pas eu de vos nouvelles depuis un moment ») et souhaite que le modèle ne voie que la copie la plus récente. Un message système limité au tour est rendu pendant un tour puis ne coûte plus rien, sans rien supprimer de l'historique.
  • Changements d'état observés par votre application. Votre application remarque quelque chose que Claude doit traiter comme un fait de niveau opérateur : des fichiers ont changé sur le disque, l'utilisateur a activé un paramètre d'approbation automatique, les outils disponibles ont changé, ou le budget de tokens restant est passé sous un seuil.
  • Saisie utilisateur qui ne doit pas interrompre une boucle agentique. Un utilisateur tape une question de suivi pendant que Claude exécute encore des outils pour la requête précédente. La relayer sous forme de message système après le résultat d'outil suivant permet à Claude d'intégrer la nouvelle saisie au travail qu'il effectue déjà, au lieu de la traiter comme une nouvelle requête vers laquelle basculer. Sur Claude Sonnet 5.5 et Claude Haiku 5.5, ajoutez plutôt les mots de l'utilisateur sous forme de bloc text après le dernier tool_result dans le même message user. Consultez Placement après les résultats d'outils.
  • Changements de mode qui accordent des autorisations permanentes. Un mode au niveau de la session peut utiliser un message système en cours de conversation pour accorder un consentement permanent à une capacité coûteuse, comme le lancement automatique de workflows multiagents, avec un bref rappel tous les quelques tours et un avis de sortie lorsque le mode est désactivé. Pour un exemple détaillé, consultez Créer un mode d'orchestration.

Dans tous ces cas, vous pourriez placer l'instruction dans un message user ordinaire, et Claude suit bien les instructions qui arrivent dans les tours utilisateur. La différence tient à la priorité : un message user est traité comme provenant de l'utilisateur final, tandis qu'un message system est traité comme provenant de vous, l'opérateur de l'application. Lorsque les deux entrent en conflit, les instructions système prévalent ; utilisez donc le rôle system pour les faits et contraintes de niveau opérateur qui doivent s'appliquer même si l'utilisateur final demande autre chose. Un message système en cours de conversation conserve cette priorité de niveau opérateur sans payer le coût d'échec de cache lié à la modification du champ system de premier niveau.

Fonctionnement

Ajoutez un message avec "role": "system" au tableau messages. Utilisez une chaîne simple ou des blocs de contenu pour content, comme pour un tour user ou assistant. L'instruction s'applique à partir de ce point de la conversation. Lorsque des instructions entrent en conflit, les messages système ultérieurs prévalent sur les précédents, et les messages système en cours de conversation prévalent sur le champ system de premier niveau pour les tours qui les suivent.

Vous pouvez toujours définir le champ system de premier niveau pour les instructions qui doivent s'appliquer à l'ensemble de la conversation. Réservez les messages système en cours de conversation aux instructions qui ne deviennent pertinentes que plus tard, ou que vous souhaitez ajouter sans invalider le préfixe mis en cache.

Un message role: "system" peut également porter output_config.effort pour modifier le niveau d'effort en cours de conversation. Cette fonctionnalité est en bêta sur Claude Fable 5.1, Claude Mythos 5.1, Claude Opus 5.5, Claude Opus 5, Claude Sonnet 5.5 et Claude Haiku 5.5 sur l'API Claude et Google Cloud, et nécessite l'en-tête bêta mid-conversation-output-config-2026-07-01. Sur Amazon Bedrock, elle est en bêta sur Claude Fable 5.1, Claude Mythos 5.1 et Claude Opus 5.5, avec la même valeur bêta. Claude Opus 5 ne la prend pas en charge sur Amazon Bedrock. Consultez Effort par message.

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    # Mise en cache automatique des prompts : chaque requête met en cache la conversation jusqu'ici,
    # et la requête suivante lit le préfixe inchangé depuis le cache.
    cache_control={"type": "ephemeral"},
    system="You are a code review assistant. Be concise.",
    messages=[
        {
            "role": "user",
            "content": "Review process() in utils.py for performance issues.",
        },
        {
            "role": "assistant",
            "content": "The list comprehension is fine for small inputs. For large inputs, consider a generator to avoid materializing the full list.",
        },
        {
            "role": "user",
            "content": "Now review the calling code that invokes process().",
        },
        # En cours de session, le relecteur réalise que toutes les suggestions doivent
        # aussi respecter la politique de typage strict de l'équipe. Ajouter
        # l'instruction ici garde les tours précédents identiques à l'octet près, donc le
        # préfixe mis en cache par la requête précédente est toujours lu depuis le cache.
        {
            "role": "system",
            "content": "From now on, every suggestion must include explicit type annotations.",
        },
    ],
)

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

Cet exemple active la mise en cache automatique avec le champ cache_control de premier niveau. La mise en cache des prompts est facultative (opt-in) : si une requête ne comporte aucun champ cache_control (automatique ou point d'arrêt explicite), rien n'est mis en cache et chaque requête paie le prix normal des tokens d'entrée pour l'ensemble de la conversation. Avec la mise en cache activée, l'ajout du message système laisse inchangés les tours déjà mis en cache, de sorte que la requête qui porte la nouvelle instruction les lit toujours depuis le cache au lieu de les traiter à nouveau. La mise en cache exige également que la conversation atteigne la longueur minimale de prompt pouvant être mise en cache ; un exemple aussi court que celui-ci se situe en dessous, de sorte que cache_creation_input_tokens et cache_read_input_tokens restent à 0 jusqu'à ce que la conversation s'allonge.

Un message système en cours de conversation qui porte du contenu (blocs text, tool_addition ou tool_removal) doit suivre immédiatement un tour user (ou un tour assistant se terminant par un résultat d'outil serveur), et doit soit être la dernière entrée de messages, soit être immédiatement suivi d'un tour assistant. Un message user qui contient des blocs tool_result compte : dans une boucle agentique, vous pouvez placer le message système juste après les résultats d'outils, avant le tour suivant de Claude. Toute autre position pour un message qui porte du contenu, y compris entre un bloc tool_use de l'assistant et le tool_result qui y répond, renvoie une erreur 400. Un message avec un content vide qui définit uniquement output_config.effort est accepté n'importe où dans messages. Les messages system consécutifs sont évalués ensemble, de sorte qu'un message ne portant que l'effort placé à côté d'un message qui porte du contenu suit la règle applicable au contenu.

Placement après les résultats d'outils

Dans une boucle agentique, le message système se place après le message user qui fournit les résultats d'outils. Sur la plupart des modèles, c'est également là que votre application peut relayer la saisie que l'utilisateur a tapée pendant que Claude travaillait, afin que le nouveau contexte soit intégré sans redémarrer le tour (pour Claude Sonnet 5.5 et Claude Haiku 5.5, consultez la fin de cette section) :

[
  { "role": "user", "content": "Run the test suite and fix any failures." },
  {
    "role": "assistant",
    "content": [{ "type": "tool_use", "id": "toolu_01", "name": "run_tests", "input": {} }]
  },
  {
    "role": "user",
    "content": [
      { "type": "tool_result", "tool_use_id": "toolu_01", "content": "12 passed, 0 failed" }
    ]
  },
  {
    "role": "system",
    "content": "The user sent the following message while you were working: also update the changelog before you finish."
  }
]

Formulez le contenu système comme du contexte plutôt que comme un ordre qui prend le pas sur l'utilisateur. Énoncez le fait (« une nouvelle saisie est arrivée de l'utilisateur : X », « le budget de tokens restant est maintenant de Y ») et laissez Claude agir en conséquence. Claude est entraîné à résister aux instructions qui semblent aller à l'encontre de l'utilisateur, et cette protection s'applique toujours au rôle système ; une formulation telle que « ignorez ce que l'utilisateur a dit » est donc moins efficace que l'énoncé de ce qui a changé.

Ce modèle sert à relayer la saisie de l'utilisateur final de la conversation elle-même. Ne l'utilisez pas pour transmettre la sortie d'outils, des documents récupérés ou tout autre contenu tiers ; conservez ce contenu dans des blocs tool_result (voir Limitations).

Sur Claude Sonnet 5.5 et Claude Haiku 5.5, transmettez plutôt les mots de l'utilisateur dans le tour utilisateur. Ces modèles sont entraînés à résister à l'injection de prompts via les résultats d'outils, de sorte qu'ils peuvent traiter un message système placé juste après un résultat d'outil comme du texte non fiable et l'ignorer. Ajoutez les mots de l'utilisateur sous forme de bloc text après le dernier tool_result dans le même message user. Conservez les avis du harnais, comme les rappels, dans un message système en cours de conversation distinct après ce message user, et ne placez jamais un avis et les mots de l'utilisateur dans le même bloc :

[
  { "role": "user", "content": "Run the test suite and fix any failures." },
  {
    "role": "assistant",
    "content": [{ "type": "tool_use", "id": "toolu_01", "name": "run_tests", "input": {} }]
  },
  {
    "role": "user",
    "content": [
      { "type": "tool_result", "tool_use_id": "toolu_01", "content": "12 passed, 0 failed" },
      { "type": "text", "text": "Also update the changelog before you finish." }
    ]
  }
]

Pour en savoir plus sur ce comportement, consultez Rédiger des prompts pour Claude Sonnet 5.5 et Rédiger des prompts pour Claude Haiku 5.5.

Messages système limités au tour

Pour limiter un message role: "system" au tour en cours, définissez son champ clear_at. Il accepte l'une de deux valeurs :

  • "never" (par défaut) : le message est rendu à sa position sur chaque requête qui l'inclut. Omettre le champ revient au même.
  • "next_user_message" : le message est limité au tour. Son texte n'est rendu que tant qu'aucun message role: "user" ne le suit dans messages. Un message utilisateur qui ne porte que des blocs tool_result compte ici comme un message utilisateur. Dès qu'un message utilisateur ultérieur existe, le message est effacé : il reste dans le tableau mais ne rend rien et ne coûte aucun token d'entrée, sur cette requête et sur toutes les suivantes.

Les messages système limités au tour sont en bêta. Incluez l'en-tête bêta mid-conversation-system-clear-at-2026-08-21. Sans celui-ci, clear_at est rejeté en tant que champ inconnu.

{
  "role": "system",
  "clear_at": "next_user_message",
  "content": "First privately list what you need next; then request every item that doesn't depend on another's result in this one response."
}

L'usage principal est un rappel par tour dans une boucle d'outils. Ajoutez le rappel après le message tool_result chaque fois que vous souhaitez que le modèle le voie, et laissez chaque copie antérieure à sa place. Le modèle ne voit que les copies qui suivent le dernier message utilisateur, de sorte que le rappel ne s'accumule jamais. Rien de ce qui précède dans messages ne change, de sorte que le cache des prompts continue de correspondre. Sur Claude Fable 5.1, Claude Opus 5.5, Claude Sonnet 5.5 et Claude Haiku 5.5, cela permet également de garder les blocs de réflexion ultérieurs valides : supprimer un rappel antérieur modifierait la conversation avant ces blocs et ferait échouer la vérification de la conversation, tandis qu'un message effacé reste dans le tableau et laisse cette conversation inchangée.

La requête suivante est une étape ultérieure d'une boucle d'agent. messages[3] a été rendu lors de la requête précédente, lorsqu'il était le dernier message du tableau. Dès que messages[5] (un message utilisateur ultérieur) existe, messages[3] est effacé : le message effacé reste dans le tableau, de sorte que la conversation précédant le bloc de réflexion de messages[4] est inchangée, mais le modèle ne voit plus son texte. messages[6] et messages[7] sont tous deux rendus, dans l'ordre.

{
  "model": "claude-fable-5-1",
  "max_tokens": 16000,
  "messages": [
    { "role": "user", "content": "Fix the failing test." },
    {
      "role": "assistant",
      "content": [
        { "type": "thinking", "thinking": "", "signature": "..." },
        {
          "type": "tool_use",
          "id": "toolu_01",
          "name": "read_file",
          "input": { "path": "test_auth.py" }
        }
      ]
    },
    {
      "role": "user",
      "content": [{ "type": "tool_result", "tool_use_id": "toolu_01", "content": "..." }]
    },
    {
      "role": "system",
      "clear_at": "next_user_message",
      "content": "Request independent reads in one turn."
    },
    {
      "role": "assistant",
      "content": [
        { "type": "thinking", "thinking": "", "signature": "..." },
        {
          "type": "tool_use",
          "id": "toolu_02",
          "name": "read_file",
          "input": { "path": "auth.py" }
        },
        {
          "type": "tool_use",
          "id": "toolu_03",
          "name": "read_file",
          "input": { "path": "tokens.py" }
        }
      ]
    },
    {
      "role": "user",
      "content": [
        { "type": "tool_result", "tool_use_id": "toolu_02", "content": "..." },
        {
          "type": "tool_result",
          "tool_use_id": "toolu_03",
          "content": "...",
          "cache_control": { "type": "ephemeral" }
        }
      ]
    },
    {
      "role": "system",
      "clear_at": "next_user_message",
      "content": "Request independent reads in one turn."
    },
    {
      "role": "system",
      "clear_at": "next_user_message",
      "content": "The shell exited with status 137."
    }
  ]
}

Règles pour les messages limités au tour :

  • Renvoyez les messages effacés à l'identique. Un message effacé fait toujours partie de l'historique de la conversation. Le reconstruire à partir de l'état actuel (un nouveau nombre de tokens, un horodatage), le supprimer comme redondant ou modifier sa valeur clear_at constitue une modification d'un message antérieur. Le cache des prompts échoue à partir de ce point, et sur Claude Fable 5.1, Claude Opus 5.5, Claude Sonnet 5.5 et Claude Haiku 5.5, chaque bloc de réflexion produit après lui échoue à la vérification de la conversation.
  • Texte uniquement. content est constitué d'un ou plusieurs blocs text (ou d'une chaîne). Les blocs tool_addition et tool_removal renvoient une erreur 400 sur un message limité au tour, tout comme output_config. Utilisez pour ceux-ci un message role: "system" distinct sans clear_at.
  • Pas de cache_control sur ses blocs. Un message effacé ne fait jamais partie d'une clé de cache, de sorte qu'un point d'arrêt placé dessus ne pourrait jamais correspondre. Placez plutôt le point d'arrêt sur le dernier bloc du tour utilisateur précédent, comme le fait l'exemple. Le champ de mise en cache automatique de premier niveau ignore les messages limités au tour lorsqu'il choisit un point d'arrêt. Sur la requête qui efface un message, le préfixe mis en cache réutilisable se termine au tour utilisateur qui le précède, de sorte que seul l'unique tour assistant situé entre ce message et le nouveau message utilisateur est retraité.
  • Les règles de placement s'appliquent toujours, que le message soit effacé ou non. Un message limité au tour doit suivre un tour user (ou un tour assistant se terminant par un résultat d'outil serveur) et précéder un tour assistant ou terminer le tableau, comme tout message système en cours de conversation. Un message qui termine le tableau est toujours rendu. Un message directement suivi d'un autre message user constitue une erreur 400, et non un message effacé : placez tous les résultats d'une série d'outils dans un seul message utilisateur et les rappels après celui-ci.
  • Les tours assistant ne l'effacent pas. Un tour assistant prérempli ou mis en pause après le message, ou une boucle d'outils côté serveur, n'ajoute aucun message utilisateur, de sorte que le message est toujours rendu lors de cette continuation. Pour garder un rappel visible tout au long d'une boucle d'outils côté client, ajoutez-le à nouveau après chaque message tool_result.
  • Le comptage des tokens suit ce qui est rendu. Un message effacé n'ajoute rien à usage.input_tokens ni à un comptage de tokens.
  • Historique importé. Dans une transcription que vous construisez en une seule étape (exemples few-shot, conversation migrée), un message limité au tour qui est déjà suivi d'un tour assistant et d'un message utilisateur est effacé dès la première requête et n'est jamais rendu. C'est l'état approprié pour un rappel par tour que vous reprenez. Ne laissez clear_at non défini que sur un message que le modèle doit voir à chaque requête.

Les erreurs de validation sont :

messages.3.clear_at: Extra inputs are not permitted
messages.3.clear_at: clear_at is only permitted on role 'system' messages
messages.3.clear_at: Input should be 'next_user_message' or 'never'
messages.3: a turn-scoped system message supports text blocks only (clear_at: 'next_user_message')
messages.3: output_config is not permitted on a turn-scoped system message (clear_at: 'next_user_message')
messages.3.content.0: cache_control is not permitted on a turn-scoped system message (clear_at: 'next_user_message')

La première est l'erreur renvoyée sans l'en-tête bêta. Sur Google Cloud et Claude dans Amazon Bedrock, envoyez la valeur bêta dans l'en-tête anthropic-beta, comme sur l'API Claude (voir En-têtes bêta). Avec l'API InvokeModel d'Amazon Bedrock, placez-la plutôt dans le tableau anthropic_beta du corps de la requête.

Via le SDK, définissez clear_at sur l'entrée role: "system" de messages et envoyez l'en-tête bêta. L'exemple suivant ajoute un rappel limité au tour après le tour utilisateur ; lors de la requête suivante, dès qu'un message utilisateur ultérieur existe, le rappel reste dans le tableau mais n'est plus rendu :

client = anthropic.Anthropic()

response = client.beta.messages.create(
    model="claude-fable-5-1",
    max_tokens=4096,
    messages=[
        {
            "role": "user",
            "content": "Draft a short status update on the database migration for the team channel.",
        },
        # Rappel limité au tour : s'affiche pour ce tour, puis s'efface dès qu'un message utilisateur ultérieur existe.
        {
            "role": "system",
            "clear_at": "next_user_message",
            "content": "The reader is on call: keep this reply under 50 words.",
        },
    ],
    betas=["mid-conversation-system-clear-at-2026-08-21"],
)

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

Combinaison avec la mise en cache des prompts

Les messages système en cours de conversation et la mise en cache des prompts sont conçus pour être utilisés ensemble :

  • Activez explicitement la mise en cache. La mise en cache n'a lieu que lorsque la requête inclut cache_control, soit le champ de mise en cache automatique de premier niveau, soit un point d'arrêt explicite sur un bloc de contenu. Un message système en cours de conversation ne crée pas d'entrée de cache à lui seul, et sans mise en cache activée, il n'y a aucune économie à préserver.
  • Mettez en cache le préfixe stable comme d'habitude. Placez cache_control sur le dernier bloc qui reste identique d'une requête à l'autre, qu'il s'agisse de la fin du champ system de premier niveau, de la fin de vos définitions d'outils ou d'un point stable de l'historique des messages.
  • Ajoutez le message système après le point d'arrêt. Comme il se situe après le préfixe mis en cache, il ne modifie pas le hachage du préfixe et le cache est toujours atteint.
  • Un message système en cours de conversation peut lui-même être mis en cache. Une fois dans la conversation, il fait partie de l'historique stable. Au tour suivant, vous pouvez déplacer votre point d'arrêt de cache au-delà de celui-ci (ou compter sur la mise en cache automatique pour le faire) et le message système est lu depuis le cache comme n'importe quel autre tour.

Évitez de modifier ou de supprimer un message système en cours de conversation qui a déjà été envoyé. Comme toute autre modification de messages antérieurs, cela invalide le cache à partir de ce point. Sur Claude Fable 5.1, Claude Opus 5.5, Claude Sonnet 5.5 et Claude Haiku 5.5, cela invalide également les blocs de réflexion de chaque tour ultérieur de l'assistant. Pour des consignes qui ne doivent s'appliquer qu'à un seul tour, utilisez un message système limité au tour et laissez-le en place. Si l'instruction doit évoluer, ajoutez un nouveau message système plutôt que de réécrire l'ancien. Les messages système consécutifs sont acceptés et traités comme une seule section système, qui suit la même règle de placement dans son ensemble.

Limitations

  • Pas pour le premier message. Un message system qui porte du contenu ne peut pas être la première entrée de messages. Utilisez le champ system de premier niveau pour les instructions qui s'appliquent dès le tout début.
  • Le placement est contraint. Un message system qui porte du contenu (blocs text, tool_addition ou tool_removal) doit suivre immédiatement un tour user (y compris un tour user qui porte des blocs tool_result) ou un tour assistant se terminant par un résultat d'outil serveur, et doit précéder un tour assistant ou terminer le tableau. Il ne peut pas se situer entre un bloc tool_use et son tool_result. Le placer ailleurs renvoie une erreur 400. Une exception : les blocs tool_addition et tool_removal ne sont pas acceptés immédiatement après un tour assistant mis en pause (qui se termine par un résultat d'outil serveur), contrairement aux blocs text ; reprenez d'abord le tour mis en pause, puis envoyez la modification d'outils dans le message system suivant. Un message au content vide qui ne définit que output_config.effort ne rend rien à sa position et est accepté n'importe où dans messages, y compris en première position ou entre un tour assistant et un tour user. Les messages system consécutifs sont évalués ensemble ; ajouter un message portant du texte à côté d'un message ne portant que l'effort soumet donc l'ensemble du groupe à la règle relative au contenu.
  • Les messages limités au tour sont uniquement textuels et renvoyés à l'identique. Un message clear_at: "next_user_message" ne porte ni tool_addition, ni tool_removal, ni output_config, ni cache_control, et une fois effacé, il doit rester dans messages octet pour octet lors des requêtes ultérieures. Consultez Messages système limités au tour.
  • Pas un emplacement pour du contenu non fiable. Claude traite le contenu système comme des instructions de l'opérateur et les suit. Ne placez pas de texte provenant de l'extérieur de la conversation, comme une sortie d'outil brute, des documents récupérés ou du contenu web, directement dans un message système ; cela conférerait à ce texte une autorité de niveau opérateur. Conservez ces données dans des blocs tool_result et continuez à suivre Atténuer les jailbreaks et les injections de prompts.

Fonctionnement de la mise en cache, où placer les points d'arrêt et comment lire les champs d'utilisation du cache.

Identifiez précisément où deux requêtes ont divergé lorsqu'un succès de cache attendu ne se produit pas.

Structure des messages, conversations multi-tours et champ system.

Rédiger des prompts et des instructions système efficaces.

Structure des blocs tool_use et tool_result dans le tableau messages.

Was this page helpful?