履歴を要約するタイミングをアプリで決める

長時間稼働するエージェントで自前の履歴要約を API 側へ移すなら、要約の生成だけでなく、返却されなかったときの履歴保持と、会話を継続するための差し替え手順まで確認してください。

Claude API の Messages API には、2026 年 9 月 14 日にオンデマンド圧縮 (on-demand compaction) がベータとして追加されました。会話とは別のリクエストで要約を取り、署名付きの compaction ブロックとして再利用する機能です。追加日は API リリースノートで確認できます。

本記事の対象は Messages API の実装です。Claude Code の /compact の操作は扱いません。コードとパラメータ名は 2026 年 9 月 19 日の公式 Compaction ドキュメントと照合しました。実 API の呼び出しによる検証や、削減率・レイテンシ・費用の実測は行っていません。

FIXITFIXIT

要約を API に任せたら、履歴の管理も全部なくせるの?

KanameKaname

要約の生成は任せられます。履歴を差し替える範囲と、失敗時に元の履歴を残す手順は必要です。

閾値圧縮との違い

既存の閾値圧縮は、通常のリクエスト内で入力トークン数が閾値に達すると要約を生成します。オンデマンド圧縮では、アプリ側が要約専用のリクエストを送るタイミングを選べます。

比較項目閾値圧縮オンデマンド圧縮
ベータヘッダーcompact-2026-01-12compact-2026-09-04
指定場所context_management.editscompact_20260112トップレベルの compaction
実行の契機入力トークン数の閾値アプリからの明示的な要求
要約後の応答通常は返信を続ける要約だけを返す
履歴との関係要約対象の後ろにブロックを追加できる要約対象を削除し、先頭のブロックで置き換える

会話を止めずに要約したい場合は、オンデマンドのリクエストをバックグラウンドで実行できます。ただし、非同期処理の開始と履歴の差し替えを担当するのはアプリです。

最小構成で要約を取得する

必要なのは compact-2026-09-04 ヘッダーと compaction: {"type": "summarize"} です。以下は公式のリクエスト形式に合わせた cURL 例で、ANTHROPIC_API_KEY を環境変数に設定して使います。

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",
    "max_tokens": 4096,
    "messages": [
      {"role": "user", "content": "レシピアプリのデータモデルを考えてください。"},
      {"role": "assistant", "content": "Recipe、Ingredient、Step を用意します。"},
      {"role": "user", "content": "Recipe のフィールド名を提案してください。"}
    ],
    "compaction": {"type": "summarize"}
  }'

Python SDK では client.beta.messages.create() に渡します。以下も同じ会話を要約する例です。

import anthropic
from anthropic.types.beta import BetaMessageParam
 
client = anthropic.Anthropic()
history: list[BetaMessageParam] = [
    {"role": "user", "content": "レシピアプリのデータモデルを考えてください。"},
    {"role": "assistant", "content": "Recipe、Ingredient、Step を用意します。"},
    {"role": "user", "content": "Recipe のフィールド名を提案してください。"},
]
 
response = client.beta.messages.create(
    model="claude-opus-5",
    max_tokens=4096,
    betas=["compact-2026-09-04"],
    messages=history,
    compaction={"type": "summarize"},
)
print(response.stop_reason)
print(response.content)

この例の会話には systemtools がありません。既存の会話で使っている場合は、圧縮時にも同じ値を送ってください。要約処理にはリクエストのモデル・systemtools・thinking 設定・max_tokens が使われます。

max_tokens は要約本文だけでなく、要約前の thinking も含めた上限です。公式は数千トークンの余裕を持たせるよう案内しています。ツール定義は読まれますが、要約処理でツールは実行されず、thinking ブロックも応答に含まれません。

返却値は response.content に入る

成功時の stop_reason"compaction" で、response.content には単一の compaction ブロックが入ります。ブロックが持つのは要約本文の contentsignature です。ユーザーへの返信本文はありません。

