月100ドルの AI Ultra プランが出て最初に迷ったのは、Antigravity の利用上限が AI Pro の5倍になるという一点でした。私は個人開発のアプリと Dolice の複数ブログを並行して回しているので、上限が5倍あれば同時に走らせるエージェントを増やしたくなります。
けれど、そこで一度手を止めました。上限のティアは永続ではありません。来月コストを見直して AI Pro に戻すかもしれませんし、Ultra の枠が使い切られる日もあります。「5倍あるから」を前提に自動処理を組むと、段が下がった瞬間に夜間のバッチが半分こけて、朝それを片付ける羽目になります。私は一度それをやりました。
ここで扱うのは、上限のティアに正しさを結びつけない自動処理の組み方です。実際に上げ下げして分かった痛点とあわせて整理します。
上限は「性能」ではなく「余白」として読む
5倍という数字を見ると、処理能力が5倍になったように錯覚します。実際に増えるのは同時に走らせられる本数と、一定時間あたりに投げられる総量の余白だけです。1本あたりの賢さや正確さが上がるわけではありません。
ここを取り違えると、「Ultra なら並行10本で回せる」といった設計をしてしまいます。私自身の感覚では、上限は貯金のようなもので、あればあるほど安心できますが、生活の設計を貯金残高に合わせて固定すると、残高が減ったときに一気に苦しくなります。
上限は、ピーク時に詰まらないための緩衝材として読むのが安全でした。恒常運転の本数はもっと手前で決めるべきです。
段が下がると、最初に壊れる3箇所
Ultra から Pro に戻したとき、あるいは Ultra の枠を使い切ったときに、私の環境で真っ先に音を上げた箇所は決まっていました。
壊れる箇所 症状 根本原因
並行数 同時起動したエージェントの後半が起動直後に429で落ちる 同時実行数を上限ぎりぎりに固定していた
リトライ 失敗した1本を即再試行し、残量をさらに削って連鎖失敗 失敗時のバックオフが残量を見ていない
夜間バッチ 深夜の同時刻に集中したジョブがまとめてこける ピークを1点に寄せ、余白を食い合っていた
共通しているのは、どれも「上限が潤沢である」という前提に静かに寄りかかっていたことです。上限が減った瞬間に前提が崩れ、しかも失敗が失敗を呼ぶ形で悪化します。
設計原則1 — 正しさを上限に結びつけない
一番大切にしているルールは、処理結果の正しさを上限に依存させないことです。上限は「速く終わるか、ゆっくり終わるか」だけに効くべきで、「終わるか、こけるか」を左右させてはいけません。
観点 上限依存の設計(脆い) 上限非依存の設計(強い)
並行数 Ultra の枠に合わせて固定10本 やり直しコストから決めた3本を基準に、余白があれば増やす
失敗時 即リトライで押し切る 残量を見て待つ/翌枠に送る
完了判定 時間内に全部終わることが前提 途中で止まっても次回に続きから再開できる
右側の設計であれば、段が下がっても「遅くなるだけ」で済みます。左側は段が下がると「終わらない」に変わります。この差が、朝の後片付けの有無を分けました。
設計原則2 — 並行数は上限ではなく「やり直しコスト」で決める
同時に何本走らせるかは、上限からの逆算ではなく、1本がこけたときのやり直しコストから決めています。
こけた1本を再実行するのに何分かかるか、消費がどれくらいかを見積もる
同時に走る本数が増えるほど、1本の失敗が他を巻き込む確率が上がることを織り込む
「全部こけても許容できる」本数を恒常運転の基準にする
上限に余白がある日は、その基準に少しだけ上乗せする
私の場合、この考え方で並行本数を実際に絞りました。夜の同時刻に寄っていたジョブを別々の時刻へずらし、毎日の総実行回数も手前で丸めています。上限が5倍あっても、恒常運転の本数はほとんど変えていません。上限は増やしても、生活のリズムは変えない、という感覚が近いです。
コードで守る — 残量に応じた段階縮退
原則を頭で持っているだけでは、深夜の自動処理は守れません。残量に応じて並行数を落とす仕組みをスクリプト側に埋めています。考え方を簡略化したシェルが次です。実際の残量取得は環境に合わせて差し替えてください。
#!/usr/bin/env bash
# 残量に応じて並行数を段階縮退させる
set -euo pipefail
# remaining_pct: 現在の利用上限の残り割合(0-100)を返す関数に差し替える
remaining_pct () {
# 例: クォータ画面や API のレスポンスから残り割合を算出して echo する
echo "${ QUOTA_REMAINING_PCT :- 100 }"
}
decide_concurrency () {
local pct = " $1 "
if [ " $pct " -ge 60 ]; then echo 3 # 余白十分: 基準どおり
elif [ " $pct " -ge 30 ]; then echo 2 # 半分以下: 1段落とす
elif [ " $pct " -ge 10 ]; then echo 1 # 残り僅か: 直列に退避
else echo 0 # 枯渇: 今枠は見送り、翌枠へ
fi
}
PCT = "$( remaining_pct )"
N = "$( decide_concurrency " $PCT ")"
if [ " $N " -eq 0 ]; then
echo "quota exhausted (${ PCT }%): skip this window, defer to next" >&2
exit 0 # 失敗ではなく「見送り」。連鎖失敗を作らない
fi
echo "remaining ${ PCT }% -> concurrency ${ N }"
# ここで N 本を上限にジョブを起動する
肝は最後の exit 0 です。枠が枯渇したときにエラーで落とすと、監視やリトライが反応して残量をさらに削ります。枯渇は異常ではなく想定内の状態なので、「見送って次の枠に送る」を正常系として扱うのが、連鎖失敗を防ぐうえで効きました。
上限を上げ下げして分かったこと
実際に Ultra へ上げ、しばらくして基準を見直す過程で、いくつか腑に落ちたことがあります。
上限を上げた直後は並行を増やしたくなりますが、増やした分だけ失敗時の巻き込みも増えます。私は結局、同時実行を上げるより時刻を分散させるほうが安定すると判断しました。
残量の観測が甘いと縮退が間に合いません。枠の消費は後追いで見えることが多いので、少し保守的に、早めに1段落とすほうが取りこぼしが減りました。
「見送り」を正常系にしてから、朝の後片付けがほぼ消えました。夜のうちに片付かなかったジョブは、翌枠で続きから静かに再開します。
数字で言えば、恒常運転の並行本数は上限が5倍になっても据え置き、夜間の同時刻集中を解いて総実行回数を手前で丸めた結果、失敗の連鎖はほとんど起きなくなりました。上限の余白は、増えた分をピーク吸収に回すだけで十分でした。
次の一歩
もし今、上限のティアに合わせて並行数を固定しているなら、まず1つだけ試してみてください。恒常運転の並行数を、上限からの逆算ではなく「全部こけても許容できる本数」に置き直すことです。そのうえで、枠の枯渇を exit 0 の見送りとして扱う一行を足しておけば、来月ティアを下げても夜間の自動処理は静かに遅くなるだけで、朝あなたを待ち構えることはなくなります。
同じように複数の処理を並行させている方の設計の助けになれば幸いです。