Claude Platform Docs
MessagesCompaction

Compaction à la demande

Demandez à Claude de résumer une conversation au moment choisi par votre application, puis poursuivez à partir du résumé.

Avec la « on-demand compaction » (compaction à la demande), votre application décide quand une conversation est résumée : vous envoyez une requête avec le paramètre compaction, et Claude renvoie un résumé à la place d'une réponse.

Fonctionnement de la compaction à la demande

Une requête de compaction est distincte des tours de votre conversation. Vous envoyez la conversation en l'état avec le paramètre compaction, et la réponse contient un unique bloc compaction. Ce bloc contient le résumé sous forme de texte lisible, ainsi qu'une signature. Renvoyez-le dans les requêtes suivantes exactement tel que vous l'avez reçu.

Dès lors, le bloc remplace les messages qu'il résume. Il est placé en premier dans messages, les messages résumés sont supprimés, et votre tour suivant vient après lui. Claude voit le résumé à l'endroit où se trouvaient ces messages.

Compaction requestfour messagesuser 1asst 1user 2asst 2Responseone block, no replycompaction blockNext requestblock firstcompaction blockuser 3

Demander un résumé

Envoyez l'en-tête bêta compact-2026-09-04 sur la requête qui demande le résumé et sur chaque requête ultérieure qui contient le bloc signé. Pour vérifier si un modèle prend en charge la compaction à la demande, appelez l'API Models avec l'en-tête bêta et lisez le champ capabilities.compaction de chaque modèle. Vous ne pouvez pas combiner compaction avec context_management dans une même requête.

Envoyez la conversation en l'état avec "compaction": {"type": "summarize"}. L'API résume une fois chaque message de la requête, ne génère aucune réponse ensuite, et renvoie uniquement le bloc avec stop_reason "compaction". Envoyez la même invite system et les mêmes tools que ceux que vous utilisez pour le reste de la conversation. Le résumeur les lit, et si vous conservez des tours après le bloc sur un modèle avec la « preserved thinking » (réflexion préservée), la réflexion de ces tours ne reste valide que si system et tools correspondent. La conversation de cet exemple n'a ni invite system ni outils, la requête n'envoie donc ni l'un ni l'autre :

from anthropic.types.beta import BetaMessageParam

client = anthropic.Anthropic()

history: list[BetaMessageParam] = [
    {
        "role": "user",
        "content": "I am building a recipe app. Help me name the main entities in the data model.",
    },
    {
        "role": "assistant",
        "content": "Start with Recipe, Ingredient, and Step. Add a RecipeIngredient entry that holds the quantity and unit for each ingredient in a recipe.",
    },
    {"role": "user", "content": "Good. Now suggest field names for Recipe."},
]

response = client.beta.messages.create(
    model="claude-opus-5-5",
    # max_tokens plafonne l'appel entier, réflexion comprise, prévoyez donc plusieurs milliers de tokens.
    max_tokens=4096,
    betas=["compact-2026-09-04"],
    messages=history,
    compaction={"type": "summarize"},
)
print(f"Stop reason: {response.stop_reason}")
Response
{
  "id": "msg_013Zva2CMHLNnXjNJJKqJ2EF",
  "type": "message",
  "role": "assistant",
  "model": "claude-opus-5-5",
  "content": [
    {
      "type": "compaction",
      "content": "Summary of the conversation: the user is designing the data model for a recipe app. The entities agreed so far are Recipe, Ingredient, Step, and RecipeIngredient, which holds the quantity and unit. The user then asked for field names for Recipe.",
      "signature": "EuYBCkQY..."
    }
  ],
  "stop_reason": "compaction",
  "usage": {
    "input_tokens": 0,
    "output_tokens": 0,
    "iterations": [{ "type": "compaction", "input_tokens": 144, "output_tokens": 276 }]
  }
}

