Managed Agentsのセッション予算(budget)でコストを上限管理する
Managed AgentsのセッションにUSD建ての上限を設定し、超過時の挙動・再開手順・マルチエージェントでの適用範囲を実装コード付きで解説します。
Managed Agentsのセッション予算とは何か
Managed Agentsのセッション予算(budget)は、セッション単位でドルの上限を設定するハード制限です。プラットフォームはセッションが消費するモデルトークン・Web検索・稼働時間を常時list価格(公開料金)で積算し、この合計(list cost)が上限に達すると新規のモデルリクエストを止めます。トークン数やターン数ではなく金額で止める点が要点です。
セッションは上限に達しても終了しません。idle(待機)状態になり、履歴とサンドボックスはそのまま保持されます。予算を変更または解除すれば、作業は自動的に再開します。組織の契約割引は反映されないため、実際の請求額は上限より低くなることがあります。
長時間タスクを本番で自律実行させるとき、いちばん怖いのは「気づいたら想定外の金額を使っていた」事故です。トークン数で上限を切るAPIは珍しくありませんが、Managed Agentsのセッションは複数スレッドが並行して動き、Web検索やサンドボックスの稼働時間まで課金対象に含むため、トークン単位の見積もりだけでは総額を読み切れません。セッション予算はこの「結局いくら使ったか」を金額そのもので止める仕組みで、長時間運用するエージェントには実質必須の安全弁です。
budgetを付けてセッションを作成する
budget はセッション作成時にしか付けられません。あとから追加しようとすると400エラーになります。
session=$(curl -sS --fail-with-body https://api.anthropic.com/v1/sessions \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
-d @- <<EOF
{
"agent": "$AGENT_ID",
"environment_id": "$ENVIRONMENT_ID",
"budget": {
"type": "limit",
"max_list_cost": {"amount": "125", "currency": "USD"}
}
}
EOF
)
SESSION_ID=$(jq -r '.id' <<< "$session")budget オブジェクトは2フィールドだけです。type は常に "limit"。max_list_cost.amount はセント単位の整数を文字列で渡します("125" は1.25ドル)。小数表記("25.00")や0以下は400エラーで拒否されます。文字列にしているのは浮動小数点の丸め誤差を排除するためで、currency は USD 固定です。
list costの算出根拠は3つ、モデルトークンが各モデルのlist価格、Web検索が1,000件あたり10ドル、セッションの稼働時間が1時間あたり0.08ドルです。これらの合計をリアルタイムで積み上げ、上限と比較します。
予算に達するとセッションはどうなるか
上限のチェックはモデルリクエストの合間に行われ、リクエストの途中では止まりません。上限を跨いだリクエストはすでに受理されているので最後まで実行され、結果として一時停止したセッションの list_cost は上限をわずかに超えた値になります。50セント上限のセッションが list_cost: "53" で止まるのは正常な挙動で、課金エラーではありません。超過幅はスレッドごとに最大1リクエスト分に収まるため、上限を決めるときはこの余白を織り込みます。
イベントストリームでは次の順に流れます。
- 各スレッドが停止するたびに
stop_reason: budget_reachedのsession.thread_status_idle - 累積使用量を持つ
session.usage stop_reason: budget_reachedのsession.status_idle(直前に必ずsession.usageが来ます)
停止中のセッションが受け付けるイベントは、進行中の作業を決着させるものだけです。user.tool_confirmation / user.tool_result / user.custom_tool_result / user.interrupt は受理されますが、新規作業を始める user.message などは400エラーで拒否されます。停止中に送った user.interrupt は黙って無視され、イベント一覧にも残りません。
予算を変更・解除して再開する
セッションの更新で max_list_cost を書き換えると、作業は自動的に再開します。追加のアクションは不要です。
新しい上限は現在の消費額より厳密に大きい値でなければなりません。停止直後の消費額は上限をわずかに超えているのが通常なので、古い max_list_cost ではなく、セッションが報告する usage.list_cost を基準にします。レポート値は丸められているため、そこから1セント以上余裕を持たせて設定するのが安全です。
マルチエージェントセッションとdeploymentでの適用範囲
マルチエージェントセッションでは、予算はスレッドごとではなくセッション全体で共有されます。各スレッドは自分が使うモデルのlist価格で消費を積み上げ、共有の上限に達したスレッドから順に停止します。advisorツールの相談も同じ予算に計上され、advisorモデルのlist価格で課金されます。1つのスレッドが承認待ち(requires_action)でもう1つが予算停止(budget_reached)の状態なら、セッション全体としては requires_action が優先されます。承認待ちへの応答は決着イベントなので、予算の停止対象にはなりません。
スケジュールデプロイでも同じ budget オブジェクトを作成・更新時に渡せます。ただしこの上限はdeploymentが起動する各セッションに個別コピーされるため、実行1回ごとの上限であって累積上限ではありません。deploymentの予算を変更しても、すでに走っているセッションには影響しません。セッションの予算と違い、deploymentの予算は null を渡せば一度解除して後から設定し直せます。
以下は用途ごとの設定単位の違いです。
| 設定単位 | 上限の意味 | 変更・解除 |
|---|---|---|
| セッション | 上限の意味そのセッション1本の累積 | 変更・解除いつでも変更・解除可(ただし一度解除すると同じセッションへの再付与は不可) |
| deployment | 上限の意味起動するセッションごとに個別コピー | 変更・解除いつでも変更・nullで解除して再設定可 |
消費額をどこで監視するか
セッションオブジェクトは budget と usage を常に保持しています。usage.list_cost が消費済みlist cost、usage.active_seconds が稼働時間課金の基になる秒数です。budget_reached で停止したセッションの usage.list_cost は、前述のとおり上限をわずかに超えた値を報告します。複数スレッドが同時に走るセッションでは、重複する稼働時間は1回だけ数えられるため、スレッドごとの usage を単純合計してもセッション全体の list_cost とは一致しません。上限判定に使われるのは常にセッション側の数値です。
session.usage イベントはこの累積値のスナップショットで、トークン内訳・list_cost・稼働秒数に加えて、Web検索の回数(課金対象)とWeb fetchの回数(課金対象外なので常に0)を含みます。セッションがidleになる直前には、停止理由を問わず必ず1件発行されるため、予算停止のログを追うときはこのイベントを起点にすると探しやすくなります。
Messages APIのtask budgetとは別物
「budget」という語はMessages APIのtask budget とも紛らわしいので区別します。セッション予算はUSD建て・プラットフォームが強制するハード停止です。一方task budgetはトークン単位でモデル自身に予算感覚を与える助言的な仕組みで、1回のエージェントループの中でモデルが自分の消費を自己調整するために使います。名前は似ていますが、強制するのがプラットフォームかモデル自身かという点で性質が異なります。
エラーになる条件
| 状況 | ステータス |
|---|---|
予算停止中に user.message など新規作業を始めるイベントを送った | ステータス400 |
| 上限をセッションの消費済みlist cost以下に設定した | ステータス400 |
| 予算なしで作ったセッションに予算を追加、または解除後に再付与しようとした | ステータス400 |
amount が整数セントでない・0以下、または currency がUSD以外 | ステータス400 |
| list価格のないモデルを使うエージェントで予算付きセッションを作成した | ステータス400 |
単発セッションとdeploymentで予算の使いどころを変える
同じ budget オブジェクトでも、単発セッションとスケジュールデプロイでは狙う効果が違います。単発セッションで予算を付けるのは、1回限りのタスクに「これ以上は使わせない」という天井を敷きたいときです。調査・分析のように、材料が尽きれば自然に終わるはずのタスクが想定外に長引いた場合の保険として機能します。
deploymentの予算は逆に、繰り返し実行される定型タスクの単価を固定する目的で使います。毎日決まった時刻に走るコンプライアンスチェックのようなタスクは、1回あたりの作業量がほぼ一定なので、実測の中央値に少し余裕を足した値を上限にしておけば、稀に発生する暴走ランだけを止められます。deploymentの予算は実行のたびに新しいセッションへコピーされる設計なので、過去の実行が使った分は次の実行の上限を圧迫しません。
予算運用でよくあるつまずき
-
list価格のないモデルは予算と併用できない。エージェントやマルチエージェントロースター上のadvisorが公開list価格を持たないモデルを使っていると、budgeted sessionの作成自体が400エラーで拒否されます。稼働後に対象モデルが混入した場合は、予算の変更が拒否され、解除でしか再開できません。
-
上限をぴったりに設定しない。1リクエスト分の超過余白を見込まずに上限を決めると、想定より早く
budget_reachedに達したように見えます。 -
既存セッションへの後付けはできない。予算なしで作ったセッションに途中から
budgetを足す設計は成立しません。上限管理が必要なら作成時点で必ず渡します。 -
list_costは契約価格ではない。ボリュームディスカウント契約があっても、上限判定は公開list価格ベースで行われるため、実際の請求額と上限の関係を誤解しないようにします。 -
上限変更の失敗を無限リトライしない。消費済みlist costより低い値で更新しようとすると毎回400になるので、まず
usage.list_costを取得してから新しい上限を決める順序を実装側で固定します。
まとめ
セッション予算はモデルトークン・Web検索・稼働時間を公開list価格で積算し、上限に達すると新規リクエストだけを止めるハードキャップです。セッションは終了せずidleで停止するため、上限変更または解除でいつでも再開できます。マルチエージェントでは予算がスレッド間で共有され、deploymentでは実行1回ごとに上限がコピーされる点が、単発セッションの予算と最も違う部分です。バッチ処理や長時間タスクを本番投入する前に、実測のlist costを見ながら上限を決めると、想定外の超過を避けられます。