---
title: オンデマンドコンパクション
url: https://platform.claude.com/docs/ja/build-with-claude/compaction-on-demand
description: アプリケーションが選んだタイミングでClaudeに会話を要約させ、その要約から会話を続行します。
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
---

「on-demand compaction」（オンデマンドコンパクション）では、会話をいつ要約するかをアプリケーションが決定します。`compaction`パラメータを付けたリクエストを1つ送信すると、Claudeは返答の代わりに要約を返します。

## オンデマンドコンパクションの仕組み

コンパクションリクエストは、会話のターンとは別のものです。現時点の会話を`compaction`パラメータとともに送信すると、レスポンスには単一の`compaction`ブロックが含まれます。このブロックには、読むことができるテキストとしての要約と、署名が含まれます。以降のリクエストでは、このブロックを受け取ったとおりにそのまま送信してください。

それ以降、このブロックは要約対象のメッセージの代わりになります。ブロックは`messages`の先頭に置き、要約されたメッセージは削除し、次のターンはその後に続けます。Claudeは、それらのメッセージがあった場所で要約を参照します。

<Frame>
  ![On-demand compaction（オンデマンドコンパクション）：4つのメッセージとcompactionパラメータを含むリクエストは、返答なしで1つのcompactionブロックを返します。次のリクエストでは、そのブロックが4つのメッセージの代わりにmessagesの先頭に置かれ、その後に次のユーザーターンが続きます](https://platform.claude.com/docs/ja/images/compaction-on-demand-swap.svg)
</Frame>

## 要約をリクエストする

要約を求めるリクエストと、署名付きブロックを含む以降のすべてのリクエストで、`compact-2026-09-04`ベータヘッダーを送信してください。モデルがオンデマンドコンパクションをサポートしているかどうかを確認するには、ベータヘッダーを付けて[Models API](https://platform.claude.com/docs/ja/api/beta/models/list)を呼び出し、各モデルの`capabilities.compaction`を確認します。1つのリクエストで`compaction`と`context_management`を組み合わせることはできません。

現時点の会話を`"compaction": {"type": "summarize"}`とともに送信します。APIはリクエスト内のすべてのメッセージを一度に要約し、その後に返答を生成せず、`stop_reason`が`"compaction"`のブロックのみを返します。会話の他の部分で使用しているのと同じ`system`プロンプトと`tools`を送信してください。要約処理はそれらを読み取ります。また、[「preserved thinking」（思考の保持）](https://platform.claude.com/docs/ja/build-with-claude/preserved-thinking)を使用するモデルでブロックの後のターンを保持する場合、それらのターン内の思考は`system`と`tools`が一致する場合にのみ有効なままとなります。この例の会話には`system`プロンプトもツールもないため、リクエストではどちらも送信しません：

<CodeGroup>
  ```bash cURL
  # max_tokens は思考を含む呼び出し全体の上限となるため、数千トークンの余裕を持たせてください。
  curl https://api.anthropic.com/v1/messages \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: compact-2026-09-04" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-opus-5-5",
      "max_tokens": 4096,
      "messages": [
        {"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."}
      ],
      "compaction": {"type": "summarize"}
    }'
  ```

  ```bash CLI
  ant beta:messages create --beta compact-2026-09-04 <<'YAML'
  model: claude-opus-5-5
  # max_tokens は思考を含む呼び出し全体の上限となるため、数千トークンの余裕を持たせてください。
  max_tokens: 4096
  messages:
    - 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.
  compaction:
    type: summarize
  YAML
  ```

  ```python Python
  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 は思考を含む呼び出し全体の上限となるため、数千トークンの余裕を持たせてください。
      max_tokens=4096,
      betas=["compact-2026-09-04"],
      messages=history,
      compaction={"type": "summarize"},
  )
  print(f"Stop reason: {response.stop_reason}")
  ```

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

  const history: Anthropic.Beta.Messages.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." }
  ];

  const response = await client.beta.messages.create({
    model: "claude-opus-5-5",
    // max_tokens は思考を含む呼び出し全体の上限なので、数千トークンの余裕を持たせてください。
    max_tokens: 4096,
    betas: ["compact-2026-09-04"],
    messages: history,
    compaction: { type: "summarize" }
  });
  console.log(`Stop reason: ${response.stop_reason}`);
  ```

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

  AnthropicClient client = new();

  List<BetaMessageParam> history =
  [
      new()
      {
          Role = Role.User,
          Content = "I am building a recipe app. Help me name the main entities in the data model.",
      },
      new()
      {
          Role = 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.",
      },
      new() { Role = Role.User, Content = "Good. Now suggest field names for Recipe." },
  ];

  var response = await client.Beta.Messages.Create(new MessageCreateParams
  {
      Model = Model.ClaudeOpus5_5,
      // max_tokens は思考を含む呼び出し全体の上限となるため、数千トークン程度の余裕を持たせてください。
      MaxTokens = 4096,
      Betas = [AnthropicBeta.Compact2026_09_04],
      Messages = history,
      Compaction = new BetaCompactionConfig(), // type defaults to "summarize"
  });

  Console.WriteLine($"Stop reason: {response.StopReason?.Raw()}");
  ```

  ```go Go
  client := anthropic.NewClient()

  history := []anthropic.BetaMessageParam{
  	anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("I am building a recipe app. Help me name the main entities in the data model.")),
  	{
  		Role:    anthropic.BetaMessageParamRoleAssistant,
  		Content: []anthropic.BetaContentBlockParamUnion{anthropic.NewBetaTextBlock("Start with Recipe, Ingredient, and Step. Add a RecipeIngredient entry that holds the quantity and unit for each ingredient in a recipe.")},
  	},
  	anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("Good. Now suggest field names for Recipe.")),
  }

  response, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
  	Model: anthropic.ModelClaudeOpus5_5,
  	// max_tokens は思考を含む呼び出し全体の上限となるため、数千トークンの余裕を持たせてください。
  	MaxTokens: 4096,
  	Betas:     []anthropic.AnthropicBeta{anthropic.AnthropicBetaCompact2026_09_04},
  	Messages:  history,
  	Compaction: anthropic.BetaCompactionConfigUnionParam{
  		OfSummarize: &anthropic.BetaSummarizeCompactionParam{},
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }
  fmt.Println("Stop reason:", response.StopReason)
  ```

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

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

      var params = MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_5_5)
          // max_tokens は思考を含む呼び出し全体の上限となるため、数千トークンの余裕を持たせてください。
          .maxTokens(4096)
          .addBeta(AnthropicBeta.COMPACT_2026_09_04)
          .addUserMessage("I am building a recipe app. Help me name the main entities in the data model.")
          .addAssistantMessage("Start with Recipe, Ingredient, and Step. Add a RecipeIngredient entry that holds the quantity and unit for each ingredient in a recipe.")
          .addUserMessage("Good. Now suggest field names for Recipe.")
          .compaction(BetaCompactionConfig.builder().build()) // type defaults to "summarize"
          .build();

      var response = client.beta().messages().create(params);
      response.stopReason().ifPresent(reason -> IO.println("Stop reason: " + reason));
  }
  ```

  ```php PHP
  use Anthropic\Beta\AnthropicBeta;
  use Anthropic\Beta\Messages\BetaCompactionConfig;
  use Anthropic\Beta\Messages\BetaMessageParam;
  use Anthropic\Beta\Messages\BetaMessageParam\Role;

  $client = new Client();

  $history = [
      BetaMessageParam::with(
          role: Role::USER,
          content: 'I am building a recipe app. Help me name the main entities in the data model.',
      ),
      BetaMessageParam::with(
          role: 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.',
      ),
      BetaMessageParam::with(role: Role::USER, content: 'Good. Now suggest field names for Recipe.'),
  ];

  $response = $client->beta->messages->create(
      model: Model::CLAUDE_OPUS_5_5,
      // max_tokens は思考を含む呼び出し全体の上限となるため、数千トークンの余裕を持たせてください。
      maxTokens: 4096,
      betas: [AnthropicBeta::COMPACT_2026_09_04],
      messages: $history,
      compaction: BetaCompactionConfig::with(), // type defaults to 'summarize'
  );

  echo "Stop reason: {$response->stopReason}", PHP_EOL;
  ```

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

  history = [
    {
      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: Anthropic::Model::CLAUDE_OPUS_5_5,
    # max_tokens は思考を含む呼び出し全体の上限となるため、数千トークンの余裕を持たせてください。
    max_tokens: 4096,
    betas: [Anthropic::AnthropicBeta::COMPACT_2026_09_04],
    messages: history,
    compaction: { type: "summarize" }
  )
  puts "Stop reason: #{response.stop_reason}"
  ```