L'appel de résumé utilise le modèle, system, tools, les paramètres de réflexion et max_tokens de la requête. Le résumeur lit les définitions d'outils mais n'exécute jamais d'outil, et la réponse ne contient aucune réflexion. max_tokens plafonne l'ensemble de l'appel, y compris toute réflexion effectuée par le modèle avant d'écrire le résumé ; prévoyez donc plusieurs milliers de tokens. Comptabiliser l'utilisation de la compaction montre comment l'appel est facturé.

Si le dernier tour assistant se termine par un appel d'outil qui n'a pas encore de résultat, l'API rejette la requête. Envoyez d'abord les résultats d'outils de ce tour. Omettez également stop_sequences, le output_config.format des sorties structurées, et un tool_choice de type any ou tool. Ils n'auraient aucun effet sur un appel de résumé, et l'API les rejette. La conversation doit toujours tenir dans la « context window » (fenêtre de contexte) du modèle ; compactez donc avant de la dépasser, et non après.

Lorsque vous recevez la réponse en « streaming » (flux), le bloc arrive en entier. Vous recevez un événement content_block_start contenant le bloc complet, puis content_block_stop, sans aucun événement content_block_delta. Des événements ping peuvent arriver avant ou entre eux.

Poursuivre à partir du résumé

Dans votre historique, remplacez les messages que vous avez envoyés par le message assistant renvoyé. Conservez le bloc compaction exactement tel que l'API l'a renvoyé, y compris sa signature. Les tours effectués après l'envoi de la requête de compaction suivent le bloc sans modification, ce sur quoi s'appuie la Compaction en arrière-plan. Envoyez le bloc en premier dans chaque requête ultérieure, avec l'en-tête bêta :

{
  "model": "claude-opus-5-5",
  "max_tokens": 2048,
  "messages": [
    {
      "role": "assistant",
      "content": [
        {
          "type": "compaction",
          "content": "Summary of the conversation: the user is designing the data model for a recipe app. The entities agreed so far are Recipe, Ingredient, Step, and RecipeIngredient, which holds the quantity and unit. The user then asked for field names for Recipe.",
          "signature": "EuYBCkQY..."
        }
      ]
    },
    {
      "role": "assistant",
      "content": "For Recipe, use title, description, servings, prep_minutes, and cook_minutes. Add created_at and updated_at timestamps."
    },
    { "role": "user", "content": "Now do the same for Ingredient." }
  ]
}

Cet exemple poursuit l'exemple de requête, qui se terminait par un tour user ; le diagramme montre le cas plus simple, où aucun tour n'est effectué pendant la rédaction du résumé. Ici, le second message assistant est la réponse au dernier tour user résumé. Il est arrivé pendant la rédaction du résumé, il ne faisait donc pas partie des messages résumés. Deux messages assistant consécutifs ne posent pas de problème ici, car le bloc vient toujours en premier.

L'API place le résumé à l'emplacement du bloc et transmet chaque message ultérieur à Claude sans modification. Respectez ces règles :

  • Placez le bloc en premier dans messages, soit comme un message assistant à part entière, soit comme premier bloc de contenu du premier message, qu'il s'agisse d'un message user ou assistant.
  • Supprimez les messages résumés. S'il en reste devant le bloc, la requête renvoie une erreur 400 (compaction_block_misplaced).
  • Envoyez exactement un bloc compaction par requête, dans chaque requête ultérieure.

La compaction par seuil fonctionne à l'inverse : son bloc suit les messages qu'il résume, et l'API les supprime pour vous. Consultez Renvoyer les blocs de compaction.

En Python, utilisez client.beta.messages, comme le font les exemples de cette page. Si vous appelez client.messages et sérialisez vous-même les blocs, utilisez to_dict() ou model_dump(exclude_none=True) : un simple model_dump() ajoute citations: null et text: null au bloc, et l'API le rejette.

Si vous conservez des tours après le bloc et renvoyez leurs blocs de réflexion, les conditions qui maintiennent la validité de cette réflexion sont décrites dans Compaction et réflexion préservée.

Compacter à nouveau

