---
title: Compattazione in background
url: https://platform.claude.com/docs/it/build-with-claude/compaction-background
description: Richiedi un riepilogo di compattazione on-demand mentre la conversazione continua sulla sua cronologia completa, poi inserisci il blocco al suo arrivo.
featureMetadata:
  status: beta
  betaHeader: compact-2026-09-04
  supportedModels:
    - claude-fable-5-1
    - claude-mythos-5-1
    - claude-fable-5
    - claude-mythos-5
    - claude-mythos-preview
    - claude-opus-5-5
    - claude-opus-5
    - claude-opus-4-8
    - claude-opus-4-7
    - claude-opus-4-6
    - claude-sonnet-5-5
    - claude-sonnet-5
    - claude-sonnet-4-6
    - claude-haiku-5-5
  supportedPlatforms:
    Claude API: beta
    Claude Platform on AWS: beta
    Google Cloud: beta
    Microsoft Foundry: beta
---

La "background compaction" (compattazione in background), spesso chiamata "async compaction" (compattazione asincrona), modifica due aspetti del [ciclo di compattazione](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#compact-in-a-loop): la richiesta di compattazione viene eseguita mentre la conversazione prosegue sulla sua cronologia completa, e lo "swap" (sostituzione) attende l'arrivo del blocco. [Continua dal riepilogo](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#continue-from-the-summary) e [Gestisci un riepilogo mancante o un errore](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#when-no-summary-comes-back) si applicano senza modifiche.

## Come funziona la sostituzione mentre il lavoro prosegue

La richiesta di compattazione e il blocco che restituisce sono gli stessi del ciclo. La tua cronologia cresce tra l'invio della richiesta e l'utilizzo del suo risultato, e la sostituzione deve lasciare intatta questa crescita.

1. Invia la [richiesta di compattazione](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#request-a-summary) con la cronologia così com'è e registra quanti messaggi conteneva.
2. Mentre quella richiesta è in esecuzione, continua la conversazione sulla cronologia completa. Aggiungi ogni nuovo turno, non modificare nulla di ciò che è già nella cronologia e non avviare un'altra richiesta di compattazione finché questa non è stata sostituita o non è fallita.
3. Quando arriva la risposta con `stop_reason` `"compaction"`, rimuovi esattamente i messaggi che hai inviato dall'inizio della cronologia e inserisci al loro posto il messaggio restituito. Ogni turno aggiunto dopo il passaggio 1 rimane dopo di esso.
4. Invia la cronologia sostituita nella prima richiesta successiva all'arrivo del blocco, in modo che il ragionamento prodotto mentre il riepilogo veniva scritto rimanga valido.

Ad esempio, se la richiesta di compattazione conteneva i messaggi da 1 a 5 e la conversazione ha acquisito i messaggi da 6 a 8 durante la sua esecuzione, dopo la sostituzione la tua cronologia è costituita dal blocco seguito dai messaggi da 6 a 8.

<Frame>
  ![Cronologia della background compaction (compattazione in background): la richiesta di compattazione viene inviata con i messaggi da 1 a 5 mentre la conversazione prosegue sulla sua cronologia completa e acquisisce i messaggi da 6 a 8; quando il blocco arriva, sostituisce i messaggi da 1 a 5 all'inizio della cronologia, e la cronologia diventa il blocco seguito dai messaggi da 6 a 8](https://platform.claude.com/docs/it/images/compaction-background-timeline.svg)
</Frame>

Se la risposta ha qualsiasi altro `stop_reason`, non è stato prodotto alcun riepilogo, il che conta come un fallimento nel passaggio 2. Mantieni la cronologia completa; [Gestisci un riepilogo mancante o un errore](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#when-no-summary-comes-back) elenca le cause e cosa fare per ciascuna.

## Richiedere il riepilogo in background

La richiesta di compattazione viene conteggiata nei tuoi "rate limit" (limiti di velocità) come qualsiasi altra richiesta e, mentre è in esecuzione, la tua applicazione ha due richieste aperte contemporaneamente. La conversazione continua a crescere sulla sua cronologia completa fino alla sostituzione, quindi avvia la richiesta di compattazione mentre la "context window" (finestra di contesto) ha ancora spazio per i turni che arrivano nel frattempo.

Il programma seguente è il ciclo di [Compatta in un ciclo](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#compact-in-a-loop) con la richiesta di compattazione tolta dal percorso della conversazione. Le righe evidenziate mostrano dove differisce dal ciclo, e l'elenco seguente le esamina nell'ordine in cui il programma le esegue.

<CodeGroup exclude="shell, php">
  ```python Python
  from concurrent.futures import Future, ThreadPoolExecutor

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

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

  # Imposta questo valore vicino al tuo budget di input reale. Qui è basso così una conversazione breve viene compattata.
  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":
          # Sostituisci esattamente i messaggi contenuti nella richiesta di compattazione.
          # I turni successivi restano dopo il blocco.
          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})

      # Anche la richiesta successiva invia questa risposta, quindi contala.
      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"},
          )

  # Inserisci un riepilogo ancora in arrivo prima di salvare
  # o di continuare la conversazione.
  if pending is not None:
      swap_in(history, pending.result(), sent)
  executor.shutdown()
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  // Imposta questo valore vicino al tuo budget di input reale. Qui è basso così una conversazione breve viene compattata.
  const compactAtTokens = 2500;
  const systemPrompt = "You help design a recipe app's data model. Keep answers short.";

  const 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?"
  ];

  function swapIn(
    history: Anthropic.Beta.Messages.BetaMessageParam[],
    summary: Anthropic.Beta.Messages.BetaMessage,
    sent: number
  ): Anthropic.Beta.Messages.BetaMessageParam[] {
    if (summary.stop_reason !== "compaction") {
      return history;
    }
    console.log(`Swapped ${sent} messages`);
    // Sostituisci esattamente i messaggi contenuti nella richiesta di compattazione. I turni successivi restano dopo il blocco.
    return [{ role: "assistant", content: summary.content }, ...history.slice(sent)];
  }

  let history: Anthropic.Beta.Messages.BetaMessageParam[] = [];
  let pending: Promise<Anthropic.Beta.Messages.BetaMessage> | undefined;
  let settled = false;
  let sent = 0;
  for (const [index, question] of questions.entries()) {
    const turn = index + 1;
    if (pending && settled) {
      history = swapIn(history, await pending, sent);
      pending = undefined;
      settled = false;
    }

    history.push({ role: "user", content: question });
    const response = await client.beta.messages.create({
      model: "claude-opus-5-5",
      max_tokens: 8192,
      system: systemPrompt,
      betas: ["compact-2026-09-04"],
      messages: history
    });
    history.push({ role: "assistant", content: response.content });

    // Anche questa risposta viene inviata con la richiesta successiva, quindi contala.
    const conversationTokens = response.usage.input_tokens + response.usage.output_tokens;
    if (conversationTokens > compactAtTokens && turn < questions.length && !pending) {
      sent = history.length;
      pending = client.beta.messages.create({
        model: "claude-opus-5-5",
        max_tokens: 4096,
        system: systemPrompt,
        betas: ["compact-2026-09-04"],
        messages: [...history],
        compaction: { type: "summarize" }
      });
      // Segna comunque la richiesta come conclusa. Attenderla restituisce poi il riepilogo o genera un'eccezione.
      const markSettled = () => {
        settled = true;
      };
      pending.then(markSettled, markSettled);
    }
  }

  // Inserisci un riepilogo ancora in arrivo prima di salvare o proseguire la conversazione.
  if (pending) {
    history = swapIn(history, await pending, sent);
  }
  ```

  ```csharp C#
  using Anthropic.Models.Beta;
  using Anthropic.Models.Beta.Messages;
  using Model = Anthropic.Models.Messages.Model;

  AnthropicClient client = new();

  // Imposta questo valore vicino al tuo budget di input reale. Qui è basso così una conversazione breve viene compattata.
  const int CompactAtTokens = 2500;
  const string SystemPrompt = "You help design a recipe app's data model. Keep answers short.";

  string[] 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?",
  ];

  static List<BetaMessageParam> SwapIn(List<BetaMessageParam> history, BetaMessage summary, int sent)
  {
      if (summary.StopReason != BetaStopReason.Compaction)
      {
          return history;
      }
      Console.WriteLine($"Swapped {sent} messages");
      // Sostituisci esattamente i messaggi contenuti nella richiesta di compattazione. I turni successivi restano dopo il blocco.
      return
      [
          new()
          {
              Role = Role.Assistant,
              Content = summary.Content.Select(block => new BetaContentBlockParam(block.Json)).ToList(),
          },
          .. history[sent..],
      ];
  }

  List<BetaMessageParam> history = [];
  Task<BetaMessage>? pending = null;
  var sent = 0;
  foreach (var (index, question) in questions.Index())
  {
      var turn = index + 1;
      if (pending is { IsCompleted: true })
      {
          history = SwapIn(history, await pending, sent);
          pending = null;
      }

      history.Add(new() { Role = Role.User, Content = question });
      var response = await client.Beta.Messages.Create(new MessageCreateParams
      {
          Model = Model.ClaudeOpus5_5,
          MaxTokens = 8192,
          System = SystemPrompt,
          Betas = [AnthropicBeta.Compact2026_09_04],
          Messages = history,
      });
      history.Add(new()
      {
          Role = Role.Assistant,
          Content = response.Content.Select(block => new BetaContentBlockParam(block.Json)).ToList(),
      });

      // Anche la richiesta successiva invia questa risposta, quindi contala.
      var conversationTokens = response.Usage.InputTokens + response.Usage.OutputTokens;
      if (conversationTokens > CompactAtTokens && turn < questions.Length && pending is null)
      {
          sent = history.Count;
          pending = client.Beta.Messages.Create(new MessageCreateParams
          {
              Model = Model.ClaudeOpus5_5,
              MaxTokens = 4096,
              System = SystemPrompt,
              Betas = [AnthropicBeta.Compact2026_09_04],
              Messages = [.. history],
              Compaction = new BetaCompactionConfig(), // type defaults to "summarize"
          });
      }
  }

  // Inserisci un riepilogo ancora in arrivo prima di salvare o proseguire la conversazione.
  if (pending is not null)
  {
      history = SwapIn(history, await pending, sent);
  }
  ```

  ```go Go
  ctx := context.Background()
  client := anthropic.NewClient()

  // Imposta questo valore vicino al tuo budget di input reale. Qui è basso così una conversazione breve viene compattata.
  const compactAtTokens = 2500
  system := []anthropic.BetaTextBlockParam{{Text: "You help design a recipe app's data model. Keep answers short."}}

  questions := []string{
  	"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?",
  }

  var history []anthropic.BetaMessageParam
  var pending chan *anthropic.BetaMessage
  var sent int
  swapIn := func(summary *anthropic.BetaMessage) {
  	if summary.StopReason != anthropic.BetaStopReasonCompaction {
  		return
  	}
  	fmt.Printf("Swapped %d messages\n", sent)
  	// Sostituisci esattamente i messaggi contenuti nella richiesta di compattazione. I turni successivi restano dopo il blocco.
  	history = slices.Replace(history, 0, sent, summary.ToParam())
  }

  for i, question := range questions {
  	turn := i + 1
  	// La ricezione da un canale nil non riesce mai, quindi questo viene saltato quando non c'è nulla in sospeso.
  	select {
  	case summary := <-pending:
  		swapIn(summary)
  		pending = nil
  	default:
  	}

  	history = append(history, anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock(question)))
  	response, err := client.Beta.Messages.New(ctx, anthropic.BetaMessageNewParams{
  		Model:     anthropic.ModelClaudeOpus5_5,
  		MaxTokens: 8192,
  		System:    system,
  		Betas:     []anthropic.AnthropicBeta{anthropic.AnthropicBetaCompact2026_09_04},
  		Messages:  history,
  	})
  	if err != nil {
  		log.Fatal(err)
  	}
  	history = append(history, response.ToParam())

  	// Anche la richiesta successiva invia questa risposta, quindi contala.
  	conversationTokens := response.Usage.InputTokens + response.Usage.OutputTokens
  	if conversationTokens > compactAtTokens && turn < len(questions) && pending == nil {
  		sent = len(history)
  		pending = make(chan *anthropic.BetaMessage, 1)
  		go func(messages []anthropic.BetaMessageParam, result chan<- *anthropic.BetaMessage) {
  			summary, err := client.Beta.Messages.New(ctx, anthropic.BetaMessageNewParams{
  				Model:     anthropic.ModelClaudeOpus5_5,
  				MaxTokens: 4096,
  				System:    system,
  				Betas:     []anthropic.AnthropicBeta{anthropic.AnthropicBetaCompact2026_09_04},
  				Messages:  messages,
  				Compaction: anthropic.BetaCompactionConfigUnionParam{
  					OfSummarize: &anthropic.BetaSummarizeCompactionParam{},
  				},
  			})
  			if err != nil {
  				log.Fatal(err)
  			}
  			result <- summary
  		}(slices.Clone(history), pending)
  	}
  }

  // Inserisci un riepilogo ancora in arrivo prima di salvare o proseguire la conversazione.
  if pending != nil {
  	swapIn(<-pending)
  }
  ```

  ```java Java
  import com.anthropic.models.beta.AnthropicBeta;
  import com.anthropic.models.beta.messages.BetaCompactionConfig;
  import com.anthropic.models.beta.messages.BetaMessage;
  import com.anthropic.models.beta.messages.BetaMessageParam;
  import com.anthropic.models.beta.messages.BetaStopReason;
  import com.anthropic.models.beta.messages.MessageCreateParams;

  // Imposta questo valore vicino al tuo budget di input reale. Qui è basso così una conversazione breve viene compattata.
  static final long COMPACT_AT_TOKENS = 2500;
  static final String SYSTEM = "You help design a recipe app's data model. Keep answers short.";

  void swapIn(List<BetaMessageParam> history, BetaMessage summary, int sent) {
      if (!summary.stopReason().map(BetaStopReason.COMPACTION::equals).orElse(false)) {
          return;
      }
      IO.println("Swapped " + sent + " messages");
      // Sostituisci esattamente i messaggi contenuti nella richiesta di compattazione. I turni successivi restano dopo il blocco.
      history.subList(0, sent).clear();
      history.addFirst(summary.toParam());
  }

  void main() {
      var client = AnthropicOkHttpClient.fromEnv();

      var questions = List.of(
          "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?"
      );

      var history = new ArrayList<BetaMessageParam>();
      CompletableFuture<BetaMessage> pending = null;
      int sent = 0;
      for (int turn = 1; turn <= questions.size(); turn++) {
          if (pending != null && pending.isDone()) {
              swapIn(history, pending.join(), sent);
              pending = null;
          }

          history.add(BetaMessageParam.builder()
              .role(BetaMessageParam.Role.USER)
              .content(questions.get(turn - 1))
              .build());
          var params = MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(8192)
              .system(SYSTEM)
              .addBeta(AnthropicBeta.COMPACT_2026_09_04)
              .messages(history)
              .build();
          var response = client.beta().messages().create(params);
          history.add(response.toParam());

          // Anche la richiesta successiva invia questa risposta, quindi conteggiala.
          long conversationTokens = response.usage().inputTokens() + response.usage().outputTokens();
          if (conversationTokens > COMPACT_AT_TOKENS && turn < questions.size() && pending == null) {
              sent = history.size();
              var summaryParams = MessageCreateParams.builder()
                  .model(Model.CLAUDE_OPUS_5_5)
                  .maxTokens(4096)
                  .system(SYSTEM)
                  .addBeta(AnthropicBeta.COMPACT_2026_09_04)
                  .messages(List.copyOf(history))
                  .compaction(BetaCompactionConfig.builder().build()) // type defaults to "summarize"
                  .build();
              pending = client.async().beta().messages().create(summaryParams);
          }
      }

      // Inserisci un riepilogo ancora in arrivo prima di salvare o proseguire la conversazione.
      if (pending != null) {
          swapIn(history, pending.join(), sent);
      }
      client.close();
  }
  ```

  <CodeGroupItem language="PHP">
    L'SDK PHP invia le richieste in modo sincrono, quindi non può eseguire la richiesta di compattazione in background mentre la conversazione prosegue.
  </CodeGroupItem>

  ```ruby Ruby
  client = Anthropic::Client.new

  # Imposta questo valore vicino al tuo budget di input reale. Qui è basso così una conversazione breve viene compattata.
  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, summary, sent)
    return history unless summary.stop_reason == :compaction

    puts "Swapped #{sent} messages"
    # Sostituisci esattamente i messaggi contenuti nella richiesta di compattazione. I turni successivi restano dopo il blocco.
    [{ role: "assistant", content: summary.content }, *history[sent..]]
  end

  history = []
  pending = nil
  sent = 0
  questions.each.with_index(1) do |question, turn|
    if pending && !pending.alive?
      history = swap_in(history, pending.value, sent)
      pending = nil
    end

    history << { role: "user", content: question }
    response = client.beta.messages.create(
      model: Anthropic::Model::CLAUDE_OPUS_5_5,
      max_tokens: 8192,
      system_: SYSTEM,
      betas: [Anthropic::AnthropicBeta::COMPACT_2026_09_04],
      messages: history
    )
    history << { role: "assistant", content: response.content }

    # Anche la richiesta successiva invia questa risposta, quindi conteggiala.
    conversation_tokens = response.usage.input_tokens + response.usage.output_tokens
    if conversation_tokens > COMPACT_AT_TOKENS && turn < questions.length && pending.nil?
      sent = history.length
      pending = Thread.new(history.dup) do |snapshot|
        client.beta.messages.create(
          model: Anthropic::Model::CLAUDE_OPUS_5_5,
          max_tokens: 4096,
          system_: SYSTEM,
          betas: [Anthropic::AnthropicBeta::COMPACT_2026_09_04],
          messages: snapshot,
          compaction: { type: "summarize" }
        )
      end
    end
  end

  # Inserisci un riepilogo ancora in arrivo prima di salvare o proseguire la conversazione.
  history = swap_in(history, pending.value, sent) if pending
  ```
</CodeGroup>

* **Decidere quando compattare:** il controllo delle dimensioni richiede anche che non ci sia alcuna richiesta di compattazione in sospeso.
* **Avviare la richiesta:** laddove il ciclo attende la risposta di compattazione, questa versione registra quanti messaggi contiene la cronologia, avvia la richiesta su una copia della cronologia con lo strumento di concorrenza proprio di ciascun linguaggio e passa al turno successivo senza attendere.
* **Verificare il risultato:** all'inizio di ogni turno, il programma verifica se la richiesta in sospeso è terminata. In caso affermativo, il programma esegue la sostituzione prima di inviare la richiesta di quel turno.
* **Eseguire la sostituzione:** laddove il ciclo sostituisce l'intera cronologia con il messaggio restituito, la funzione di sostituzione di questa versione sostituisce solo i messaggi contenuti nella richiesta, contati dall'inizio, e mantiene tutto ciò che è stato aggiunto successivamente.
* **Terminare il ciclo:** se la richiesta di compattazione è ancora in sospeso quando il ciclo termina, il programma la attende ed esegue la sostituzione, in modo che un riepilogo ancora in arrivo non vada perso prima che tu salvi o prosegua la conversazione.

Il controllo di `stop_reason` è invariato rispetto al ciclo: una risposta senza blocco lascia la cronologia com'era. Poiché non c'è più nulla in sospeso, il programma può quindi avviare una nuova richiesta di compattazione.

## Mantenere valido il ragionamento mentre il riepilogo viene creato

I turni che arrivano mentre il riepilogo viene scritto sono turni mantenuti. Se rinvii i blocchi di ragionamento su un modello con [ragionamento preservato](https://platform.claude.com/docs/it/build-with-claude/preserved-thinking), il ragionamento in quei turni rimane valido solo finché valgono le [condizioni per il ragionamento mantenuto](https://platform.claude.com/docs/it/build-with-claude/compaction-thinking-blocks#conditions-for-kept-thinking-to-stay-valid).
