Claude API の Task Budgets(public beta)実践 — Opus 4.7 のエージェントに token 予算を渡して総消費を制御する

Claude API に Task Budgets が public beta で登場(2026-05-06)。Opus 4.7 専用で、エージェントループ全体に対して token 予算を渡すと Claude が残量を見ながら自分でペース配分し、予算間際で「いまの成果をまとめて締める」挙動を取ります。本記事では beta header、output_config.task_budget の正しい書き方、ハマりやすい『payload と budget の差』、prompt caching との両立、適切な予算サイズの決め方までを実装目線でまとめます。

Anthropic が 2026-05-06 の Code with Claude 2026 keynote で、Task Budgets を public beta として正式に公開しました。Claude Opus 4.7 専用で、エージェントループ全体に対して token 予算を渡し、Claude が残量を見ながら自分でペース配分する仕組みです。本記事では実装観点で、何が新しくどう書きどこでハマるかを整理します。

到達点

  • Task Budgets の position(max_tokens / effort との違い)を把握
  • output_config.task_budget の正しい書き方
  • payload tokens と budget の差(これが地味に詰まる)
  • prompt caching との両立で避けたい書き方
  • 適切な予算サイズの選び方(measure-first)

まず position から

Task Budgets は agentic loop 全体の token 上限を Claude にヒントとして渡す機能です。混同しやすい兄弟機能との違いはこうです。

パラメータスコープenforce or hint何を制御するか
max_tokens1 リクエストの outputhard capリクエスト単位の生成上限
effort1 ターンの reasoning 深度hintどれだけ深く考えるか(per-step)
task_budgetagentic loop 全体soft cap(advisory)総計でどれだけ働くか(across-steps)

つまり max_tokensハードな天井task_budget運用の予算枠effort深さのつまみで、3 つは独立に共存できます

beta header と最低値

anthropic-beta: task-budgets-2026-03-13
  • モデル: Claude Opus 4.7 のみ。4.6 / Sonnet 4.6 / Haiku 4.5 は 非対応
  • 最低値: task_budget.total20,000 tokens 以上(下回ると 400)
  • Claude Code / Cowork は launch 時点で非対応(Messages API 経由のみ)

最小コード

cURL:

curl https://api.anthropic.com/v1/messages \
  --header "x-api-key: $ANTHROPIC_API_KEY" \
  --header "anthropic-version: 2023-06-01" \
  --header "anthropic-beta: task-budgets-2026-03-13" \
  --header "content-type: application/json" \
  --data '{
    "model": "claude-opus-4-7",
    "max_tokens": 128000,
    "messages": [{
      "role": "user",
      "content": "このリポを security 観点でレビューして報告して。"
    }],
    "output_config": {
      "effort": "high",
      "task_budget": {"type": "tokens", "total": 100000}
    }
  }'

Python SDK:

import anthropic
client = anthropic.Anthropic()

response = client.beta.messages.create(
    model="claude-opus-4-7",
    max_tokens=128_000,
    output_config={
        "effort": "high",
        "task_budget": {"type": "tokens", "total": 100_000},
    },
    messages=[
        {"role": "user", "content": "このリポを security 観点でレビューして報告して。"}
    ],
    betas=["task-budgets-2026-03-13"],
)

task_budget の中身:

キー必須説明
typestringyes常に "tokens"
totalintyesループ全体の予算(thinking + tool call + tool result + output 合算)
remainingintno既に使った分を引いた残量。omit で total と同値

重要 — payload と budget はずれる

ここが一番ハマる場所です。

公式ドキュメントの注意書きを噛み砕くと:

budget が減るのは「Claude がそのターンで見た新規 tokens」(thinking、tool call、新しい tool result、最終 output)。 クライアントが履歴を resend したぶんは数えない(同じものを再送しても server は double-count しない)。

つまり、自分の req.body の input_tokens と budget の減り方は一致しません。これを踏まえて以下のミスを避けます。

❌ アンチパターン: クライアントで budget を毎ターン手動で詰める

# 危険: payload の長さで remaining を引いていく
remaining = total - sum_of_previous_payload_tokens
output_config = {
  "effort": "high",
  "task_budget": {"type": "tokens", "total": total, "remaining": remaining},
}

これだと実際より早く 0 に近づき、Claude が用も無いのに「予算が無いので終わります」モードに入ります(早期切り上げ、partial result、最悪は refusal 様の挙動)。

✅ 正解 1: そもそも remaining を渡さない

履歴を毎ターン resend する素直なエージェントなら、remaining を omit して server に任せるのが一番素直です。budget の countdown は server が自分で管理しています。

✅ 正解 2: コンテキスト圧縮するときだけ remaining を渡す

途中で context compaction や summarization で履歴を書き換える設計の場合、server から見て履歴が連続しないので、自前で消費分を集計して remaining を渡す必要があります。

# compaction 後の最初のリクエスト
output_config = {
    "effort": "high",
    "task_budget": {
        "type": "tokens",
        "total": 128_000,
        "remaining": 128_000 - tokens_spent_so_far,
    },
}

tokens_spent_so_far過去の各 response の usage.output_tokens と、こちらが追加した tool_result の token 数を合算して算出します。

