task_budgetは強制上限でなくadvisoryという性質
Claude APIのtask_budget(ベータ)はハード上限ではなくadvisoryです。refusal-likeな挙動や早すぎる打ち切りを症状から切り分け、予算を実測で決める手順を解説します。
task_budgetは「必ず守られる上限」ではない
task_budgetはadvisory(強制されない助言的な指定)です。予算が小さすぎると、refusal-likeな挙動(依頼を断る・スコープを縮める・途中で打ち切る)が起きます。
task_budget(ベータ)は、エージェントループ全体で使えるトークン数をClaudeに伝える機能です。数えるのはthinking・tool call・tool result・出力のすべてで、Claudeは残量のカウントダウンを見ながら優先順位をつけ、予算が尽きる前に区切りよく終えようとします。
誤解されやすいのは、これをmax_tokensと同じ「ハードな上限」だと思い込むことです。公式ドキュメントはソフトなヒントであり、強制上限ではないと説明しています。中断するより完了させたほうが影響が小さい作業の途中なら、Claudeは予算を超えることがあります。
task_budgetとmax_tokensの役割
task_budget
Claudeがペース配分の目安にする数値です。複数リクエストにまたがるエージェントループ全体にかかり、超えても止まりません。最小値は20,000トークンです。
max_tokens
暴走的な生成を止める絶対的な天井です。到達するとstop_reason: "max_tokens"でレスポンスが打ち切られます。個々のリクエストにかかる値です。
コストや遅延にハードな上限が必要なら、task_budgetと適切なmax_tokensを組み合わせます。対象が違うので両者は独立した値で、どちらかがどちらかを下回っている必要もありません。
向くのは、最終出力までに複数回のtool callと判断を挟むエージェント型のワークフローです。使いどころは三つです。長時間タスクのペース配分をClaudeに任せたいとき。タスクごとのコストや待ち時間を読みやすくしたいとき。予算が尽きそうな場面で、作業を中途半端に切らず調査結果を要約して報告させたいときです。tool callを伴わない単発の生成は、公式が想定する主な用途ではありません。
症状から原因を切り分ける
予算まわりのトラブルは、症状でおおよその原因が分かれます。
| 症状 | 最初に見る点 |
|---|---|
| 依頼を断る・スコープを縮める・途中経過だけで止まる | 最初に見る点totalが作業量に対して小さすぎる |
| 予算が残っているはずなのに早く切り上げる | 最初に見る点クライアント側でremainingを減らしている |
| ループの後半で推論が浅くなる | 最初に見る点thinkingも消費に含まれ、残量とともに深さが縮む |
| プロンプトキャッシュが効かない | 最初に見る点予算の値やremainingを毎回書き換えている |
| 予算を超えて動き続ける | 最初に見る点advisoryなので超えうる。上限はmax_tokens |
| 400エラーになる | 最初に見る点totalが20,000トークン未満 |
| レスポンスに残量が出てこない | 最初に見る点残量はモデルにだけ見え、usageには含まれない |
最後の行は、実装で最初につまずきやすい点です。カウントダウンはモデルにだけ見えるため、APIレスポンスに予算の残量フィールドはなく、SDKにもその値を読むアクセサがありません。残量をクライアントで追いたいときは、ループ内のトークン使用量を自前で合計します(後述の「実測ベースで予算を決める手順」を参照)。
予算が小さすぎるとrefusal-likeな挙動が起きる
task_budget運用で見落とされやすい副作用です。作業量に対して明らかに足りない予算を見せられると、Claudeの振る舞いが変わることがあります。タスクに着手しない、スコープを大幅に縮める、完了できない見込みの作業は始めずに途中経過だけ返して打ち切る、といった形です。公式の例は、数時間かかるエージェント型のコーディングタスクに20,000トークンの予算を付けるケースです。
想定外のrefusalや早すぎる打ち切りが起きたら、他のパラメータを調べる前に予算を引き上げます。固定のデフォルト値を決め打ちせず、実際のタスク長の分布に合わせて設計する前提です。
早すぎる打ち切りはクライアント側の実装でも起きます。原因は後述の「自前でcompactionするときのremaining」にあります。
実測ベースで予算を決める手順
task_budgetを付けずに代表的なタスクを走らせ、タスクごとの合計トークン消費を記録します。エージェントループなら、ループ内の全リクエストのusage.output_tokensを合計し、リクエスト間で渡すtool resultのトークン数も加えます。
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
messages=[{"role": "user", "content": "Review the codebase and propose a refactor plan."}],
)
# output_tokens(テキスト・thinking・tool callを含む)をループ内の全リクエストで合計する
print(response.usage.output_tokens)代表的なタスク集合でこれを実行して分布を取り、まずp99(上位1%)の消費量を出発点にします。そこから上下に振って、モデルの振る舞いがどう変わるかを見るのが公式の手順です。
task_budget.totalの最小受理値は、対応モデルのすべてで20,000トークンです。これより小さい値は400エラーになります。
task_budgetの設定方法
output_configにtask_budgetを追加し、ベータヘッダーを付けます。
curl https://api.anthropic.com/v1/messages \
-N \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: task-budgets-2026-03-13" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 128000,
"stream": true,
"messages": [{
"role": "user",
"content": "Review the codebase and propose a refactor plan."
}],
"output_config": {
"effort": "high",
"task_budget": {"type": "tokens", "total": 64000}
}
}'task_budgetオブジェクトのフィールドは3つです。typeは常に"tokens"、totalはループ全体で使えるトークン数、remaining(省略可)は前のリクエストから引き継ぐ残量で、省略するとtotalになります。
effortとの役割は別です(使い分け全般はClaude effortとはを参照)。effortは各ステップをどれだけ丁寧に推論するかを決め、task_budgetはループ全体でこなす作業量に天井を付けます。公式は前者を深さ、後者を広さの調整と位置づけています。xhighやmaxのeffortでは、max_tokensを少なくとも64k確保し、各リクエストで考え行動する余地を残すことが推奨されています。
1ターンの区切りは「tool resultを含むか」で決まる
予算がカバーするのは、1つのエージェントターン(エージェントループ)です。tool resultを含まないユーザーメッセージで始まり、複数のリクエストにまたがりえます。
予算がリセットされるかどうか
新しいターン
tool resultを含まないユーザーメッセージです。予算が尽きてターンが終わった後の"Continue."のような続きの依頼がこれにあたります。
同じターンの続き
tool_resultブロックを含むユーザーメッセージです。tool_resultと一緒に「Dockerfileも確認して」のようなテキストを添えても、同じターンとして扱われます。
リセットされた後も、以前のターンの履歴がコンテキストに残っている間は、カウントダウンの計算にその履歴分が数えられます。
ターンの途中でサーバーサイドCompactionが起きても予算はリセットされず、それまでに消費した分は数え続けられます。一方、ターンの開始時にCompactionで要約された以前の履歴は、今回のターンの予算に数えられません。この除外は、サーバーサイドCompactionをまたいで引き継がれる予算にだけ適用されます。要約を挟まず前のターンの履歴が残っているだけなら、上のとおり数えられます。
予算が減るのは「Claudeが見た新規分」だけ
エージェントループでは、クライアントが毎回会話履歴の全体を再送します。ペイロードは膨らみますが、予算が減るのはClaudeが新しく見た分(生成したトークンと、まだ見ていないtool result)だけで、再送された内容が二重に数えられることはありません。task_budgetはthinkingトークンも消費に含めるため、残量が減るとadaptive thinkingの深さも自動的に縮みます。長いループの後半で推論が浅くなったと感じるなら、原因の一つはこの残量です。
公式の実例は、100,000トークンの予算で3リクエストからなる1ターンです。
3リクエストの合計
クライアントが送った累計
約20,820
履歴を再送するぶん、ペイロードは膨らむ
予算に計上された分
19,000
新しく見たトークンだけ
最終の残量
約81,000
100,000から19,000を引いた値
リクエストごとの内訳
- 1
リクエスト1:ユーザーメッセージを送る
送信ペイロードは約20トークンです。Claudeがthinkingとtool callで5,000トークンを生成し、残量は約95,000になります。
- 2
リクエスト2:1つ目のtool resultを足して履歴を再送する
ペイロードは約7,800トークンです。計上されるのはtool result 2,800とthinking等4,000の計6,800で、残量は約88,200です。
- 3
リクエスト3:2つ目のtool resultを足して再送する
ペイロードは約13,000トークンです。計上されるのはtool result 1,200と最終報告のtext 6,000の計7,200で、残量は約81,000です。
送信量と予算の減り方は一致しないため、クライアント側の数え方をそのまま予算に当てはめることはできません。公式は、クライアント側で残量を追いかけて合わせにいくより、余裕を持った予算を設定してカウントダウンに任せることを勧めています。
会話の途中で予算を変えるとキャッシュが外れる
task_budgetはリクエスト単位の設定です。ユーザーの要求が広がって予算を伸ばしたいときは、次のリクエストのoutput_configに新しいtask_budgetを渡します。予算の値はレンダリングされるプロンプトの一部として扱われるため、値を変えると古い予算で作られたキャッシュエントリとは一致しません。
もう一段深い影響もあります。予算のカウントダウンマーカーはリクエストごとにサーバー側で注入され、リクエスト間では一致しません。そのうえ、クライアント側でtask_budget.remainingを毎リクエスト減らして送ると、その値を含むキャッシュプレフィックスがそのたびに無効になります。
キャッシュを保ちたいなら、最初のリクエストで一度だけ予算を設定し、以降はクライアントで値を書き換えずサーバー側のカウントダウンに任せるのが公式の推奨です。予算を頻繁に変える運用では、再キャッシュのコストも織り込みます。
自前でcompactionするときのremaining
長時間のループでは、呼び出し側が独自にメッセージ履歴を圧縮することがあります。サーバーは圧縮前の消費を覚えていないので、そのままでは次のリクエストでカウントダウンがtotalに戻ります。そこでremainingに「totalから、取り除いた履歴の消費分を引いた値」を渡し、圧縮前の続きから再開させます。
# 圧縮でメッセージから取り除いた分の消費トークン(クライアント側で記録)
tokens_spent_so_far = 45000
output_config = {
"effort": "high",
"task_budget": {
"type": "tokens",
"total": 128000,
"remaining": 128000 - tokens_spent_so_far,
},
}引く対象は、送信するメッセージにもう含まれていない分だけです。圧縮後のメッセージに残っている分や、自分で足した要約は、サーバーがトークンを数え直すので引きません。この値を更新するのは履歴を置き換えたときだけで、リクエストごとに減らす値ではありません。一方、渡すときは圧縮したリクエストに限らず、以降のすべてのリクエストに同じ値を付けます。
Compaction自体の発動しきい値の考え方はCompactionの発動しきい値の決め方にあります。
一時停止と組み合わせる運用はCompactionの一時停止で合計トークン予算を強制する実装パターンが扱っています。
remainingを使うのは、独自に圧縮しているループだけです。毎回の履歴をまるごと再送する通常のループでは、remainingを省いてサーバー側のカウントダウンに任せます。履歴を再送しながらremainingまで減らすと、Claudeが見る残量が実際より少なくなり、カウントダウンが本来より速く進みます。予算が十分あるのに作業を早めに切り上げるのは、この二重の引き算が原因です。
task_budgetの対応モデルと制約
task_budgetはベータ機能で、ベータヘッダーはtask-budgets-2026-03-13です。対応・非対応はモデルごとに分かれます。
| モデル | 対応状況 |
|---|---|
| Claude Fable 5.1 / Mythos 5.1 / Fable 5 / Mythos 5 | 対応状況ベータ対応 |
| Claude Opus 5.5 / Opus 5 / Opus 4.8 / Opus 4.7 | 対応状況ベータ対応 |
| Claude Sonnet 5.5 | 対応状況ベータ対応 |
| Claude Sonnet 5 / Opus 4.6 / Sonnet 4.6 / Haiku 4.5 | 対応状況非対応 |
同じSonnet系でもSonnet 5.5は対応、Sonnet 5は非対応と分かれる点に注意してください。Claude CodeやCoworkの利用面ではtask_budgetは使えません。使うなら、Messages APIを対応モデルへ直接呼び出す実装が前提です。