</CodeGroup>

```json 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 }]
  }
}
```

要約呼び出しでは、リクエストのモデル、`system`、`tools`、思考設定、`max_tokens`が使用されます。要約処理はツール定義を読み取りますが、ツールを実行することはなく、レスポンスに思考は含まれません。`max_tokens`は、モデルが要約を書く前に行う思考を含め、呼び出し全体の上限となるため、数千トークンの余裕を持たせてください。[コンパクションの使用量をカウントする](https://platform.claude.com/docs/ja/build-with-claude/compaction-on-demand#understanding-usage)では、この呼び出しがどのように課金されるかを説明しています。

最後の`assistant`ターンがまだ結果のないツール呼び出しで終わっている場合、APIはリクエストを拒否します。先にそのターンのツール結果を送信してください。また、`stop_sequences`、構造化出力の`output_config.format`、およびタイプが`any`または`tool`の`tool_choice`は含めないでください。これらは要約呼び出しでは何の効果もなく、APIはこれらを拒否します。会話は引き続きモデルの「context window」（コンテキストウィンドウ）に収まる必要があるため、超過した後ではなく、超過する前にコンパクションを行ってください。

「streaming」（ストリーミング）でレスポンスを受け取る場合、ブロックは完全な形で届きます。完全なブロックを含む`content_block_start`イベントが1つ届き、その後に`content_block_stop`が続きます。`content_block_delta`イベントはありません。`ping`イベントは、これらの前または間に届くことがあります。

## 要約から続ける

履歴内で、送信したメッセージを返されたアシスタントメッセージに置き換えます。`compaction`ブロックは、`signature`を含め、APIが返したとおりに保持してください。コンパクションリクエストを送信した後に行われたターンは、変更せずにブロックの後に続けます。これは[バックグラウンドでのコンパクション](https://platform.claude.com/docs/ja/build-with-claude/compaction-background)の基盤となる仕組みです。以降のすべてのリクエストで、ベータヘッダーとともにブロックを先頭に置いて送信してください：

```json
{
  "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." }
  ]
}
```

この例はリクエストのサンプルの続きであり、そのサンプルは`user`ターンで終わっていました。図は、要約の作成中にターンが行われない、より単純なケースを示しています。ここでの2番目の`assistant`メッセージは、要約された最後の`user`ターンへの返答です。これは要約の作成中に届いたため、要約対象のメッセージには含まれていませんでした。ブロックが引き続き先頭にあるため、ここでは`assistant`メッセージが2つ連続しても問題ありません。

APIはブロックがある位置に要約を配置し、それ以降のすべてのメッセージを変更せずにClaudeに渡します。次のルールに従ってください：

* ブロックを`messages`の先頭に置きます。単独の`assistant`メッセージとして置くか、最初のメッセージ（`user`メッセージでも`assistant`メッセージでも構いません）の最初のコンテンツブロックとして置きます。
* 要約されたメッセージを削除します。ブロックの前にいずれかが残っている場合、リクエストは400エラー（`compaction_block_misplaced`）を返します。
* 以降のすべてのリクエストで、リクエストごとに`compaction`ブロックを正確に1つ送信します。

<Warning>
  置き換えにおける2つの誤りはエラーになりません。要約されたメッセージがブロックの後に残っている場合、APIはそれらを再びClaudeに送信します。以降のリクエストでブロックを省略した場合、Claudeは要約を受け取りません。
</Warning>

「threshold compaction」（しきい値コンパクション）は逆の方法で動作します。そのブロックは要約対象のメッセージの後に続き、APIがそれらのメッセージを自動的に削除します。[コンパクションブロックを返す](https://platform.claude.com/docs/ja/build-with-claude/compaction-threshold#passing-compaction-blocks-back)を参照してください。

Pythonでは、このページのサンプルと同様に`client.beta.messages`を使用してください。`client.messages`を呼び出してブロックを自分でシリアライズする場合は、`to_dict()`または`model_dump(exclude_none=True)`を使用してください。通常の`model_dump()`はブロックに`citations: null`と`text: null`を追加するため、APIに拒否されます。

ブロックの後のターンを保持し、その思考ブロックを送り返す場合、その思考を有効に保つための条件については[コンパクションと思考の保持](https://platform.claude.com/docs/ja/build-with-claude/compaction-thinking-blocks)を参照してください。

### 再度コンパクションする

すでにブロックで始まっている会話をコンパクションするには、再度`compaction`を送信します。新しいブロックは、古い要約とその後のすべてを要約します。それ以降は、最新のブロックのみを送信してください。

## ループでコンパクションする

各ターンの後、ループは最後のレスポンスの入力トークンと出力トークンを加算します。次のリクエストでは返答も送信されるためです。その合計が上限を超え、かつまだ次のターンが残っている場合、ループは同じモデルと`system`プロンプトでコンパクションリクエストを送信し、`stop_reason`を確認し、履歴を返されたメッセージに置き換え、どのターンの前にコンパクションしたかを出力します。サンプルの上限である2,500トークンは、短い会話でもコンパクションが行われるように意図的に低く設定されています。実際の入力予算に近い値を設定してください。

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

  client = anthropic.Anthropic()

  # 実際の入力予算に近い値を設定してください。ここでは短い会話でもコンパクションが発生するよう低く設定しています。
  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})

      # 次のリクエストではこの応答も送信されるため、これもカウントしてください。
      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}")
  ```

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

  // 実際の入力予算に近い値を設定してください。ここでは短い会話でもコンパクションが発生するよう低く設定しています。
  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?"
  ];

  let history: Anthropic.Beta.Messages.BetaMessageParam[] = [];
  for (const [index, question] of questions.entries()) {
    const turn = index + 1;
    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 });

    // 次のリクエストではこの応答も送信されるため、カウントに含めてください。
    const conversationTokens = response.usage.input_tokens + response.usage.output_tokens;
    if (conversationTokens > compactAtTokens && turn < questions.length) {
      const summary = await client.beta.messages.create({
        model: "claude-opus-5-5",
        max_tokens: 4096,
        system: systemPrompt,
        betas: ["compact-2026-09-04"],
        messages: history,
        compaction: { type: "summarize" }
      });
      if (summary.stop_reason === "compaction") {
        history = [{ role: "assistant", content: summary.content }];
        console.log(`Compacted before turn ${turn + 1}`);
      }
    }
  }
  ```

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

  AnthropicClient client = new();

  // 実際の入力予算に近い値を設定してください。ここでは短い会話でもコンパクションが発生するよう低く設定しています。
  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?",
  ];

  List<BetaMessageParam> history = [];
  foreach (var (index, question) in questions.Index())
  {
      var turn = index + 1;
      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(),
      });

      // 次のリクエストではこの応答も送信されるため、これもカウントに含めます。
      var conversationTokens = response.Usage.InputTokens + response.Usage.OutputTokens;
      if (conversationTokens > CompactAtTokens && turn < questions.Length)
      {
          var summary = await 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"
          });
          if (summary.StopReason == BetaStopReason.Compaction)
          {
              history =
              [
                  new()
                  {
                      Role = Role.Assistant,
                      Content = summary.Content.Select(block => new BetaContentBlockParam(block.Json)).ToList(),
                  },
              ];
              Console.WriteLine($"Compacted before turn {turn + 1}");
          }
      }
  }
  ```

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

  // 実際の入力予算に近い値を設定してください。ここでは短い会話でもコンパクションが発生するよう低く設定しています。
  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
  for i, question := range questions {
  	turn := i + 1
  	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())

  	// 次のリクエストではこの応答も送信されるため、カウントに含めてください。
  	conversationTokens := response.Usage.InputTokens + response.Usage.OutputTokens
  	if conversationTokens > compactAtTokens && turn < len(questions) {
  		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:  history,
  			Compaction: anthropic.BetaCompactionConfigUnionParam{
  				OfSummarize: &anthropic.BetaSummarizeCompactionParam{},
  			},
  		})
  		if err != nil {
  			log.Fatal(err)
  		}
  		if summary.StopReason == anthropic.BetaStopReasonCompaction {
  			history = []anthropic.BetaMessageParam{summary.ToParam()}
  			fmt.Printf("Compacted before turn %d\n", turn+1)
  		}
  	}
  }
  ```

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

  // 実際の入力予算に近い値を設定してください。ここでは短い会話でもコンパクションが発生するよう低く設定しています。
  static final long COMPACT_AT_TOKENS = 2500;
  static final String SYSTEM = "You help design a recipe app's data model. Keep answers short.";

  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>();
      for (int turn = 1; turn <= questions.size(); turn++) {
          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());

          // 次のリクエストではこの応答も送信されるため、カウントに含めます。
          long conversationTokens = response.usage().inputTokens() + response.usage().outputTokens();
          if (conversationTokens > COMPACT_AT_TOKENS && turn < questions.size()) {
              var summaryParams = MessageCreateParams.builder()
                  .model(Model.CLAUDE_OPUS_5_5)
                  .maxTokens(4096)
                  .system(SYSTEM)
                  .addBeta(AnthropicBeta.COMPACT_2026_09_04)
                  .messages(history)
                  .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)) {
                  history.clear();
                  history.add(summary.toParam());
                  IO.println("Compacted before turn " + (turn + 1));
              }
          }
      }
  }
  ```

  ```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;

  $client = new Client();

  // 実際の入力予算に近い値を設定してください。ここでは短い会話でもコンパクションされるよう低くしています。
  const COMPACT_AT_TOKENS = 2500;
  const 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 = [];
  foreach ($questions as $index => $question) {
      $turn = $index + 1;
      $history[] = BetaMessageParam::with(role: Role::USER, content: $question);
      $response = $client->beta->messages->create(
          model: Model::CLAUDE_OPUS_5_5,
          maxTokens: 8192,
          system: SYSTEM,
          betas: [AnthropicBeta::COMPACT_2026_09_04],
          messages: $history,
      );
      $history[] = BetaMessageParam::with(role: Role::ASSISTANT, content: $response->content);

      // 次のリクエストではこの応答も送信されるため、カウントに含めます。
      $conversationTokens = $response->usage->inputTokens + $response->usage->outputTokens;
      if ($conversationTokens > COMPACT_AT_TOKENS && $turn < count($questions)) {
          $summary = $client->beta->messages->create(
              model: Model::CLAUDE_OPUS_5_5,
              maxTokens: 4096,
              system: SYSTEM,
              betas: [AnthropicBeta::COMPACT_2026_09_04],
              messages: $history,
              compaction: new BetaCompactionConfig(), // type defaults to 'summarize'
          );
          if ($summary->stopReason === BetaStopReason::COMPACTION->value) {
              $history = [BetaMessageParam::with(role: Role::ASSISTANT, content: $summary->content)];
              printf("Compacted before turn %d\n", $turn + 1);
          }
      }
  }
  ```

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

  # 実際の入力予算に近い値を設定してください。ここでは短い会話でもコンパクションされるよう低くしています。
  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 = []
  questions.each.with_index(1) do |question, turn|
    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 }

    # 次のリクエストではこの応答も送信されるため、カウントに含めてください。
    conversation_tokens = response.usage.input_tokens + response.usage.output_tokens
    if conversation_tokens > COMPACT_AT_TOKENS && turn < questions.length
      summary = client.beta.messages.create(
        model: Anthropic::Model::CLAUDE_OPUS_5_5,
        max_tokens: 4096,
        system_: SYSTEM,
        betas: [Anthropic::AnthropicBeta::COMPACT_2026_09_04],
        messages: history,
        compaction: { type: "summarize" }
      )
      if summary.stop_reason == :compaction
        history = [{ role: "assistant", content: summary.content }]
        puts "Compacted before turn #{turn + 1}"
      end
    end
  end
  ```