Pour compacter une conversation qui commence déjà par un bloc, envoyez de nouveau compaction. Le nouveau bloc résume l'ancien résumé et tout ce qui le suit. Dès lors, n'envoyez que le bloc le plus récent.

Compacter dans une boucle

Après chaque tour, la boucle additionne les tokens d'entrée et de sortie de la dernière réponse, car la requête suivante envoie aussi la réponse. Lorsque ce total dépasse une limite et qu'un autre tour reste à venir, elle envoie une requête de compaction avec le même modèle et la même invite system, vérifie stop_reason, remplace son historique par le message renvoyé, et affiche le tour avant lequel elle a compacté. La limite de 2 500 tokens de l'exemple est volontairement basse, afin qu'une courte conversation soit compactée. Fixez la vôtre près de votre budget d'entrée réel.

from anthropic.types.beta import BetaMessageParam

client = anthropic.Anthropic()

# Définissez cette valeur près de votre budget d'entrée réel. Elle est basse ici pour qu'une courte conversation soit compactée.
COMPACT_AT_TOKENS = 2500
SYSTEM = "You help design a recipe app's data model. Keep answers short."

QUESTIONS = [
    "What are the main entities in the data model?",
    "Which fields should Recipe have?",
    "Which fields should Ingredient have?",
    "Which fields should RecipeIngredient have?",
    "Which fields should Step have?",
    "Which indexes should these tables have?",
    "Which fields should be required?",
    "Which fields should have default values?",
]

history: list[BetaMessageParam] = []
for turn, question in enumerate(QUESTIONS, start=1):
    history.append({"role": "user", "content": question})
    response = client.beta.messages.create(
        model="claude-opus-5-5",
        max_tokens=8192,
        system=SYSTEM,
        betas=["compact-2026-09-04"],
        messages=history,
    )
    history.append({"role": "assistant", "content": response.content})

    # La prochaine requête envoie aussi cette réponse, comptez-la donc.
    conversation_tokens = response.usage.input_tokens + response.usage.output_tokens
    if conversation_tokens > COMPACT_AT_TOKENS and turn < len(QUESTIONS):
        summary = client.beta.messages.create(
            model="claude-opus-5-5",
            max_tokens=4096,
            system=SYSTEM,
            betas=["compact-2026-09-04"],
            messages=history,
            compaction={"type": "summarize"},
        )
        if summary.stop_reason == "compaction":
            history = [{"role": "assistant", "content": summary.content}]
            print(f"Compacted before turn {turn + 1}")

La vérification de stop_reason intervient avant que le code ne recherche le bloc ; Gérer un résumé manquant ou une erreur explique pourquoi. L'historique est remplacé, et non complété : le message renvoyé remplace chaque message que contenait la requête, selon les règles de Poursuivre à partir du résumé. Lorsqu'aucun résumé n'est renvoyé, la boucle conserve son historique et redemande après le tour suivant.

Le « tool runner » (exécuteur d'outils) du SDK en Python, TypeScript, C#, Go et Java peut envoyer la requête de compaction à votre place. Lorsque vous décidez de compacter, appelez compact_before_next_turn() sur le runner (compactBeforeNextTurn() en TypeScript et Java, CompactBeforeNextTurn() en C# et Go). Une fois le tour en cours et ses appels d'outils terminés, le runner envoie la requête de compaction et remplace son historique par le message renvoyé. Créez le runner avec la bêta compact-2026-09-04, car le runner ne l'ajoute pas. Le runner construit la requête à partir de ses propres paramètres et omet context_management. Si ces paramètres incluent stop_sequences, un tool_choice de type any ou tool, ou un output_config.format de sortie structurée, l'API rejette la requête avec une erreur 400. Demander un résumé explique pourquoi. Le runner refuse de compacter tant que son context_management contient une édition de compaction ; utilisez donc un seul type de compaction par runner.

Quand compacter

Vous pouvez envoyer une requête de compaction après n'importe quel tour terminé ; c'est donc votre code qui décide du moment.

Pour estimer la taille de la prochaine requête, additionnez input_tokens et output_tokens du usage de la dernière réponse, comme le fait la boucle. Avec la « prompt caching » (mise en cache des prompts), input_tokens ne compte que les tokens situés après le dernier point d'arrêt du cache ; ajoutez donc également cache_read_input_tokens et cache_creation_input_tokens. Vous pouvez aussi envoyer les mêmes messages au point de terminaison de « token counting » (comptage de tokens).

Comparez ce nombre à une limite de votre choix, inférieure à la fenêtre de contexte du modèle.

Rédiger votre propre prompt de résumé

Sans instructions, l'API utilise son propre prompt de résumé. Une chaîne instructions non vide (jusqu'à 16 384 caractères) remplace entièrement ce prompt. Par exemple :