payload と budget の差を実例で見る

ドキュメントの worked example を簡略化すると、task_budget.total = 100,000 で 3 ターン回した場合に概ね次のようになります。

Turnクライアントが送った input_tokens(payload)budget が減った量remaining 残量
1~205,000(thinking + tool_use)~95,000
2~7,800(turn1 履歴 + tool_result)6,800(2,800 tool_result + 4,000 thinking + tool_use)~88,200
3~13,000(全履歴 + 2 個目の tool_result)7,200(1,200 tool_result + 6,000 final text)~81,000
合計~20,820 送出19,000 消費

クライアントは累積で 2 万トークン分を送出しているのに、budget はトータル 19,000 だけ減っている——これがズレの実体です。max_tokens のクライアント側計算とは別物として扱う、と覚えておけば問題ありません。

prompt caching と組み合わせると

task_budget.remainingターンごとに変えると prompt cache の prefix が無効化されます(値が変わるため)。output_config 全体は cacheable な系列に含まれているので、毎リクエストで remaining を計算して渡す = キャッシュヒットしないとなりがちです。

そこで実装パターンとしては以下を推奨:

  1. 初回リクエストだけ total を設定
  2. 以降は remainingtotal も触らず、server に countdown を任せる
  3. compaction を実施するピンポイントでだけ remaining を更新

これだけで output_config が安定し、prompt caching とも素直に両立します。

max_tokens との二段がけ

Task Budgets は soft cap です。Claude は budget を多少超過する可能性があります(行動の途中で切るより、まとめて締めるほうが現実的なケース)。ハードな天井は引き続き max_tokens です。

実務では:

  • task_budget.total: 計画上の予算(運用契約として定める数字)
  • max_tokens: 暴走防止の絶対上限(リクエスト 1 本あたり)

の二段でかけるのが安全です。xhigh / max effort を使う場合は max_tokens を 64k 以上に取らないと、各リクエストで思考が削られて挙動が荒れます。

小さすぎる予算は「拒否様」の挙動を引き起こす

ここが知らないと事故ります。

明らかにタスクに対して足りない予算を渡すと、Claude は着手を拒否したり、極端にスコープを縮めたり、partial result で早期に止まることがある。

たとえば、マルチ時間級のコーディングタスクに対して 20,000 token の最低値を渡すと、「こんな予算では真面目に着手しません」というリアクションが返ります。これは refusal ではないのですが、外形的には refusal そっくりに見えます。

まずは予算を上げ、上げても挙動が変だったら他のパラメータを疑う、という順で切り分けるのが鉄則です。

適切な予算サイズの決め方

ドキュメントが明示しているのは「まず Task Budget なしで p99 を測れ」です。

def run_task_and_count_tokens(messages, tools):
    total_spend = 0
    while True:
        r = client.beta.messages.create(
            model="claude-opus-4-7",
            max_tokens=128_000,
            messages=messages,
            tools=tools,
            betas=["task-budgets-2026-03-13"],
        )
        total_spend += r.usage.output_tokens  # thinking + tool_use + text 合算
        if r.stop_reason == "end_turn":
            return total_spend
        messages = messages + [
            {"role": "assistant", "content": r.content},
            {"role": "user", "content": run_tools(r.content)},
        ]

代表的なタスク群でこの計測を回し、p99 を初期 budgetにします。あとは(a) p99 にどれだけ余裕を載せるか、(b) p50 を狙ったタイトな運用にするか、をコスト/品質トレードオフとして決めます。

既存記事との関係

このブログでは以前、Opus 4.7 の破壊的変更とアダプティブ思考の記事で**budget_tokens パラメータが API から削除されたことを書きました。当時の budget_tokensper-request の thinking token 予算であり、今回の task_budget とは別物**です(混同注意)。

  • budget_tokens(削除済): per-request の thinking token 上限
  • effort(現行): per-step の reasoning 深度のヒント
  • task_budget(今回 GA への beta): across-loop の総予算

effort が「どれだけ深く考えるか」、task_budget が「どれだけ全体で働くか」、と読み替えると整理できます。

採用判断 — どんな現場で効くか

強く効くケース:

  • 1 タスクで 長時間多数の tool call を打つエージェント(コーディング agent、研究エージェント、データ分析パイプライン)
  • コスト/レイテンシの上限を運用契約として持っているプロダクト
  • 早期に切り上げたほうが UX が良いフロー(時間切れで「ここまでの所感をまとめます」が成立する用途)

そうでもないケース:

  • 1 〜 2 turn で終わる Q&A(max_tokens で十分)
  • バッチで品質最優先・コスト無視の研究系(effort: max だけで足りる)

まとめ

Task Budgets は **「エージェントに予算を運用契約として渡す」**ための部品です。max_tokens(ハード)+ effort(深さ)+ task_budget(総量)の 3 段構えで、コストとレイテンシの再現可能性が初めて現実的に握れるようになりました。

実装上の注意は payload と budget の差remaining を毎ターン触らない最低 20,000、足りなければ拒否様挙動——この 3 点を押さえれば事故は減ります。Opus 4.7 を本気でエージェントとして回すなら、最初から噛ませて困らない機能です。

参考