---
title: Compactación en segundo plano
url: https://platform.claude.com/docs/es/build-with-claude/compaction-background
description: Solicita un resumen de compactación bajo demanda mientras la conversación continúa con su historial completo y luego intercambia el bloque cuando llegue.
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" (compactación en segundo plano), a menudo llamada "async compaction" (compactación asíncrona), cambia dos cosas en el [bucle de compactación](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#compact-in-a-loop): la solicitud de compactación se ejecuta mientras la conversación continúa con su historial completo, y el "swap" (intercambio) espera hasta que llega el bloque. [Continuar a partir del resumen](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#continue-from-the-summary) y [Manejar un resumen faltante o un error](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#when-no-summary-comes-back) se aplican sin cambios.

## Cómo funciona el intercambio mientras el trabajo continúa

La solicitud de compactación y el bloque que devuelve son los mismos que en el bucle. Tu historial crece entre el envío de la solicitud y el uso de su resultado, y el intercambio debe dejar ese crecimiento en su lugar.

1. Envía la [solicitud de compactación](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#request-a-summary) con tu historial tal como está y registra cuántos mensajes contenía.
2. Mientras esa solicitud se ejecuta, mantén la conversación en marcha con el historial completo. Agrega cada turno nuevo, no edites nada que ya esté en el historial y no inicies otra solicitud de compactación hasta que esta se haya intercambiado o haya fallado.
3. Cuando llegue la respuesta con `stop_reason` `"compaction"`, elimina exactamente los mensajes que enviaste del inicio de tu historial y coloca el mensaje devuelto en su lugar. Cada turno agregado desde el paso 1 permanece después de él.
4. Envía el historial intercambiado en la primera solicitud después de que llegue el bloque, para que el pensamiento producido mientras se escribía el resumen siga siendo válido.

Por ejemplo, si la solicitud de compactación contenía los mensajes 1 a 5 y la conversación ganó los mensajes 6 a 8 mientras se ejecutaba, después del intercambio tu historial es el bloque seguido de los mensajes 6 a 8.

<Frame>
  ![Línea de tiempo de la "background compaction" (compactación en segundo plano): la solicitud de compactación se envía con los mensajes 1 a 5 mientras la conversación continúa con su historial completo y gana los mensajes 6 a 8; cuando llega el bloque, reemplaza los mensajes 1 a 5 al inicio del historial, y el historial pasa a ser el bloque seguido de los mensajes 6 a 8](https://platform.claude.com/docs/es/images/compaction-background-timeline.svg)
</Frame>

Si la respuesta tiene cualquier otro `stop_reason`, no se produjo ningún resumen, lo cual cuenta como un fallo en el paso 2. Conserva el historial completo; [Manejar un resumen faltante o un error](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#when-no-summary-comes-back) enumera las causas y qué hacer en cada caso.

## Solicita el resumen en segundo plano

La solicitud de compactación cuenta para tus "rate limits" (límites de velocidad) como cualquier otra solicitud, y mientras se ejecuta tu aplicación tiene dos solicitudes abiertas a la vez. La conversación sigue creciendo con su historial completo hasta el intercambio, así que inicia la solicitud de compactación mientras la "context window" (ventana de contexto) todavía tenga espacio para los turnos que lleguen mientras tanto.

El siguiente programa es el bucle de [Compactar en un bucle](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#compact-in-a-loop) con la solicitud de compactación fuera de la ruta de la conversación. Las líneas resaltadas muestran dónde difiere del bucle, y la lista siguiente las recorre en el orden en que el programa las ejecuta.

<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)

  # Ajusta esto cerca de tu presupuesto real de entrada. Aquí es bajo para que una conversación corta se compacte.
  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":
          # Reemplaza exactamente los mensajes que contenía la solicitud de compactación.
          # Los turnos posteriores quedan después del bloque.
          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 siguiente solicitud también envía esta respuesta, así que cuéntala.
      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"},
          )

  # Sustituye un resumen que aún está en camino antes de guardar
  # o de continuar la conversación.
  if pending is not None:
      swap_in(history, pending.result(), sent)
  executor.shutdown()
  ```

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

  // Ajusta esto cerca de tu presupuesto real de entrada. Aquí es bajo para que una conversación corta se compacte.
  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`);
    // Reemplaza exactamente los mensajes que contenía la solicitud de compactación. Los turnos posteriores quedan tras el bloque.
    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 });

    // La siguiente solicitud también envía esta respuesta, así que cuéntala.
    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" }
      });
      // Marca la solicitud como resuelta en cualquier caso. Al esperarla, devuelve el resumen o lanza un error.
      const markSettled = () => {
        settled = true;
      };
      pending.then(markSettled, markSettled);
    }
  }

  // Sustituye un resumen que aún está en camino antes de guardar o continuar la conversación.
  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();

  // Ajusta esto cerca de tu presupuesto real de entrada. Aquí es bajo para que una conversación corta se compacte.
  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");
      // Reemplaza exactamente los mensajes que contenía la solicitud de compactación. Los turnos posteriores quedan después del bloque.
      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(),
      });

      // La siguiente solicitud también envía esta respuesta, así que cuéntala.
      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"
          });
      }
  }

  // Sustituye un resumen que aún está en camino antes de guardar o continuar la conversación.
  if (pending is not null)
  {
      history = SwapIn(history, await pending, sent);
  }
  ```

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

  // Ajusta esto cerca de tu presupuesto real de entrada. Aquí es bajo para que una conversación corta se compacte.
  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)
  	// Reemplaza exactamente los mensajes que contenía la solicitud de compactación. Los turnos posteriores quedan después del bloque.
  	history = slices.Replace(history, 0, sent, summary.ToParam())
  }

  for i, question := range questions {
  	turn := i + 1
  	// Recibir de un canal nil nunca tiene éxito, así que esto se omite cuando no hay nada pendiente.
  	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())

  	// La siguiente solicitud también envía esta respuesta, así que cuéntala.
  	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)
  	}
  }

  // Sustituye un resumen que aún está en camino antes de guardar o continuar la conversación.
  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;

  // Ajusta esto cerca de tu presupuesto real de entrada. Aquí es bajo para que una conversación corta se compacte.
  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");
      // Reemplaza exactamente los mensajes que contenía la solicitud de compactación. Los turnos posteriores quedan tras el bloque.
      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());

          // La siguiente solicitud también envía esta respuesta, así que cuéntala.
          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);
          }
      }

      // Sustituye un resumen que aún está en camino antes de guardar o continuar la conversación.
      if (pending != null) {
          swapIn(history, pending.join(), sent);
      }
      client.close();
  }
  ```

  <CodeGroupItem language="PHP">
    El SDK de PHP envía las solicitudes de forma síncrona, por lo que no puede ejecutar la solicitud de compactación en segundo plano mientras la conversación continúa.
  </CodeGroupItem>

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

  # Ajusta esto cerca de tu presupuesto real de entrada. Aquí es bajo para que una conversación corta se compacte.
  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"
    # Reemplaza exactamente los mensajes que contenía la solicitud de compactación. Los turnos posteriores quedan tras el bloque.
    [{ 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 }

    # La siguiente solicitud también envía esta respuesta, así que cuéntala.
    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

  # Sustituye un resumen que aún está en camino antes de guardar o continuar la conversación.
  history = swap_in(history, pending.value, sent) if pending
  ```
</CodeGroup>

* **Decidir cuándo compactar:** La verificación de tamaño también requiere que no haya ninguna solicitud de compactación pendiente.
* **Iniciar la solicitud:** Donde el bucle espera la respuesta de compactación, esta versión registra cuántos mensajes contiene el historial, inicia la solicitud sobre una copia del historial con la herramienta de concurrencia propia de cada lenguaje y pasa al siguiente turno sin esperar.
* **Comprobar el resultado:** Al inicio de cada turno, el programa comprueba si la solicitud pendiente ha terminado. Si es así, el programa realiza el intercambio antes de enviar la solicitud de ese turno.
* **Realizar el intercambio:** Donde el bucle reemplaza todo el historial con el mensaje devuelto, la función de intercambio de esta versión reemplaza solo los mensajes que contenía la solicitud, contados desde el inicio, y conserva todo lo agregado desde entonces.
* **Terminar el bucle:** Si la solicitud de compactación sigue pendiente cuando termina el bucle, el programa la espera y realiza el intercambio, para que un resumen que todavía está en camino no se pierda antes de que guardes o continúes la conversación.

La verificación de `stop_reason` no cambia respecto al bucle: una respuesta sin bloque deja el historial como estaba. Como ya no hay nada pendiente, el programa puede entonces iniciar una nueva solicitud de compactación.

## Mantén válido el pensamiento mientras se construye el resumen

Los turnos que llegan mientras se escribe el resumen son turnos conservados. Si devuelves bloques de pensamiento en un modelo con [pensamiento preservado](https://platform.claude.com/docs/es/build-with-claude/preserved-thinking), el pensamiento de esos turnos sigue siendo válido solo mientras se cumplan las [condiciones para el pensamiento conservado](https://platform.claude.com/docs/es/build-with-claude/compaction-thinking-blocks#conditions-for-kept-thinking-to-stay-valid).
