原典: Compaction on demand / 日本語版
一行要約
アプリが決めたタイミングで compaction パラメータ付きのリクエストを1本送ると、返答の代わりに署名つきの要約ブロックが1個返り、以降はそれを messages の先頭に置いて要約した範囲の代わりにする方式で、概要ページ(compaction)が「使えるならこちら」と推す側。
要点
プラットフォーム: Claude API / Claude Platform on AWS / Google Cloud / Microsoft Foundry(いずれも beta)。Amazon Bedrock では使えない(閾値方式 compaction-threshold は使える)。以前の取得では「Claude API のみ」だった。
A compaction request is separate from your conversation turns. You send the conversation as it stands with the
compactionparameter, and the response contains a singlecompactionblock. The block holds the summary as text you can read, and a signature. Send it in future requests exactly as it came.compaction のリクエストは会話のターンとは別物である。いまの会話をそのまま
compactionパラメータ付きで送ると、応答にはcompactionブロックが1個だけ入っている。ブロックは読めるテキストとしての要約と、署名を持つ。以降のリクエストでは、返ってきたとおりに送れ。
要約を頼む
- beta header
compact-2026-09-04は、要約を頼むリクエストと、ブロックを載せる以降のすべてのリクエストに付ける "compaction": {"type": "summarize"}を送ると、送ったメッセージを全部1回要約し、返答は生成せず、ブロックだけをstop_reason: "compaction"で返す- 要約はリクエストのモデル・
system・tools・thinking 設定・max_tokensで走る。 要約器はツール定義を読むがツールは実行せず、応答に thinking は付かない。max_tokensは要約前の thinking も含めた全体の上限なので、数千は確保する systemとtoolsは会話の他の部分と同じものを送る。 preserved thinking のあるモデルでブロックの後ろにターンを残すなら、残したターンの thinking が有効なのはsystemとtoolsが一致するときだけ- 送れないもの: 最後の
assistantターンが結果待ちのツール呼び出しで終わっている(先にツール結果を送る)/stop_sequences/structured outputs のoutput_config.format/tool_choiceのanyとtool/context_management(同じリクエストに併用できない) - 会話はまだモデルの context window に収まっている必要がある。溢れる前に compact する
- ストリーミングではブロックが丸ごと届く(
content_block_startが完全なブロックを持ち、content_block_deltaは来ない)
どのモデルが対応しているかは、Models API を beta header 付きで呼んで各モデルの capabilities.compaction を読む。
要約から続ける(差し替えの規則)
- ブロックは
messagesの先頭に置く(単独のassistantメッセージでも、先頭メッセージの最初のコンテンツブロックでもよい。先頭メッセージはuserでもassistantでもよい) - 要約したメッセージは消す。 ブロックより前に残ると 400(
compaction_block_misplaced) - 1リクエストに
compactionブロックはちょうど1個を、以降の毎リクエストに載せる - ブロックは
signatureごと返ってきたまま送る - 要約を頼んだ後に進んだターンは、そのままブロックの後ろに続けてよい(これが「裏で要約する」子ページの土台)
Two mistakes in the swap raise no error. If summarized messages remain after the block, the API sends them to Claude again. If a later request leaves the block out, Claude gets no summary.
差し替えの誤りのうち2つはエラーにならない。要約したメッセージがブロックの後ろに残っていれば、API はそれを Claude にもう一度送る。以降のリクエストでブロックを落とせば、Claude は要約を受け取らない。
閾値方式とは向きが逆。閾値方式のブロックは要約した範囲の「後ろ」に来て、API が前を捨てる。
Python で client.messages を使って自分でシリアライズするなら、to_dict() か model_dump(exclude_none=True) を使う(素の model_dump() は citations: null と text: null を足し、API に拒否される)。
もう一度 compact する: すでにブロックで始まる会話に compaction をもう一度送ると、新しいブロックが古い要約とその後ろ全部を要約する。以降は新しいほうだけを送る。
いつ compact するか
完了したターンの後ならいつでも送れる。次のリクエストの大きさは、直前の応答の usage の input_tokens + output_tokens で見積もる(次のリクエストはその返答も送るから)。prompt caching を使っているなら input_tokens は最後のブレークポイントより後ろしか数えないので、cache_read_input_tokens と cache_creation_input_tokens も足す。その値を、モデルの context window より下に自分で決めた上限と比べる。
SDK の tool runner(Python / TypeScript / C# / Go / Java / PHP / Ruby)に要約を任せられる。compact すると決めたら runner の compact_before_next_turn()(言語により compactBeforeNextTurn() / CompactBeforeNextTurn())を呼ぶと、今のターンとそのツール呼び出しが終わった後に要約を頼んで履歴を差し替える。
- runner は beta header を足さない。
compact-2026-09-04を付けて runner を作る - 古い SDK(Python 1.8.0 / TypeScript 0.128.0 / C# 12.50.0 / Go 1.75.0 / Java 2.65.0 より前)は、要約のリクエストにも
stop_sequencesなどを送ってしまい 400 になる - task budget の
remainingを設定していると要約のリクエストが 400 になるので、設定しない - runner の
context_managementに compaction の edit があると、runner は compact を拒む。 1つの runner では一方の方式だけを使う
要約のプロンプトを自分で書く
instructions を指定しなければ API の要約プロンプトが使われる。空でない instructions(最大 16,384 文字)はそれを完全に置き換える。 要約器は instructions の有無に関わらず、それ以前の thinking も含めて会話全体を読む(閾値方式では、Claude 5.1 以降で instructions を指定すると見えている会話だけから要約する。compaction-threshold)。instructions には、要約に残すべきものと「ツールを呼ぶな」を書く。
要約が返らないとき・エラー
要約が出るのは、要約の呼び出しがテキストで正常終了しツールを呼ばなかったときだけ。 それ以外は 200 のまま content が空で返り、課金はされる。ブロックを探す前に stop_reason を見る。 どの場合も、要約なしで続けて後で compact し直せる。
stop_reason | 意味と対処 |
|---|---|
"max_tokens" | 要約が途中で切れた。max_tokens を増やして送り直す |
"model_context_window_exceeded" | 要約プロンプトの入る余地が無かった。instructions を短くするかメッセージを減らす |
"tool_use" | ツールを呼んでしまった。instructions で禁じる |
"refusal" | 拒否された。要約なしで続ける。stop_details にポリシー分類が入る |
"end_turn" | テキストが返らなかった。要約なしで続ける |
| エラー | 原因と対処 |
|---|---|
529 overloaded_error(error.details.error_code が compaction_unavailable) | 一時的なサーバ側の問題。再試行してよい |
400 compaction_block_misplaced | 要約したメッセージがブロックの前に残っている |
400 compaction_signature_invalid / compaction_content_mismatch | 返ってきた後にブロックの signature か content を変えた |
| 400(コード無し) | ブロックが2個以上ある/最後の assistant ターンが結果待ちのツール呼び出し |
400 compaction_nothing_to_summarize | messages に user / assistant の中身が無い(空リストなど) |
| 400(要約を頼むリクエスト) | beta header が無い。メッセージが requires anthropic-beta: compact-2026-09-04 と言う |
| 400(ブロックを載せた後のリクエスト) | beta header が無い。ただしメッセージは compaction が想定されたブロック型ではないと言うだけで、header に触れない |
400 Extra inputs are not permitted(…compaction.citations など) | API が返していないフィールドを付けて送り返した |
気づきにくいのは header の付け忘れで、要約を頼むリクエストでは header が要ると言われるが、ブロックを載せた後のリクエストでは言われない。
usage の数え方
The top-level
input_tokensandoutput_tokensare zero because no reply was generated. To count what a conversation consumed, sum acrossusage.iterations, not the top-level fields. Sending a block back on later requests adds no compaction cost.返答を生成しないので、トップレベルの
input_tokensとoutput_tokensはゼロになる。会話が消費した量を数えるには、トップレベルではなくusage.iterationsを合計せよ。 以降のリクエストでブロックを送り返しても compaction の費用は増えない。
併用の制限
compactionとcontext_managementは同じリクエストに送れない。 閾値 compaction(compact_20260112)も、署名つきブロックを積んだリクエストでは走らない- prompt caching: ブロックに
cache_controlを置くと、要約の後ろにブレークポイントが置かれる - 要約した範囲の
role: "system"メッセージは一緒に要約され、効力を失う。 まだ効かせたい指示はrole: "system"で言い直す。置き場所は次の新しいuserターンの直後で、以降も履歴に残しておく - task budget の
remaining(output_config.task_budget.remaining)をcompactionと一緒に、またはブロックを積んだリクエストに送ると 400 - token counting エンドポイントは
compactionパラメータを無視する - 画像・ドキュメント・
container_upload・取得した URL は要約に載らない。 ブロックが置き換えた時点で消えるので、後のターンで要る物は言い直すかアップロードし直す
そのまま使える具体例
要約だけを取りに行く(返るのはブロック1個):
response = client.beta.messages.create(
model="claude-opus-5-5",
# max_tokens caps the whole call, including any thinking, so allow several thousand tokens.
max_tokens=4096,
betas=["compact-2026-09-04"],
messages=history,
compaction={"type": "summarize"},
)
print(f"Stop reason: {response.stop_reason}")ターンごとにトークンを数え、上限を超えたら compact するループ(原典の例。上限 2,500 はわざと低い。実際は入力予算の近くに置く):
COMPACT_AT_TOKENS = 2500
SYSTEM = "You help design a recipe app's data model. Keep answers short."
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})
# The next request sends this reply too, so count it.
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}")履歴は追記ではなく置き換える(返ったメッセージが、要約に送ったメッセージ全部の代わりになる)。stop_reason を先に見る —— 要約が返らなかったら履歴はそのままにして、次のターンの後にもう一度頼む。
原典で言及されている関連文書
- compaction — 3方式の比較と選び方
- compaction-threshold — 閾値 compaction(ブロックの向きが逆)
- prompt-caching —
input_tokensがブレークポイント以降しか数えないこと - context-windows — compact する上限の目安
- compaction-thinking-blocks — 残したターンの thinking を有効に保つ条件