</CodeGroup>

`stop_reason`の確認は、コードがブロックを探す前に行われます。その理由は[要約が返されない場合やエラーを処理する](https://platform.claude.com/docs/ja/build-with-claude/compaction-on-demand#when-no-summary-comes-back)で説明しています。履歴は追加されるのではなく置き換えられます。返されたメッセージは、[要約から続ける](https://platform.claude.com/docs/ja/build-with-claude/compaction-on-demand#continue-from-the-summary)のルールに従い、リクエストに含まれていたすべてのメッセージを置き換えます。要約が返されない場合、ループは履歴を保持し、次のターンの後に再度リクエストします。

Python、TypeScript、C#、Go、Java、PHP、RubyのSDKの[「tool runner」（ツールランナー）](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/tool-runner)は、コンパクションリクエストを代わりに送信できます。コンパクションすると決めたら、ランナーで`compact_before_next_turn()` (typescript, java, php: `compactBeforeNextTurn()`; csharp, go: `CompactBeforeNextTurn()`)を呼び出します。現在のターンとそのツール呼び出しが完了すると、ランナーはコンパクションリクエストを送信し、履歴を返されたメッセージに置き換えます。ランナーはベータを追加しないため、`compact-2026-09-04`ベータを指定してランナーを作成してください。

ランナーは自身のパラメータからコンパクションリクエストを構築し、`context_management`を除外します。また、APIがコンパクションリクエストで拒否する`stop_sequences`、タイプが`any`または`tool`の`tool_choice`、構造化出力の`output_config.format`も除外します。その理由は[要約をリクエストする](https://platform.claude.com/docs/ja/build-with-claude/compaction-on-demand#request-a-summary)で説明しています。ランナーは以降のリクエストでこれらを再び送信します。Python 1.8.0、TypeScript 0.128.0、C# 12.50.0、Go 1.75.0、Java 2.65.0より前のSDKバージョンでは、コンパクションリクエストでもこれらが送信されます。これらのバージョンでは、これらのパラメータのいずれかを設定したランナーは400エラーを受け取ります。ランナーは[「task budget」（タスク予算）](https://platform.claude.com/docs/ja/build-with-claude/task-budgets)を変更せずに送信します。`output_config.task_budget`で`remaining`が設定されている場合、コンパクションリクエストは400エラーを返すため、[制限と他の機能との相互作用](https://platform.claude.com/docs/ja/build-with-claude/compaction-on-demand#how-it-fits-with-the-rest-of-the-api)に記載されているとおり、`remaining`は設定しないでください。ランナーは、その`context_management`にコンパクション編集が含まれている間はコンパクションを拒否するため、1つのランナーでは1種類のコンパクションを使用してください。

### コンパクションのタイミング

完了したターンの後であればいつでもコンパクションリクエストを送信できるため、タイミングはコードで決定します。

次のリクエストのサイズを見積もるには、ループと同様に、最後のレスポンスの`usage`から`input_tokens`と`output_tokens`を加算します。[「prompt caching」（プロンプトキャッシング）](https://platform.claude.com/docs/ja/build-with-claude/prompt-caching#tracking-cache-performance)を使用している場合、`input_tokens`は最後のキャッシュブレークポイント以降のトークンのみをカウントするため、`cache_read_input_tokens`と`cache_creation_input_tokens`も加算してください。同じメッセージを[「token counting」（トークンカウント）](https://platform.claude.com/docs/ja/build-with-claude/token-counting)エンドポイントに送信することもできます。

その数値を、モデルの[コンテキストウィンドウ](https://platform.claude.com/docs/ja/build-with-claude/context-windows)より小さい、自分で選んだ上限と比較します。

## 独自の要約プロンプトを作成する

`instructions`を指定しない場合、APIはデフォルトの要約プロンプトを使用します。空白でない`instructions`文字列（最大16,384文字）を指定すると、そのプロンプトが完全に置き換えられます。例：

```json
{
  "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."
  }
}
```

`instructions`の有無にかかわらず、要約処理は以前の思考を含む会話全体を読み取ります。`instructions`では、要約に保持すべき内容を指定し、ツールを呼び出さないようモデルに指示してください。要約呼び出しは、他のリクエストと同じセーフガードの下で実行されます。

## 要約が返されない場合やエラーを処理する

要約が生成されるのは、要約呼び出しがテキストを含み、ツール呼び出しなしで正常に終了した場合のみです。それ以外の場合でもレスポンスは空の`content`を持つ200となるため、ブロックを探す前に`stop_reason`を確認してください。この呼び出しは引き続き課金され、`usage.iterations`で報告されます。呼び出しを実行できなかった場合、使用量はゼロになります。`stop_reason`は、要約呼び出しが終了した際のものです。いずれの場合も、要約なしで続行し、後でコンパクションを行うことができます。

| `stop_reason`                     | 原因                        | 対処方法                                          |
| --------------------------------- | ------------------------- | --------------------------------------------- |
| `"max_tokens"`                    | 要約が途中で切れました。              | より大きな`max_tokens`で再送信します。                     |
| `"model_context_window_exceeded"` | 要約プロンプトのための余地がありませんでした。   | より短い`instructions`またはより少ないメッセージで再送信します。       |
| `"tool_use"`                      | モデルが要約を書く代わりにツールを呼び出しました。 | ツールを呼び出さないようモデルに指示する`instructions`を付けて再送信します。 |
| `"refusal"`                       | リクエストが拒否されました。            | 要約なしで続行します。                                   |
| `"end_turn"`                      | 呼び出しがテキストを返しませんでした。       | 要約なしで続行します。                                   |

要約呼び出しには、他のリクエストと同じセーフガードが適用されます。`"refusal"`の後は、[`stop_details`](https://platform.claude.com/docs/ja/build-with-claude/handling-stop-reasons#refusal)によってその背後にあるポリシーカテゴリが特定されます。

### エラー

コンパクションリクエスト、またはブロックを含むリクエストは、完全に失敗することもあります。ほとんどの400エラーには、何を削除または再送信すべきかを示すメッセージが含まれます。一部のエラーには、`compaction_`で始まる`error.details.error_code`も含まれます。`compaction`と組み合わせられないフィールドなどのパラメータエラーには、メッセージのみが含まれます。

| エラー                                                                                                  | 原因                                                    | 対処方法                                                                                                                                                |
| ---------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| 529 `overloaded_error`、`error.details.error_code` `compaction_unavailable`                           | ブロックの生成中、または送り返されたブロックの読み取り中に一時的なサーバーの問題が発生しました。      | リクエストを再試行します。                                                                                                                                       |
| 400 `compaction_block_misplaced`                                                                     | 要約されたメッセージがブロックの前に残っています。                             | それらを削除し、ブロックが`messages`の先頭に来るようにします。                                                                                                                |
| 400 `compaction_signature_invalid`または`compaction_content_mismatch`                                   | APIが返した後に、ブロックの`signature`または`content`が変更されました。       | `signature`を含め、返されたとおりにブロックを送信します。                                                                                                                  |
| 400                                                                                                  | リクエストに複数の`compaction`ブロックが含まれています。                    | 最新のブロックを正確に1つ送信します。                                                                                                                                 |
| 400                                                                                                  | 最後の`assistant`ターンが、まだ結果のないツール呼び出しで終わっています。            | そのターンのツール結果を送信してから、コンパクションを行います。                                                                                                                    |
| 400 `compaction_nothing_to_summarize`                                                                | `messages`に`user`または`assistant`のコンテンツがありません（空のリストなど）。 | 少なくとも1つの`user`または`assistant`メッセージを送信します。                                                                                                            |
| コンパクションリクエストでの400で、`compaction`パラメータが`requires anthropic-beta: compact-2026-09-04`であることを示すメッセージが含まれる | コンパクションリクエストでベータヘッダーが省略されました。                         | ベータヘッダーを追加します。[要約をリクエストする](https://platform.claude.com/docs/ja/build-with-claude/compaction-on-demand#request-a-summary)を参照してください。                  |
| ブロックを含む以降のリクエストでの400：`compaction`が想定されるコンテンツブロックタイプのいずれでもないことを示す検証エラー。メッセージにはヘッダーについての言及はありません       | そのリクエストでベータヘッダーが省略されました。                              | ブロックを含むすべてのリクエストにベータヘッダーを追加します。[要約をリクエストする](https://platform.claude.com/docs/ja/build-with-claude/compaction-on-demand#request-a-summary)を参照してください。 |
| `messages.0.content.0.compaction.citations: Extra inputs are not permitted`などの400検証エラー               | `citations: null`など、APIが返さなかったフィールドを含むブロックが送り返されました。  | 返されたとおりにブロックを送信します。[要約から続ける](https://platform.claude.com/docs/ja/build-with-claude/compaction-on-demand#continue-from-the-summary)を参照してください。        |

## コンパクションの使用量をカウントする

要約呼び出しは他のリクエストと同様に課金され、「rate limit」（レート制限）の対象となり、`usage.iterations`では`compaction`エントリとして報告されます。返答が生成されないため、トップレベルの`input_tokens`と`output_tokens`はゼロです。会話で消費された量をカウントするには、トップレベルのフィールドではなく、`usage.iterations`全体を合計してください。以降のリクエストでブロックを送り返しても、コンパクションのコストは追加されません。

これで、会話をコンパクションし、要約が返されない場合を処理する、動作するループができました。2つのページでその動作を変更でき、両者を組み合わせることもできます。[直近のターンを保持するコンパクション](https://platform.claude.com/docs/ja/build-with-claude/compaction-keep-recent-turns)は最後のターンを一字一句そのまま保持し、[バックグラウンドでのコンパクション](https://platform.claude.com/docs/ja/build-with-claude/compaction-background)は要約の作成中も会話を続けられるようにします。思考ブロックを送り返し、いずれかを行う場合は、[コンパクションと思考の保持](https://platform.claude.com/docs/ja/build-with-claude/compaction-thinking-blocks)が適用されます。

## 制限と他の機能との相互作用

* **しきい値コンパクションと「context editing」（コンテキスト編集）。** 同じリクエストで`compaction`と`context_management`を送信することはできません。しきい値コンパクション（`compact_20260112`）は、署名付きブロックを含むリクエストでは実行できません。
* **プロンプトキャッシング。** ブロックの`cache_control`は、要約の後にブレークポイントを配置します。
* **会話途中のシステムメッセージとツールの変更。** 要約範囲内の`role: "system"`メッセージも要約されるため、ブロックがそれらを置き換えると、そのテキストによる指示は適用されなくなります。それらが設定した[メッセージごとのeffort](https://platform.claude.com/docs/ja/build-with-claude/effort#change-effort-mid-conversation-beta)レベルも引き継がれません。後のメッセージがレベルを設定するまで、ターンはリクエストのトップレベルの`output_config.effort`で実行され、設定していない場合はモデルのデフォルトで実行されます。指示やeffortレベルが引き続き重要な場合は、`role: "system"`メッセージで再度記述してください。そのメッセージは次の新しい`user`ターンの直後に送信し、それ以降は履歴に残しておいてください。[ツールの変更](https://platform.claude.com/docs/ja/build-with-claude/mid-conversation-system-messages#mid-conversation-tool-changes)について、またブロックの後のターンを保持する場合にそのメッセージをどこに置くかについては、[システムプロンプトまたはツールを変更する](https://platform.claude.com/docs/ja/build-with-claude/compaction-thinking-blocks#change-the-system-prompt-or-tools)を参照してください。
* **タスク予算。** [「task budget」（タスク予算）](https://platform.claude.com/docs/ja/build-with-claude/task-budgets)の`remaining`値（`output_config.task_budget.remaining`）を、`compaction`とともに、またはブロックを含むリクエストで送信しないでください。送信すると400エラーが返されます。
* **トークンカウント。** [トークンカウント](https://platform.claude.com/docs/ja/build-with-claude/token-counting)エンドポイントは`compaction`パラメータを無視します。
* **要約で引き継げないコンテンツ。** 要約されたメッセージ内の画像、ドキュメント、`container_upload`ブロック、取得したURLは、ブロックがそれらを置き換えると失われます。後のターンで引き続き必要なものは、再度記述するか再アップロードしてください。