{
  "compaction": {
    "type": "summarize",
    "instructions": "Summarize this recipe app design conversation. Preserve every entity and field name agreed so far, and the user's latest open request. Do not call tools; respond with the summary text only."
  }
}

Le résumeur lit l'intégralité de la conversation, y compris la réflexion antérieure, avec ou sans instructions. Dans vos instructions, indiquez ce que le résumé doit conserver et demandez au modèle de ne pas appeler d'outils. L'appel de résumé s'exécute avec les mêmes garde-fous que toute autre requête.

Gérer un résumé manquant ou une erreur

Un résumé n'est produit que lorsque l'appel de résumé se termine normalement avec du texte et sans appel d'outil. Sinon, la réponse reste un 200 avec un content vide ; vérifiez donc stop_reason avant de rechercher le bloc. L'appel est tout de même facturé et signalé dans usage.iterations, avec une utilisation nulle lorsqu'aucun appel n'a pu être effectué. Le stop_reason est celui par lequel l'appel de résumé s'est terminé. Dans tous les cas, vous pouvez continuer sans résumé et compacter plus tard.

stop_reasonCauseQue faire
"max_tokens"Le résumé a été tronqué.Renvoyez la requête avec un max_tokens plus élevé.
"model_context_window_exceeded"Il n'y avait pas de place pour le prompt de résumé.Renvoyez la requête avec des instructions plus courtes ou moins de messages.
"tool_use"Le modèle a appelé un outil au lieu d'écrire le résumé.Renvoyez la requête avec des instructions qui demandent au modèle de ne pas appeler d'outils.
"refusal"La requête a été refusée.Continuez sans résumé.
"end_turn"L'appel n'a renvoyé aucun texte.Continuez sans résumé.

L'appel de résumé est soumis aux mêmes garde-fous que vos autres requêtes. Après un "refusal", stop_details identifie la catégorie de politique à l'origine du refus.

Erreurs

Une requête de compaction, ou une requête qui contient un bloc, peut aussi échouer purement et simplement. La plupart des erreurs 400 ont un message qui indique ce qu'il faut supprimer ou renvoyer. Certaines contiennent aussi un error.details.error_code qui commence par compaction_. Les erreurs de paramètres, comme un champ qui ne peut pas être combiné avec compaction, ne contiennent que le message.