次のリクエストには、受け取ったブロックを署名ごと変更せずに渡します。要約の文字列だけを抜き出したり、署名を自作したりせず、response.content を使ってください。

圧縮時に送れない指定

通常の呼び出し設定をそのまま流用すると、検証エラーになる場合があります。

指定・状態対応
context_managementcompaction と同時に送らない
stop_sequences要約リクエストから外す
output_config.format構造化出力の指定を外す
tool_choiceany / toolツール実行を強制する指定を外す
output_config.task_budget.remaining圧縮時と署名付きブロックを送るリクエストの両方で外す
最後の assistant ターンに未解決のツール呼び出しがあるツール結果を送ってから圧縮する

圧縮リクエスト自体もモデルのコンテキストウィンドウ内に収まる必要があります。上限を超えてから圧縮する設計にはできません。

要約から会話を続けるときの配置

署名付きブロックの扱いは、閾値圧縮のブロックと異なります。公式の Continue from the summary に沿って、配置と送信を確認してください。

  • ブロックは messages の先頭に置きます。独立した assistant メッセージにするか、最初の user または assistant メッセージの先頭コンテンツブロックにします。
  • 要約済みのメッセージは削除します。ブロックの前に残すと 400 compaction_block_misplaced になり、後ろに残すとモデルに重複して渡されます。
  • 1 リクエストに含める compaction ブロックは 1 個です。
  • 後続のリクエストにもブロックとベータヘッダーを毎回送ります。ブロックを省略したリクエストでは、モデルに要約が渡りません。

要約後に履歴が増え、再び圧縮するときは、現在のブロックを含む履歴を compaction 付きで送ります。新しい要約には以前の要約と後続の会話が含まれるため、その後は最新のブロックだけを使ってください。

直近ターンは圧縮リクエストから除外する

直近の会話を原文のまま残すには、残したいターンを圧縮リクエストに含めません。API は送られたメッセージをすべて要約するので、古い範囲だけを送信し、返却されたブロックの後ろに保持したターンを並べます。

たとえば、直近のツール結果を引き続き参照したい場合は、その結果を含む会話の範囲を保持対象にします。保持するターン数を API の専用パラメータに指定する方式ではありません。

thinking も保持する場合は、単に配列の末尾を切り出すだけでは不十分です。後述するターンの境界と、systemtools の一致条件も確認してください。

バックグラウンドでは送った範囲だけ差し替える

要約を待つ間も通常の会話を続ける場合、要約リクエストに送ったメッセージ数を sent_count として控えます。会話の履歴には新しいターンを末尾へ追加し、要約が届いたら先頭の sent_count 件だけを置き換える手順です。

以下は公式が示す差し替え部分です。単独で実行する非同期プログラムではなく、既存の会話ループに組み込む処理で、response はバックグラウンドの要約リクエストの結果を指します。

# sent_count は圧縮リクエストに送ったメッセージ数
# history は送信時の履歴に後続ターンを追加したもの
if response.stop_reason == "compaction":
    compaction_message = {"role": "assistant", "content": response.content}
    history = [compaction_message] + history[sent_count:]
# 要約が返らなかった場合は履歴を維持する

送信から差し替えまでの間に、既存の履歴を編集してはいけません。要約が届いた後、次の通常リクエストを送る前に、履歴の先頭の sent_count 件を要約ブロックに差し替えます。要約中に追加された会話まで削除すると、モデルに未要約の情報が渡らなくなります。

この手順から、アプリ側では「どの履歴のどの範囲を送ったか」を固定して管理します。複数の処理が同じ履歴を編集する構成なら、差し替えを担当する処理を決めてから組み込むのがよいでしょう。

保持したターンの thinking を有効に保つ条件

preserved thinking に対応するモデルでは、要約後に残したターンの thinking を引き継げる場合があります。公式が挙げている条件は、保持したターンが要約範囲の直後に続いていたことと、圧縮時から system および defer_loading: true ではない tools が変わっていないことです。

