---
title: 압축과 보존된 사고
url: https://platform.claude.com/docs/ko/build-with-claude/compaction-thinking-blocks
description: 보존된 사고를 지원하는 모델에서 온디맨드 압축 후 유지된 턴의 사고 블록이 유효하게 유지되는 경우와 이를 확인하는 방법을 설명합니다.
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
---

["preserved thinking"(보존된 사고)](https://platform.claude.com/docs/ko/build-with-claude/preserved-thinking)를 지원하는 모델에 사고 블록을 다시 보내고 "compaction"(압축) 블록 이후의 턴을 유지하는 경우가 아니라면 이 페이지를 건너뛰세요. "Kept turns"(유지된 턴)는 블록 뒤에 오는 턴으로, [최근 턴을 유지하는 압축](https://platform.claude.com/docs/ko/build-with-claude/compaction-keep-recent-turns)에서처럼 압축 요청에서 제외한 최근 턴이거나, [백그라운드 압축](https://platform.claude.com/docs/ko/build-with-claude/compaction-background)에서처럼 요약이 작성되는 동안 도착한 턴입니다.

보존된 사고를 지원하는 모델은 이전 사고 블록을 그것을 생성한 대화와 대조하여 확인합니다. 요약은 해당 대화의 일부를 대체하지만, API가 요약을 작성한 경우 확인 과정에서 이 교체를 허용하므로 유지된 턴의 사고는 유효한 상태로 남을 수 있습니다.

## 유지된 사고가 유효하게 유지되기 위한 조건

유지된 턴의 사고 블록은 다음 조건이 모두 충족되는 동안 유효하게 유지됩니다:

* **압축 요청이 보존된 사고를 지원하는 모델에서 실행됩니다.** 이 조건은 가장 최근의 압축 요청뿐만 아니라 사고 블록이 생성된 이후의 모든 압축 요청에 적용됩니다. 이 조건을 충족하는 한 가지 방법은 모든 압축 요청을 대화에서 사용하는 모델로 보내는 것입니다.
* **유지된 턴이 요약된 메시지 바로 뒤에 오며, 이를 변경하지 않고 보냅니다.** 각 유지된 메시지를 기록에 있는 그대로 정확히 보내세요. 마지막 요약된 메시지와 첫 번째 유지된 메시지 사이에서 메시지를 건너뛰거나 추가하지 마세요. 또한 첫 번째 유지된 메시지는 마지막 요약된 메시지와 다른 역할(role)을 가져야 하며, 대화 중간의 `role: "system"` 메시지일 수 없습니다. 그렇지 않으면 API가 이를 마지막 요약된 메시지에 병합합니다. 첫 번째 유지된 메시지를 올바르게 구성하는 한 가지 방법은 이미 보낸 요청의 `messages`를 정확히 그대로 압축하는 것입니다. 그러면 유지된 턴은 해당 요청에 대한 Claude의 응답으로 시작합니다.
* **`system`과 `defer_loading: true`로 표시되지 않은 `tools`가 변경되지 않습니다.** 이들은 압축 요청에서도 유지된 사고를 생성한 요청에서와 동일하며, 이후 요청에서도 동일하게 유지됩니다. [시스템 프롬프트 또는 도구 변경](https://platform.claude.com/docs/ko/build-with-claude/compaction-thinking-blocks#change-the-system-prompt-or-tools)에서 이를 안전하게 변경하는 방법을 다룹니다.

조건이 충족되지 않더라도 압축 시에는 아무것도 실패하지 않으며, API는 어느 경우든 이후 요청에서 블록을 허용합니다. 실패는 API가 확인을 적용하는 곳에서 유지된 사고를 보내는 첫 번째 이후 요청에서 발생합니다: 기본적으로 400 오류가 발생하거나, 요청에서 `thinking.block_binding.prefix_mismatch_behavior`를 `"drop_block"`으로 설정한 경우 사고 블록이 삭제됩니다. Message Batches API에서는 이 필드를 설정하지 않은 항목이 실패하지 않습니다. 확인이 기본적으로 적용되는 경우, API는 대신 블록을 삭제합니다. [API가 무효한 블록을 처리하는 방식](https://platform.claude.com/docs/ko/build-with-claude/preserved-thinking#mismatch-behavior)에서 두 결과를 모두 설명하며, [API가 확인을 적용하는 시점](https://platform.claude.com/docs/ko/build-with-claude/preserved-thinking#enforcement)에서 어떤 요청이 확인되는지 설명합니다.

## 이전 사고를 손상시키지 않고 다시 압축하기

[다시 압축](https://platform.claude.com/docs/ko/build-with-claude/compaction-on-demand#compact-again)하면서 턴을 유지할 수 있습니다: 새 블록은 이전 요약과 압축 요청에서 그 뒤에 오는 모든 메시지를 포함하며, 해당 요청에서 제외한 턴은 새 블록의 유지된 턴이 됩니다.

[유지된 사고에 대한 조건](https://platform.claude.com/docs/ko/build-with-claude/compaction-thinking-blocks#conditions-for-kept-thinking-to-stay-valid) 중 첫 번째는 사고 블록이 생성된 이후의 모든 압축을 대상으로 하므로, 두 번의 압축을 거쳐 유지하는 턴은 두 압축 모두 보존된 사고를 지원하는 모델에서 실행되어야 합니다.

사고 블록이 생성되기 전의 압축은 해당 블록에 영향을 주지 않습니다. 블록이 자리 잡은 후 생성된 사고는 해당 블록에 바인딩되며, 조건을 충족하는 이후 압축을 거쳐도 유효하게 유지됩니다.

## 시스템 프롬프트 또는 도구 변경

이후 요청은 압축 요청과 다른 `system`, 다른 `tools` 또는 다른 모델을 사용할 수 있으며, API는 여전히 블록을 허용합니다. 이러한 변경은 유지된 턴의 사고를 무효화할 수 있지만, 그 외의 영향은 없습니다.

유지된 사고를 무효화하지 않고 `system` 또는 `tools`를 변경하려면, 먼저 전체 대화를 압축하여 유지되는 턴이 없도록 하세요. 그런 다음 다음 요청에서 변경하세요.

`system` 또는 `tools`를 건드리지 않고 지시를 추가하거나 사용 가능한 도구를 변경하려면, [접두사를 편집하지 않고 변경하기](https://platform.claude.com/docs/ko/build-with-claude/preserved-thinking#replace-prefix-edits)에 설명된 대로 변경 사항을 `messages`에 추가하세요.

요약된 턴 내부의 대화 중간 시스템 메시지도 함께 요약되므로, 교체 후에는 해당 텍스트 지시가 더 이상 적용되지 않습니다. 이 메시지들이 설정한 [메시지별 effort](https://platform.claude.com/docs/ko/build-with-claude/effort#change-effort-mid-conversation-beta) 수준도 이어지지 않습니다. 이후 메시지가 수준을 설정할 때까지 턴은 요청의 최상위 `output_config.effort`로 실행되며, 이를 설정하지 않은 경우 모델의 기본값으로 실행됩니다. 지시나 effort 수준을 계속 적용하려면, 유지된 턴 뒤에 오는 첫 번째 새 `user` 턴 바로 다음에 `role: "system"` 메시지로 이를 다시 명시하세요. 압축 요청에 `inline-tools-2026-09-15`도 포함된 경우, 해당 턴 내부의 도구 변경은 자동으로 이어집니다. 반환된 블록이 그 최종 효과를 `tool_changes` 필드에 기록하므로, 블록을 수정하지 않고 그대로 다시 보내세요. 블록에 `tool_changes` 필드가 없으면 해당 도구 변경도 같은 방식으로 다시 명시하세요. 블록과 유지된 턴 사이에 배치된 시스템 메시지는 해당 턴의 사고를 손상시킵니다.

## 유지된 사고가 유효한지 확인하기

압축 응답은 유지된 사고가 유효한지 알려주지 않습니다. 교체 후 첫 번째 요청이 이를 알려줍니다. 테스트에서 확인하려면:

1. 사고를 켠 상태로 짧은 대화를 진행하세요. API가 확인을 실행하는 모델을 사용하고([API가 확인을 적용하는 시점](https://platform.claude.com/docs/ko/build-with-claude/preserved-thinking#enforcement) 참조), 모든 단계에서 해당 모델을 사용하세요. 사고 블록을 읽을 수 없는 모델은 오류 없이 블록을 삭제하기 때문입니다.
2. 이전 턴을 압축하고, 사고 블록을 포함하는 턴을 하나 이상 유지하세요.
3. 블록을 먼저, 그다음 유지된 턴, 그다음 새 `user` 메시지 순서로 배치하고 `thinking.block_binding.prefix_mismatch_behavior`를 `"error"`로 설정하여 다음 요청을 보내세요.
4. 결과를 확인하세요. `input_transformations` 배열이 비어 있는 200 응답은 확인에 실패하거나 삭제된 사고 블록이 없음을 의미합니다. 블록이 다른 대화에 바인딩되어 있다는 400 오류는 그러한 블록이 있음을 의미합니다. 메시지는 실패한 첫 번째 블록의 경로로 시작하며, [API가 무효한 블록을 처리하는 방식](https://platform.claude.com/docs/ko/build-with-claude/preserved-thinking#mismatch-behavior)에서 전체 메시지를 보여줍니다.

`prefix_mismatch_behavior` 필드에는 [`compact-2026-09-04` 베타 헤더](https://platform.claude.com/docs/ko/build-with-claude/compaction-on-demand#request-a-summary)와 함께 `thinking-binding-controls-2026-08-01` 베타 헤더가 필요합니다. 이 필드를 설정하면 확인이 기본적으로 활성화되지 않은 계정에서도 요청이 확인에 참여하게 됩니다.

다음 프로그램은 네 단계를 실행합니다. 유지된 턴에 포함된 사고 블록 수와 `input_transformations`의 항목 수를 출력하며, 항목이 없으면 유지된 사고가 유효하다는 의미입니다:

<CodeGroup exclude="shell">
  ```python Python
  from anthropic.types.beta import BetaMessageParam, BetaThinkingConfigParam

  client = anthropic.Anthropic()

  # Claude Fable 5.1은 다시 전송된 사고 내용을 대화와 대조하여 검사하는 첫 번째 모델입니다.
  MODEL = "claude-fable-5-1"
  BETAS = ["compact-2026-09-04", "thinking-binding-controls-2026-08-01"]
  SYSTEM = "You help plan a recipe app's release. Keep answers short."
  # "error"로 설정하면 검사에 실패한 사고 블록으로 인해 요청이 400으로 실패합니다.
  THINKING: BetaThinkingConfigParam = {
      "type": "adaptive",
      "block_binding": {"prefix_mismatch_behavior": "error"},
  }

  # 1. 사고를 켠 상태로 짧은 대화를 진행합니다.
  history: list[BetaMessageParam] = [
      {"role": "user", "content": "What are the main entities in the app's data model?"}
  ]
  first = client.beta.messages.create(
      model=MODEL,
      max_tokens=8192,
      system=SYSTEM,
      betas=BETAS,
      thinking=THINKING,
      messages=history,
  )
  history += [
      {"role": "assistant", "content": first.content},
      {
          "role": "user",
          "content": "Testing starts on Tuesday, March 3, 2026, takes 10 weekdays, and pauses on March 9 and March 16. On which date does it end?",
      },
  ]
  second = client.beta.messages.create(
      model=MODEL,
      max_tokens=8192,
      system=SYSTEM,
      betas=BETAS,
      thinking=THINKING,
      messages=history,
  )
  history.append({"role": "assistant", "content": second.content})
  thinking_blocks = sum(block.type == "thinking" for block in second.content)
  print(f"Thinking blocks in the kept turn: {thinking_blocks}")

  # 2. 첫 번째 턴을 요약합니다. 두 번째 턴은 요청에 포함하지 않습니다.
  summary = client.beta.messages.create(
      model=MODEL,
      max_tokens=4096,
      system=SYSTEM,
      betas=BETAS,
      thinking=THINKING,
      messages=history[:2],
      compaction={"type": "summarize"},
  )
  if summary.stop_reason != "compaction":
      raise SystemExit(f"No summary: {summary.stop_reason}")

  # 3. 유지한 턴 앞에 블록을 배치하고 다음 질문을 합니다.
  history = [
      {"role": "assistant", "content": summary.content},
      *history[2:],
      {"role": "user", "content": "Which day should the release go out?"},
  ]
  third = client.beta.messages.create(
      model=MODEL,
      max_tokens=8192,
      system=SYSTEM,
      betas=BETAS,
      thinking=THINKING,
      messages=history,
  )

  # 4. 삭제된 블록 없이 200이 반환되면 유지한 사고가 유효하다는 의미입니다.
  print(f"Dropped thinking blocks: {len(third.input_transformations)}")
  ```

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

  // Claude Fable 5.1은 다시 전송된 thinking을 대화 내용과 대조하여 검사하는 첫 번째 모델입니다.
  const model: Anthropic.Model = "claude-fable-5-1";
  const betas: Anthropic.Beta.AnthropicBeta[] = [
    "compact-2026-09-04",
    "thinking-binding-controls-2026-08-01"
  ];
  const systemPrompt = "You help plan a recipe app's release. Keep answers short.";
  // "error"로 설정하면 검사에 실패한 thinking 블록이 있을 때 요청이 400으로 실패합니다.
  const thinking: Anthropic.Beta.Messages.BetaThinkingConfigParam = {
    type: "adaptive",
    block_binding: { prefix_mismatch_behavior: "error" }
  };

  // 1. thinking을 켠 상태로 짧은 대화를 진행합니다.
  let history: Anthropic.Beta.Messages.BetaMessageParam[] = [
    { role: "user", content: "What are the main entities in the app's data model?" }
  ];
  const first = await client.beta.messages.create({
    model,
    max_tokens: 8192,
    system: systemPrompt,
    betas,
    thinking,
    messages: history
  });
  history.push(
    { role: "assistant", content: first.content },
    {
      role: "user",
      content:
        "Testing starts on Tuesday, March 3, 2026, takes 10 weekdays, and pauses on March 9 and March 16. On which date does it end?"
    }
  );
  const second = await client.beta.messages.create({
    model,
    max_tokens: 8192,
    system: systemPrompt,
    betas,
    thinking,
    messages: history
  });
  history.push({ role: "assistant", content: second.content });
  const thinkingBlocks = second.content.filter((block) => block.type === "thinking").length;
  console.log(`Thinking blocks in the kept turn: ${thinkingBlocks}`);

  // 2. 첫 번째 턴을 요약합니다. 두 번째 턴은 요청에 포함하지 않습니다.
  const summary = await client.beta.messages.create({
    model,
    max_tokens: 4096,
    system: systemPrompt,
    betas,
    thinking,
    messages: history.slice(0, 2),
    compaction: { type: "summarize" }
  });
  if (summary.stop_reason !== "compaction") {
    throw new Error(`No summary: ${summary.stop_reason}`);
  }

  // 3. 유지한 턴 앞에 블록을 배치하고 다음 질문을 합니다.
  history = [
    { role: "assistant", content: summary.content },
    ...history.slice(2),
    { role: "user", content: "Which day should the release go out?" }
  ];
  const third = await client.beta.messages.create({
    model,
    max_tokens: 8192,
    system: systemPrompt,
    betas,
    thinking,
    messages: history
  });

  // 4. 삭제된 블록 없이 200이 반환되면 유지한 thinking이 검사를 통과한 것입니다.
  console.log(`Dropped thinking blocks: ${third.input_transformations?.length ?? 0}`);
  ```

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

  AnthropicClient client = new();

  // Claude Fable 5.1은 다시 전송된 thinking을 대화 내용과 대조해 검사하는 첫 번째 모델입니다.
  const Model ModelId = Model.ClaudeFable5_1;
  AnthropicBeta[] betas = [AnthropicBeta.Compact2026_09_04, AnthropicBeta.ThinkingBindingControls2026_08_01];
  const string SystemPrompt = "You help plan a recipe app's release. Keep answers short.";
  // "error"로 설정하면 검사에 실패한 thinking 블록이 있을 때 요청이 400으로 실패합니다.
  BetaThinkingConfigAdaptive thinking = new()
  {
      BlockBinding = new() { PrefixMismatchBehavior = BetaThinkingPrefixMismatchBehavior.Error },
  };

  // 1. thinking을 켠 상태로 짧은 대화를 진행합니다.
  List<BetaMessageParam> history =
  [
      new() { Role = Role.User, Content = "What are the main entities in the app's data model?" },
  ];
  var first = await client.Beta.Messages.Create(new MessageCreateParams
  {
      Model = ModelId,
      MaxTokens = 8192,
      System = SystemPrompt,
      Betas = [.. betas],
      Thinking = thinking,
      Messages = history,
  });
  history.AddRange(
  [
      new()
      {
          Role = Role.Assistant,
          Content = first.Content.Select(block => new BetaContentBlockParam(block.Json)).ToList(),
      },
      new()
      {
          Role = Role.User,
          Content = "Testing starts on Tuesday, March 3, 2026, takes 10 weekdays, and pauses on March 9 and March 16. On which date does it end?",
      },
  ]);
  var second = await client.Beta.Messages.Create(new MessageCreateParams
  {
      Model = ModelId,
      MaxTokens = 8192,
      System = SystemPrompt,
      Betas = [.. betas],
      Thinking = thinking,
      Messages = history,
  });
  history.Add(new()
  {
      Role = Role.Assistant,
      Content = second.Content.Select(block => new BetaContentBlockParam(block.Json)).ToList(),
  });
  var thinkingBlocks = second.Content.Count(block => block.TryPickThinking(out _));
  Console.WriteLine($"Thinking blocks in the kept turn: {thinkingBlocks}");

  // 2. 첫 번째 턴을 요약합니다. 두 번째 턴은 요청에 포함하지 않습니다.
  var summary = await client.Beta.Messages.Create(new MessageCreateParams
  {
      Model = ModelId,
      MaxTokens = 4096,
      System = SystemPrompt,
      Betas = [.. betas],
      Thinking = thinking,
      Messages = history[..2],
      Compaction = new BetaCompactionConfig(), // type defaults to "summarize"
  });
  if (summary.StopReason != BetaStopReason.Compaction)
  {
      throw new InvalidOperationException($"No summary: {summary.StopReason?.Raw()}");
  }

  // 3. 유지한 턴 앞에 블록을 넣고 다음 질문을 합니다.
  history =
  [
      new()
      {
          Role = Role.Assistant,
          Content = summary.Content.Select(block => new BetaContentBlockParam(block.Json)).ToList(),
      },
      .. history[2..],
      new() { Role = Role.User, Content = "Which day should the release go out?" },
  ];
  var third = await client.Beta.Messages.Create(new MessageCreateParams
  {
      Model = ModelId,
      MaxTokens = 8192,
      System = SystemPrompt,
      Betas = [.. betas],
      Thinking = thinking,
      Messages = history,
  });

  // 4. 삭제된 블록 없이 200이 반환되면 유지한 thinking이 검사를 통과한 것입니다.
  Console.WriteLine($"Dropped thinking blocks: {third.InputTransformations?.Count ?? 0}");
  ```

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

  // Claude Fable 5.1은 다시 전송된 사고 내용을 대화와 대조하여 검사하는 첫 번째 모델입니다.
  const model = anthropic.ModelClaudeFable5_1
  betas := []anthropic.AnthropicBeta{
  	anthropic.AnthropicBetaCompact2026_09_04,
  	anthropic.AnthropicBetaThinkingBindingControls2026_08_01,
  }
  system := []anthropic.BetaTextBlockParam{{Text: "You help plan a recipe app's release. Keep answers short."}}
  // "error"로 설정하면 검사에 실패한 사고 블록으로 인해 요청이 400으로 실패합니다.
  thinking := anthropic.BetaThinkingConfigParamUnion{
  	OfAdaptive: &anthropic.BetaThinkingConfigAdaptiveParam{
  		BlockBinding: anthropic.BetaThinkingBlockBindingParam{
  			PrefixMismatchBehavior: anthropic.BetaThinkingPrefixMismatchBehaviorError,
  		},
  	},
  }

  // 1. 사고를 켠 상태로 짧은 대화를 진행합니다.
  history := []anthropic.BetaMessageParam{
  	anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("What are the main entities in the app's data model?")),
  }
  first, err := client.Beta.Messages.New(ctx, anthropic.BetaMessageNewParams{
  	Model:     model,
  	MaxTokens: 8192,
  	System:    system,
  	Betas:     betas,
  	Thinking:  thinking,
  	Messages:  history,
  })
  if err != nil {
  	log.Fatal(err)
  }
  history = append(history,
  	first.ToParam(),
  	anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("Testing starts on Tuesday, March 3, 2026, takes 10 weekdays, and pauses on March 9 and March 16. On which date does it end?")),
  )
  second, err := client.Beta.Messages.New(ctx, anthropic.BetaMessageNewParams{
  	Model:     model,
  	MaxTokens: 8192,
  	System:    system,
  	Betas:     betas,
  	Thinking:  thinking,
  	Messages:  history,
  })
  if err != nil {
  	log.Fatal(err)
  }
  history = append(history, second.ToParam())
  thinkingBlocks := 0
  for _, block := range second.Content {
  	if _, ok := block.AsAny().(anthropic.BetaThinkingBlock); ok {
  		thinkingBlocks++
  	}
  }
  fmt.Printf("Thinking blocks in the kept turn: %d\n", thinkingBlocks)

  // 2. 첫 번째 턴을 요약합니다. 두 번째 턴은 요청에 포함하지 않습니다.
  summary, err := client.Beta.Messages.New(ctx, anthropic.BetaMessageNewParams{
  	Model:     model,
  	MaxTokens: 4096,
  	System:    system,
  	Betas:     betas,
  	Thinking:  thinking,
  	Messages:  history[:2],
  	Compaction: anthropic.BetaCompactionConfigUnionParam{
  		OfSummarize: &anthropic.BetaSummarizeCompactionParam{},
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }
  if summary.StopReason != anthropic.BetaStopReasonCompaction {
  	log.Fatalf("No summary: %s", summary.StopReason)
  }

  // 3. 유지한 턴 앞에 블록을 배치하고 다음 질문을 합니다.
  history = slices.Concat(
  	[]anthropic.BetaMessageParam{summary.ToParam()},
  	history[2:],
  	[]anthropic.BetaMessageParam{anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("Which day should the release go out?"))},
  )
  third, err := client.Beta.Messages.New(ctx, anthropic.BetaMessageNewParams{
  	Model:     model,
  	MaxTokens: 8192,
  	System:    system,
  	Betas:     betas,
  	Thinking:  thinking,
  	Messages:  history,
  })
  if err != nil {
  	log.Fatal(err)
  }

  // 4. 삭제된 블록 없이 200이 반환되면 유지한 사고가 검사를 통과한 것입니다.
  fmt.Printf("Dropped thinking blocks: %d\n", len(third.InputTransformations))
  ```

  ```java Java
  import com.anthropic.models.beta.AnthropicBeta;
  import com.anthropic.models.beta.messages.BetaCompactionConfig;
  import com.anthropic.models.beta.messages.BetaContentBlock;
  import com.anthropic.models.beta.messages.BetaMessageParam;
  import com.anthropic.models.beta.messages.BetaStopReason;
  import com.anthropic.models.beta.messages.BetaThinkingBlockBinding;
  import com.anthropic.models.beta.messages.BetaThinkingConfigAdaptive;
  import com.anthropic.models.beta.messages.BetaThinkingPrefixMismatchBehavior;
  import com.anthropic.models.beta.messages.MessageCreateParams;

  // Claude Fable 5.1은 다시 전송된 thinking을 대화 내용과 대조하여 검사하는 최초의 모델입니다.
  static final Model MODEL = Model.CLAUDE_FABLE_5_1;
  static final List<AnthropicBeta> BETAS = List.of(
      AnthropicBeta.COMPACT_2026_09_04,
      AnthropicBeta.THINKING_BINDING_CONTROLS_2026_08_01
  );
  static final String SYSTEM = "You help plan a recipe app's release. Keep answers short.";
  // "error"로 설정하면 검사에 실패한 thinking 블록이 있을 때 요청이 400으로 실패합니다.
  static final BetaThinkingConfigAdaptive THINKING = BetaThinkingConfigAdaptive.builder()
      .blockBinding(BetaThinkingBlockBinding.builder()
          .prefixMismatchBehavior(BetaThinkingPrefixMismatchBehavior.ERROR)
          .build())
      .build();

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

      // 1. thinking을 켠 상태로 짧은 대화를 진행합니다.
      var history = new ArrayList<BetaMessageParam>();
      history.add(BetaMessageParam.builder()
          .role(BetaMessageParam.Role.USER)
          .content("What are the main entities in the app's data model?")
          .build());
      var firstParams = MessageCreateParams.builder()
          .model(MODEL)
          .maxTokens(8192)
          .system(SYSTEM)
          .betas(BETAS)
          .thinking(THINKING)
          .messages(history)
          .build();
      var first = client.beta().messages().create(firstParams);
      history.add(first.toParam());
      history.add(BetaMessageParam.builder()
          .role(BetaMessageParam.Role.USER)
          .content("Testing starts on Tuesday, March 3, 2026, takes 10 weekdays, and pauses on March 9 and March 16. On which date does it end?")
          .build());
      var secondParams = MessageCreateParams.builder()
          .model(MODEL)
          .maxTokens(8192)
          .system(SYSTEM)
          .betas(BETAS)
          .thinking(THINKING)
          .messages(history)
          .build();
      var second = client.beta().messages().create(secondParams);
      history.add(second.toParam());
      long thinkingBlocks = second.content().stream().filter(BetaContentBlock::isThinking).count();
      IO.println("Thinking blocks in the kept turn: " + thinkingBlocks);

      // 2. 첫 번째 턴을 요약합니다. 두 번째 턴은 요청에 포함하지 않습니다.
      var firstTurn = history.subList(0, 2);
      var summaryParams = MessageCreateParams.builder()
          .model(MODEL)
          .maxTokens(4096)
          .system(SYSTEM)
          .betas(BETAS)
          .thinking(THINKING)
          .messages(firstTurn)
          .compaction(BetaCompactionConfig.builder().build()) // type defaults to "summarize"
          .build();
      var summary = client.beta().messages().create(summaryParams);
      if (!summary.stopReason().map(BetaStopReason.COMPACTION::equals).orElse(false)) {
          throw new IllegalStateException("No summary: " + summary.stopReason().orElseThrow());
      }

      // 3. 유지한 턴 앞에 블록을 배치하고 다음 질문을 합니다.
      firstTurn.clear();
      history.addFirst(summary.toParam());
      history.add(BetaMessageParam.builder()
          .role(BetaMessageParam.Role.USER)
          .content("Which day should the release go out?")
          .build());
      var thirdParams = MessageCreateParams.builder()
          .model(MODEL)
          .maxTokens(8192)
          .system(SYSTEM)
          .betas(BETAS)
          .thinking(THINKING)
          .messages(history)
          .build();
      var third = client.beta().messages().create(thirdParams);

      // 4. 삭제된 블록 없이 200이 반환되면 유지한 thinking이 검사를 통과한 것입니다.
      IO.println("Dropped thinking blocks: " + third.inputTransformations().map(List::size).orElse(0));
  }
  ```

  ```php PHP
  use Anthropic\Beta\AnthropicBeta;
  use Anthropic\Beta\Messages\BetaCompactionConfig;
  use Anthropic\Beta\Messages\BetaMessageParam;
  use Anthropic\Beta\Messages\BetaMessageParam\Role;
  use Anthropic\Beta\Messages\BetaStopReason;
  use Anthropic\Beta\Messages\BetaThinkingBlock;
  use Anthropic\Beta\Messages\BetaThinkingBlockBinding;
  use Anthropic\Beta\Messages\BetaThinkingConfigAdaptive;
  use Anthropic\Beta\Messages\BetaThinkingPrefixMismatchBehavior;

  $client = new Client();

  // Claude Fable 5.1은 다시 전송된 thinking을 대화 내용과 대조해 검사하는 첫 번째 모델입니다.
  const MODEL = Model::CLAUDE_FABLE_5_1;
  const BETAS = [AnthropicBeta::COMPACT_2026_09_04, AnthropicBeta::THINKING_BINDING_CONTROLS_2026_08_01];
  const SYSTEM = "You help plan a recipe app's release. Keep answers short.";
  // "error"를 사용하면 검사에 실패한 thinking 블록이 있을 때 요청이 400으로 실패합니다.
  $thinking = BetaThinkingConfigAdaptive::with(
      blockBinding: BetaThinkingBlockBinding::with(
          prefixMismatchBehavior: BetaThinkingPrefixMismatchBehavior::ERROR,
      ),
  );

  // 1. thinking을 켠 상태로 짧은 대화를 진행합니다.
  $history = [
      BetaMessageParam::with(role: Role::USER, content: "What are the main entities in the app's data model?"),
  ];
  $first = $client->beta->messages->create(
      model: MODEL,
      maxTokens: 8192,
      system: SYSTEM,
      betas: BETAS,
      thinking: $thinking,
      messages: $history,
  );
  $history[] = BetaMessageParam::with(role: Role::ASSISTANT, content: $first->content);
  $history[] = BetaMessageParam::with(
      role: Role::USER,
      content: 'Testing starts on Tuesday, March 3, 2026, takes 10 weekdays, and pauses on March 9 and March 16. On which date does it end?',
  );
  $second = $client->beta->messages->create(
      model: MODEL,
      maxTokens: 8192,
      system: SYSTEM,
      betas: BETAS,
      thinking: $thinking,
      messages: $history,
  );
  $history[] = BetaMessageParam::with(role: Role::ASSISTANT, content: $second->content);
  $thinkingBlocks = count(array_filter($second->content, fn ($block) => $block instanceof BetaThinkingBlock));
  printf("Thinking blocks in the kept turn: %d\n", $thinkingBlocks);

  // 2. 첫 번째 턴을 요약합니다. 두 번째 턴은 요청에 포함하지 않습니다.
  $summary = $client->beta->messages->create(
      model: MODEL,
      maxTokens: 4096,
      system: SYSTEM,
      betas: BETAS,
      thinking: $thinking,
      messages: array_slice($history, 0, 2),
      compaction: new BetaCompactionConfig(), // type defaults to 'summarize'
  );
  if ($summary->stopReason !== BetaStopReason::COMPACTION->value) {
      throw new \RuntimeException("No summary: {$summary->stopReason}");
  }

  // 3. 유지한 턴 앞에 블록을 배치하고 다음 질문을 합니다.
  $history = [
      BetaMessageParam::with(role: Role::ASSISTANT, content: $summary->content),
      ...array_slice($history, 2),
      BetaMessageParam::with(role: Role::USER, content: 'Which day should the release go out?'),
  ];
  $third = $client->beta->messages->create(
      model: MODEL,
      maxTokens: 8192,
      system: SYSTEM,
      betas: BETAS,
      thinking: $thinking,
      messages: $history,
  );

  // 4. 삭제된 블록 없이 200이 반환되면 유지한 thinking이 검사를 통과한 것입니다.
  printf("Dropped thinking blocks: %d\n", count($third->inputTransformations));
  ```

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

  # Claude Fable 5.1은 다시 전송된 사고 내용을 대화와 대조하여 검사하는 첫 번째 모델입니다.
  MODEL = Anthropic::Model::CLAUDE_FABLE_5_1
  BETAS = [
    Anthropic::AnthropicBeta::COMPACT_2026_09_04,
    Anthropic::AnthropicBeta::THINKING_BINDING_CONTROLS_2026_08_01
  ]
  SYSTEM = "You help plan a recipe app's release. Keep answers short."
  # "error"로 설정하면 검사에 실패한 사고 블록이 있을 때 요청이 400 오류로 실패합니다.
  THINKING = Anthropic::Beta::BetaThinkingConfigAdaptive.new(
    block_binding: Anthropic::Beta::BetaThinkingBlockBinding.new(
      prefix_mismatch_behavior: Anthropic::Beta::BetaThinkingPrefixMismatchBehavior::ERROR
    )
  )

  # 1. 사고를 켠 상태로 짧은 대화를 진행합니다.
  history = [{ role: "user", content: "What are the main entities in the app's data model?" }]
  first = client.beta.messages.create(
    model: MODEL,
    max_tokens: 8192,
    system_: SYSTEM,
    betas: BETAS,
    thinking: THINKING,
    messages: history
  )
  history += [
    { role: "assistant", content: first.content },
    {
      role: "user",
      content: "Testing starts on Tuesday, March 3, 2026, takes 10 weekdays, and pauses on March 9 and March 16. On which date does it end?"
    }
  ]
  second = client.beta.messages.create(
    model: MODEL,
    max_tokens: 8192,
    system_: SYSTEM,
    betas: BETAS,
    thinking: THINKING,
    messages: history
  )
  history << { role: "assistant", content: second.content }
  thinking_blocks = second.content.count { it.is_a?(Anthropic::Beta::BetaThinkingBlock) }
  puts "Thinking blocks in the kept turn: #{thinking_blocks}"

  # 2. 첫 번째 턴을 요약합니다. 두 번째 턴은 요청에 포함하지 않습니다.
  summary = client.beta.messages.create(
    model: MODEL,
    max_tokens: 4096,
    system_: SYSTEM,
    betas: BETAS,
    thinking: THINKING,
    messages: history.first(2),
    compaction: { type: "summarize" }
  )
  abort "No summary: #{summary.stop_reason}" unless summary.stop_reason == :compaction

  # 3. 유지한 턴 앞에 블록을 배치하고 다음 질문을 합니다.
  history = [
    { role: "assistant", content: summary.content },
    *history.drop(2),
    { role: "user", content: "Which day should the release go out?" }
  ]
  third = client.beta.messages.create(
    model: MODEL,
    max_tokens: 8192,
    system_: SYSTEM,
    betas: BETAS,
    thinking: THINKING,
    messages: history
  )

  # 4. 삭제된 블록 없이 200이 반환되면 유지한 사고가 검사를 통과한 것입니다.
  puts "Dropped thinking blocks: #{third.input_transformations.length}"
  ```
</CodeGroup>

```text Output wrap
Thinking blocks in the kept turn: 1
Dropped thinking blocks: 0
```

프로덕션 환경에서 `"drop_block"`은 조건이 충족되지 않을 때에도 요청이 계속 성공하도록 하며, 삭제된 각 블록을 `reason: "prefix_binding_mismatch"`와 함께 `input_transformations`에 보고합니다. `path`가 유지된 턴에 해당하는 항목은 그 턴의 사고가 유효하지 않았다는 의미입니다. [API가 무효한 블록을 처리하는 방식](https://platform.claude.com/docs/ko/build-with-claude/preserved-thinking#mismatch-behavior)에서 무엇이 삭제되는지와 이에 대한 알림을 설정하는 방법을 설명합니다. Claude Sonnet 5.5와 Claude Haiku 5.5에서 `block_binding`은 `thinking: {"type": "adaptive"}`에서만 작동합니다. Claude Sonnet 5.5에서 `thinking: {"type": "between_tools"}`와 함께, 또는 Claude Haiku 5.5에서 `thinking: {"type": "disabled"}`와 함께 이를 설정한 요청은 400 오류를 반환합니다. 이러한 요청에서는 모든 조건이 충족되는지 확인하거나, 유지된 턴에서 `thinking` 및 `redacted_thinking` 블록을 제거하세요.