ErreurCauseQue faire
529 overloaded_error, error.details.error_code compaction_unavailableUn problème serveur transitoire lors de la production d'un bloc, ou lors de la lecture d'un bloc que vous avez renvoyé.Réessayez la requête.
400 compaction_block_misplacedDes messages résumés restent devant le bloc.Supprimez-les, afin que le bloc vienne en premier dans messages.
400 compaction_signature_invalid ou compaction_content_mismatchLa signature ou le content du bloc a été modifié après que l'API l'a renvoyé.Envoyez le bloc exactement tel qu'il a été renvoyé, y compris sa signature.
400La requête contient plus d'un bloc compaction.Envoyez-en exactement un, le plus récent.
400Le dernier tour assistant se termine par un appel d'outil qui n'a pas encore de résultat.Envoyez les résultats d'outils de ce tour, puis compactez.
400 compaction_nothing_to_summarizemessages ne contient aucun contenu user ou assistant, par exemple une liste vide.Envoyez au moins un message user ou assistant.
400 sur la requête de compaction, avec un message indiquant que le paramètre compaction requires anthropic-beta: compact-2026-09-04La requête de compaction a omis l'en-tête bêta.Ajoutez l'en-tête bêta ; consultez Demander un résumé.
400 sur une requête ultérieure qui contient le bloc : une erreur de validation indiquant que compaction ne fait pas partie des types de blocs de contenu attendus. Le message ne mentionne pas l'en-têteCette requête a omis l'en-tête bêta.Ajoutez l'en-tête bêta à chaque requête qui contient le bloc ; consultez Demander un résumé.
400 erreur de validation, comme messages.0.content.0.compaction.citations: Extra inputs are not permittedUn bloc a été renvoyé avec des champs que l'API n'avait pas renvoyés, comme citations: null.Envoyez le bloc exactement tel qu'il a été renvoyé ; consultez Poursuivre à partir du résumé.

Comptabiliser l'utilisation de la compaction

L'appel de résumé est facturé et soumis aux « rate limits » (limites de débit) comme toute autre requête, et usage.iterations le signale comme l'entrée compaction. Les input_tokens et output_tokens de premier niveau sont à zéro, car aucune réponse n'a été générée. Pour comptabiliser ce qu'une conversation a consommé, faites la somme sur usage.iterations, et non sur les champs de premier niveau. Renvoyer un bloc dans les requêtes ultérieures n'ajoute aucun coût de compaction.

Vous disposez d'une boucle fonctionnelle qui compacte une conversation et gère un résumé manquant. Deux pages modifient son fonctionnement, et vous pouvez les combiner : Compaction qui conserve les tours récents conserve les derniers tours mot pour mot, et Compaction en arrière-plan permet à la conversation de se poursuivre pendant la rédaction du résumé. Compaction et réflexion préservée s'applique si vous renvoyez des blocs de réflexion et utilisez l'une ou l'autre.

Limites et interactions avec d'autres fonctionnalités

  • Compaction par seuil et édition du contexte. Vous ne pouvez pas envoyer compaction et context_management dans la même requête. La compaction par seuil (compact_20260112) ne peut pas s'exécuter sur une requête qui contient un bloc signé.
  • Mise en cache des prompts. cache_control sur le bloc place un point d'arrêt après le résumé.
  • Messages système en cours de conversation et modifications d'outils. Les messages role: "system" situés dans la plage résumée sont également résumés ; leurs instructions textuelles cessent donc de s'appliquer une fois que le bloc les remplace. Si une instruction reste importante, énoncez-la de nouveau dans un message role: "system". Envoyez ce message juste après votre prochain nouveau tour user, et conservez-le ensuite dans votre historique. Pour les modifications d'outils, et pour savoir où placer ce message lorsque vous conservez des tours après le bloc, consultez Modifier l'invite système ou les outils.
  • Budgets de tâche. N'envoyez pas la valeur remaining d'un budget de tâche (output_config.task_budget.remaining) avec compaction ni dans les requêtes qui contiennent le bloc. Cela renvoie une erreur 400.
  • Comptage de tokens. Le point de terminaison de comptage de tokens ignore le paramètre compaction.
  • Contenu que le résumé ne peut pas transporter. Les images, les documents, les blocs container_upload et les URL récupérées dans les messages résumés disparaissent une fois que le bloc les remplace. Reformulez ou téléversez de nouveau tout ce dont un tour ultérieur a encore besoin.

Compatibility

Supported models
  • Fable 5 and 5.1
  • Mythos 5, 5.1, and Preview
  • Opus 4.6, 4.7, 4.8, 5, and 5.5
  • Sonnet 4.6 and 5
Supported platforms
  • Claude APIBeta
  • Claude Platform on AWSBeta
  • Google CloudBeta
  • Microsoft FoundryBeta

Was this page helpful?