さらに、保持する最初のメッセージが、要約範囲の最後と同じ role、または role: "system" だと、API が直前のメッセージに結合する可能性があり、境界の条件を満たしません。公式は、すでに送信したリクエストの messages をそのまま圧縮対象にする方法を案内しています。

systemtools を変更する必要があるなら、会話全体を先に圧縮して保持するターンをなくし、次のリクエストで変更できます。別モデルなどへ変更してもブロック自体は受け付けられますが、保持したターンの thinking は無効になる場合があります。前提となる仕組みは Claude Fable 5.1 の preserved thinking 解説にまとめています。

使用量は usage.iterations を合算する

オンデマンド圧縮のトップレベルの usage.input_tokensusage.output_tokens は 0 です。返信を生成していないことを示す値で、無料という意味ではありません。

要約処理の使用量は usage.iterationstype: "compaction" のエントリに記録されます。圧縮を含むリクエストの使用量を集計するときは、iterations の各エントリの入力・出力トークン数をそれぞれ合算してください。トップレベルの値をさらに足すと、通常の返信分を二重計上する可能性があります。

既存のブロックを再送するだけなら、新たな圧縮処理の費用は発生しません。ブロックを含むリクエストでも、通常の入力・出力トークンは従来どおり課金されます。モデルやキャッシュも含む費用設計は LLM コスト最適化の解説を参照してください。

200 でも要約が返らない場合がある

要約処理がテキストを正常に生成し、ツールを呼ばずに終わった場合だけブロックが返ります。それ以外は HTTP 200 でも content が空です。公式の When no summary comes back では、次の終了理由が説明されています。

stop_reason状態対応
max_tokens要約が途中で打ち切られたmax_tokens を増やして再送する
model_context_window_exceeded要約用プロンプトを追加する余裕がないinstructions を短くするか、送るメッセージを減らす
refusal要求が拒否されたstop_details のポリシーカテゴリを確認する
tool_use要約の代わりにツール呼び出しが生成されたツールを呼ばず要約を書くよう instructions で指定する
end_turnテキストが返らなかった要約なしで継続するなど、履歴を保持する分岐へ進む

要約が返らない呼び出しも課金・使用量記録の対象です。ただし、内部呼び出し自体を実行できなかった場合の使用量は 0 になります。HTTP ステータスだけで履歴を削除せず、stop_reason == "compaction" を確認してから差し替えてください。

400 と 529 は対応を分ける

一時的なサーバー側の問題でブロックの生成や読み取りに失敗した場合、529 overloaded_error が返ります。error.details.error_codecompaction_unavailable なら再試行可能です。

一方、配置違反・ブロックの変更・重複などは 400 の対象になります。compaction_ で始まるコードが付く場合がありますが、パラメータの組み合わせ違反にはメッセージしか付かない場合もあります。

ベータヘッダーを忘れたときは、compaction: Extra inputs are not permitted のような一般的な検証エラーになります。エラー文にヘッダー名が出なくても、要約取得時と後続リクエストの両方でヘッダーを送っているか確認してください。

要約に残せる情報と、再送が必要な情報

compaction.instructions は省略可能で、空白だけではない文字列を最大 16,384 文字まで指定できます。既定の要約プロンプトを補足する設定ではなく、全文を置き換える指定です。後続の作業に必要な決定事項や未完了の依頼を残すこと、ツールを呼び出さないことを指示します。

オンデマンド圧縮では、カスタム instructions の有無にかかわらず、要約処理が圧縮リクエストに含めた会話全体を、過去の thinking も含めて読みます。ただし、要約範囲内の画像・ドキュメント・container_upload・取得済み URL は、ブロックで置き換えた後に引き継がれません。後続ターンでも必要な情報は再提示・再アップロードしてください。

