約 4 分で読めます

per-message effortでキャッシュを保つ切替設計

長時間のエージェントセッションでは、最初の計画立案は深く考えさせたいが、その後の定型的な確認や要約は軽くこなさせたい、という場面が必ず出てきます。ところがトップレベルの output_config.effort を次のリクエストで書き換えると、プロンプトキャッシュは先頭から作り直しになります。複数チームが共有する基盤では、この再構築コストがそのまま入力トークンの増加として現れます。per-message effort はこの問題を、会話履歴の末尾に差し込むメッセージ1つで解決するベータ機能です。

なぜトップレベルのeffort変更はキャッシュを壊すのか

トップレベルのeffortはレンダリング後のプロンプトを形作るため、リクエスト間で値を変えると過去ターンのキャッシュ済みプレフィックスは再利用できなくなります。

公式ドキュメントは「トップレベルの effort はレンダリングされたプロンプトに影響するため、リクエスト間で変えると以前のターンのキャッシュ済みプレフィックスは保持されない」と明記しています。対応モデルでなければ、キャッシュに依存する長いセッションでは最初に effort を決めて固定することが推奨されています。

Claude Fable 5.1 ではさらに別の問題があります。過去の返信は以前の effort で書かれているため、モデルがその一貫性に引きずられやすく、トップレベル変更では切替が効きにくいとされています。キャッシュコストと挙動の両面で、会話内でトップレベル値を動かす設計は避けるべきです。

per-message effortはどう書くのか

role: "system" で content を空にし output_config.effort だけを載せたメッセージを追記すると、既存プレフィックスを変えずに次のuserターンから効きます。

仕組みは mid-conversation system messages の延長です。ベータヘッダー mid-conversation-output-config-2026-07-01 を付け、messages に effort だけを持つ system メッセージを入れます。

``python
response = client.beta.messages.create(
model="claude-fable-5-1",
max_tokens=4096,
output_config={"effort": "high"},
messages=[
{"role": "user", "content": "移行計画を3ステップで立ててください。"},
{"role": "assistant", "content": "1. ... 2. ... 3. ..."},
{"role": "system", "content": [], "output_config": {"effort": "low"}},
{"role": "user", "content": "計画を1文で要約してください。"},
],
betas=["mid-conversation-output-config-2026-07-01"],
)
``

effort だけを持つメッセージはテキストを含まないため、コンテンツ付き system メッセージの配置ルールは適用されず、messages の任意の位置に置けます。新しい値は、新しい入力を持つ次の user ターンから有効になり、後続のメッセージが変えるまで保たれます。変更点より前は一切書き換わらないので、キャッシュ済みのプレフィックスはそのまま一致します。なお、隣り合う system メッセージはまとめて判定されるため、コンテンツ付きメッセージの隣に置く場合はそちらの配置ルールに従います。

切替の粒度はどこまで細かくできるのか

ツール結果だけを返すuserターンは「新しい入力」に数えられないため、effortの切替粒度はツールループの1ステップ単位ではなくuserターン単位です。

ここが設計上の最大の制約です。tool_result ブロックだけを持つ user ターンは新しい入力として扱われず、その後ろに置いた effort 変更は次の本物の user ターンまで待たされます。したがって、1つのツールループの途中で「検索は軽く、統合判断は重く」と切り替えることはできません。

粒度を細かくしたい場合は、次の2通りで設計します。

  1. ターン単位: ユーザー入力の種類(新規の調査依頼か、定型の追質問か)で effort を決め、user ターンの直前に effort メッセージを入れる
  2. サブエージェント単位: 軽い探索や整形を別リクエストのサブエージェントに切り出し、そちらを low で走らせる。公式の effort 表でも、low の典型用途にサブエージェントが挙がっている

ルーティング規則は評価データで決めます。effort は厳密なトークン上限ではなく挙動への信号で、低い設定では検索や確認を省く傾向が出ます。Claude Haiku 5.5 は長いエージェントプロンプトで low にすると、検索を飛ばす、早く止まる、確認を省くといった挙動が出やすいと明記されています。規則を本番に載せる前に、自社の評価セットで effort ごとの完了率を測ってください。

モデルとプラットフォームの差をどう吸収するか

対応モデルはプラットフォームで異なり、Bedrockでは範囲が狭いため、ゲートウェイ側で能力判定して未対応時はトップレベル固定にフォールバックさせます。

公式ドキュメント上の対応状況は次のとおりです。

環境per-message effort 対応モデル
Claude API / Google CloudClaude Fable 5.1、Mythos 5.1、Opus 5.5、Opus 5、Sonnet 5.5、Haiku 5.5
Amazon BedrockClaude Fable 5.1、Mythos 5.1、Opus 5.5(Opus 5 は対象外)

さらに、Claude Sonnet 5.5 の thinking: {"type": "between_tools"} と、Claude Haiku 5.5 の thinking: {"type": "disabled"} では、現在値と異なる per-message effort が400エラーになります。ターンごとに effort を変えたい経路では adaptive thinking を使ってください。

未対応モデルにベータ値付きで送ると400になります(output_config.effort requires a model that supports per-turn effort)。Bedrock では Extra inputs are not permitted が返ります。エンタープライズの LLMゲートウェイ には、モデル別の能力テーブルを持たせ、非対応なら effort をリクエスト全体で固定する分岐を入れます。

規模別の運用留意点

数百のセッションが同じ基盤を共有する環境では、effort ポリシーをアプリ側ではなくゲートウェイで一元管理すると、チーム別の配賦と監査が容易になります。デフォルト値もモデルで異なる点(Opus 5.5 と Haiku 5.5 は medium、他は high)に注意が必要で、モデル更新時は effort を省略した呼び出しの挙動が1段階変わり得ます。モデル更新のたびに effort スイープを回すことが公式にも推奨されています。

参考

まとめ

per-message effort は、キャッシュを保ったまま推論深度をターン単位で切り替える仕組みです。ツールループ内部では切替できないこと、モデルとプラットフォームで対応が異なることを前提に、ゲートウェイでの能力判定と評価データに基づくルーティング規則を組み合わせます。大規模基盤での effort ポリシー設計や統制の相談は、Kuuの大規模AI変革プログラム(RDE)までお問い合わせください。

関連記事

プロンプトキャッシュミスの原因をAPIで特定するSonnet 5.5のbetween_tools移行ガイドClaude Opus 5.5移行の破壊的変更とチェックリストExtended Thinking設計指針——adaptive thinkingとeffort制御