Claude Platform Docs
MessagesCompaction

Compaction en arrière-plan

Demandez un résumé de compaction à la demande pendant que la conversation se poursuit sur son historique complet, puis insérez le bloc à sa place lorsqu'il arrive.

La « background compaction » (compaction en arrière-plan), souvent appelée « async compaction » (compaction asynchrone), modifie deux choses dans la boucle de compaction : la requête de compaction s'exécute pendant que la conversation se poursuit sur son historique complet, et le remplacement attend l'arrivée du bloc. Les sections Poursuivre à partir du résumé et Gérer un résumé manquant ou une erreur s'appliquent sans changement.

Fonctionnement du remplacement pendant que le travail se poursuit

La requête de compaction et le bloc qu'elle renvoie sont les mêmes que dans la boucle. Votre historique s'allonge entre l'envoi de la requête et l'utilisation de son résultat, et le remplacement doit laisser ces ajouts en place.

  1. Envoyez la requête de compaction avec votre historique tel qu'il est, et notez le nombre de messages qu'il contenait.
  2. Pendant que cette requête s'exécute, poursuivez la conversation sur l'historique complet. Ajoutez chaque nouveau tour, ne modifiez rien de ce qui se trouve déjà dans l'historique, et ne lancez pas d'autre requête de compaction tant que celle-ci n'a pas été intégrée ou n'a pas échoué.
  3. Lorsque la réponse arrive avec le stop_reason "compaction", retirez exactement les messages que vous avez envoyés du début de votre historique et placez le message renvoyé à leur place. Chaque tour ajouté depuis l'étape 1 reste après lui.
  4. Envoyez l'historique ainsi remplacé dans la première requête qui suit l'arrivée du bloc, afin que la réflexion produite pendant la rédaction du résumé reste valide.

Par exemple, si la requête de compaction contenait les messages 1 à 5 et que la conversation a gagné les messages 6 à 8 pendant son exécution, après le remplacement votre historique se compose du bloc suivi des messages 6 à 8.

Request sentmessages 1–512345While it runs6–8 arrive12345678compaction request: 1–5After the swapblock, then 6–8compaction block678

Si la réponse a un autre stop_reason, aucun résumé n'a été produit, ce qui compte comme un échec à l'étape 2. Conservez l'historique complet ; la section Gérer un résumé manquant ou une erreur répertorie les causes et la marche à suivre pour chacune.

Demander le résumé en arrière-plan

La requête de compaction est décomptée de vos « rate limits » (limites de débit) comme toute autre requête, et pendant son exécution votre application a deux requêtes ouvertes en même temps. La conversation continue de s'allonger sur son historique complet jusqu'au remplacement ; lancez donc la requête de compaction tant que la « context window » (fenêtre de contexte) a encore de la place pour les tours qui arrivent entre-temps.

Le programme suivant reprend la boucle de Compacter dans une boucle en retirant la requête de compaction du chemin de la conversation. Il n'a pas de version PHP, car l'exemple repose sur l'exécution simultanée de deux requêtes. Les lignes mises en évidence montrent en quoi il diffère de la boucle, et la liste qui suit les présente dans l'ordre où le programme les exécute.

from concurrent.futures import Future, ThreadPoolExecutor

import anthropic
from anthropic.types.beta import BetaMessage, BetaMessageParam

client = anthropic.Anthropic()
executor = ThreadPoolExecutor(max_workers=1)

# Réglez 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?",
]


def swap_in(history: list[BetaMessageParam], summary: BetaMessage, sent: int) -> None:
    if summary.stop_reason == "compaction":
        # Remplacez exactement les messages contenus dans la requête de compaction.
        # Les tours suivants restent après le bloc.
        history[:sent] = [{"role": "assistant", "content": summary.content}]
        print(f"Swapped {sent} messages")


history: list[BetaMessageParam] = []
pending: Future[BetaMessage] | None = None
sent = 0
for turn, question in enumerate(QUESTIONS, start=1):
    if pending is not None and pending.done():
        swap_in(history, pending.result(), sent)
        pending = None

    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 requête suivante 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)
        and pending is None
    ):
        sent = len(history)
        pending = executor.submit(
            client.beta.messages.create,
            model="claude-opus-5-5",
            max_tokens=4096,
            system=SYSTEM,
            betas=["compact-2026-09-04"],
            messages=history.copy(),
            compaction={"type": "summarize"},
        )

# Insérez un résumé encore en cours de génération avant d'enregistrer
# ou de poursuivre la conversation.
if pending is not None:
    swap_in(history, pending.result(), sent)
executor.shutdown()
  • Décider quand compacter : la vérification de taille exige également qu'aucune requête de compaction ne soit en attente.
  • Lancer la requête : là où la boucle attend la réponse de compaction, cette version note le nombre de messages que contient l'historique, lance la requête sur une copie de l'historique avec l'outil de concurrence propre à chaque langage, et passe au tour suivant sans attendre.
  • Vérifier le résultat : au début de chaque tour, le programme vérifie si la requête en attente est terminée. Si c'est le cas, le programme effectue le remplacement avant d'envoyer la requête de ce tour.
  • Effectuer le remplacement : là où la boucle remplace tout l'historique par le message renvoyé, la fonction de remplacement de cette version ne remplace que les messages que contenait la requête, comptés depuis le début, et conserve tout ce qui a été ajouté depuis.
  • Terminer la boucle : si la requête de compaction est toujours en attente à la fin de la boucle, le programme l'attend et effectue le remplacement, afin qu'un résumé encore en cours d'acheminement ne soit pas perdu avant que vous n'enregistriez ou ne poursuiviez la conversation.

La vérification du stop_reason est identique à celle de la boucle : une réponse sans bloc laisse l'historique tel qu'il était. Comme plus rien n'est en attente, le programme peut alors lancer une nouvelle requête de compaction.

Garder la réflexion valide pendant la construction du résumé

Les tours qui arrivent pendant la rédaction du résumé sont des tours conservés. Si vous renvoyez des « thinking blocks » (blocs de réflexion) sur un modèle avec réflexion préservée, la réflexion de ces tours ne reste valide que tant que les conditions de validité de la réflexion conservée sont remplies.

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?