会話途中の role: "system" に書かれた指示やツール変更も要約対象で、宣言した設定の効力は置き換え後に失われます。必要な設定は、保持したターンの後に送る次の新しい user ターンの直後で、role: "system" として再宣言し、履歴に残します。要約ブロックと保持したターンの間には挟まないでください。ここに設定変更を挟むと、保持した thinking が無効になるためです。

なお、ストリーミング実装にも違いがあります。オンデマンドのブロックは content_block_start に全体が入り、content_block_stop が続きます。content_block_delta は来ないので、閾値圧縮の delta を待つ実装は流用できません。

SDK の対応版と tool runner の圧縮予約

リクエストの型対応と、tool runner による履歴管理の対応は別のリリースです。

SDKパラメータ・署名付きブロックへの対応tool runner の圧縮予約
Python1.6.01.7.0compact_before_next_turn()
TypeScript0.126.00.127.0compactBeforeNextTurn()

Python の 0.x 系から更新する場合は、Anthropic Python SDK v1 移行ガイドで互換性に関わる変更を先に確認してください。本記事で扱うのは、更新後にオンデマンド圧縮を組み込む手順です。

Python SDK の tools.md では、既存の runner に対して次のように圧縮を予約します。

runner.compact_before_next_turn()

tools.md によると、呼び出した時点では圧縮は実行されません。現在のターンとツール呼び出しが完了してから、runner が要約を要求し、履歴を差し替えます。pause_turn で中断されたターンは再開・完了が先です。反復開始前に呼んだ場合は、最初のリクエストが圧縮になります。

runner の生成時には betas=["compact-2026-09-04"] を明示します。SDK は自動で付けません。context_managementcompact_* の edit がある場合は例外になるため、閾値圧縮の設定を残したまま予約しないでください。

要約が返らなければ、runner は警告を記録して履歴を維持します。また、未実行のツール呼び出しを残してターンが打ち切られた場合、max_iterations で終了した場合、ループを break した場合などは、予約した圧縮が実行されない点も運用上の確認事項です。runner 自体への compaction パラメータの常設はできません。

対応モデルと提供範囲

2026 年 9 月 19 日時点の公式一覧には、次のモデルが掲載されています。

系列モデル ID
Fableclaude-fable-5-1claude-fable-5
Mythosclaude-mythos-5-1claude-mythos-5claude-mythos-preview
Opusclaude-opus-5claude-opus-4-8claude-opus-4-7claude-opus-4-6
Sonnetclaude-sonnet-5claude-sonnet-4-6

利用先は Claude API です。Amazon Bedrock と Google Cloud ではオンデマンド圧縮を利用できません。対応状況をプログラムで確認する場合は、同じベータヘッダーを付けて Models API を呼び、各モデルの capabilities.compaction を読みます。

自前の要約を置き換える前に決めること

通常のリクエスト内で API に圧縮を任せたいなら、閾値圧縮が候補です。タイミングを指定したい、会話を継続しながら要約したい、直近の会話と thinking を保持したい場合は、オンデマンド圧縮を検討できます。

compactioncontext_management は同一リクエストで併用できません。さらに、署名付きブロックを送るリクエストで閾値圧縮を実行することもできないため、取得時だけ設定を外せばよいわけではありません。

置き換えの判断では、要約処理そのものに加えて、失敗時の履歴保持、送信範囲の管理、添付情報の再提示、usage.iterations の集計を実装できるか確認してください。自前の要約生成を減らせても、アプリが責任を持つ履歴管理は残ります。

FIXITFIXIT

じゃあ、導入前には何を確かめればいいの?

KanameKaname

要約が返らなくても履歴を残せるか、差し替え後に必要な情報を参照できるかを確認するとよいです。

AI 駆動開発のクリエイティブスタジオ FIXIT では、AI エージェント開発でコンテキスト設計と評価ハーネス、段階的な運用導入を支援しています。履歴の圧縮後も必要な判断・ツール実行を続けられるか、業務に合わせた評価からご相談いただけます。