ブログ

常時稼働エージェントの請求書はステップ数の二乗で伸びる——prompt の「節約して」が効かない理由

20 時間で 136M トークン、うち 97.7% が自分の履歴の再読。ステートレス API・5 分で切れるキャッシュ・伸び続けるスレッドの三つが揃うと、請求書はステップ数に比例せず二乗で伸びます。他社の公開データ四本から、上限を置くべき層を整理しました。

Leo Kaka約 11 分
手描きのインク挿画。自分でぜんまいを巻く小さな真鍮の置き時計と、そこから吐き出された紙テープが時計よりはるかに大きく巻き上がった山。山の中腹に小さな黄色い旗が一本立っている。

「AI エージェントを常時稼働させるべきか」という問いには、たぶん答えが出ません。出るのは 「止める境界を誰が引くか」のほうです。 prompt に「トークンを節約して」と書いた予算は、 モデルが無視できる助言です。コードかゲートウェイに書いた上限は、エージェントが交渉できない 保証です。同じ「予算」という言葉で呼ばれていますが、強制力の所在がまったく違います。 そして請求書はステップ数に比例しません——n ステップの実行で入力トークンは n の二乗で 伸びる(Anti-Pattern: The Unbounded Agent)。 「もう少し長めに回してみるか」の見積もりが外れるのは、直感が線形だからです。

きっかけは Zenn で Eggletric 氏が公開した「AIは回せば回すほど凄いのか ―「常時稼働」という設計の敗北」(2026-08-25、 採集時 152 ポイント・11 コメント)です。氏は常時稼働を「条件分岐が書けないからループで ゴリ押しするコードと、構造的には同じもの」と切ります。ただし具体的な計測値は載っていません。 その「敗北」がどういう機構で起きるのかを、他所の公開データで埋めます。 以下、私たちの計測は一つも出てきません。全部よそのデータです。

「回しすぎ」ではない——20 時間で 136M トークン、うち 97.7% は自分の履歴の再読

実例は、dev.to の wartzar-bee 氏が公開した一晩の記録(2026-07-20 公開、08-19 編集)。 タイマーで数分おきに起こし、タスクキューを見て一歩進めて眠る——それだけの構成を一晩放置した結果です。

項目
セッション時間20 時間・1,297 ターン
一晩で燃やしたトークン136M
5 時間ブロック単体116M(アカウント上限の 76%)
履歴の再読に消えた分508M
実際の新規作業11.9M
再読が占める比率97.7%(508M ÷ 508M + 11.9M)

比率の分母は 136M ではなく、508M と 11.9M を足した 519.9M です——処理したトークンと 請求に乗ったトークンは別の勘定なので、混ぜて検算すると合いません。

数字より効くのは、氏が本文で先回りして潰している弁解のほうです。

Nothing crashed. There was no runaway loop in my code. The agent did exactly what I told it to.

クラッシュしていない。暴走ループを書いた覚えもない。指示どおりに動いた。つまりバグの記録ではなく、 設計どおりに動いた結果の記録——Eggletric 氏の言う「設計の敗北」が別の言語圏で 計測されていたことになります。

二つの数字を並べたデータカード「一晩のトークン、その内訳」:履歴の再読 508M(97.7%)と、実際の新規作業 11.9M(2.3%)
20 時間の内訳。比率の分母は 508M + 11.9M = 519.9M で、請求に乗った 136M とは別の勘定。

この比率のたちが悪いところは、レビューで見つからない点です。コードは正しく、ログにエラーは出ず、 タスクは(少しずつ)進んでいる。異常が現れるのは請求書だけで、そこに「再読 97.7%」とは 印字されません。

三つの機構——ステートレス API・5 分で切れるキャッシュ・伸び続けるスレッド

なぜ再読が起きるのか。同記事は三つの機構を名指しします。どれも単体では既知の仕様で、 問題は三つが揃ったときだけ現れます。

機構原文単体では
API はステートレスThe API is stateless. The model doesn't remember your conversation — every turn re-sends the whole thread当たり前。だから履歴を送る
キャッシュが短命The prompt cache is short-lived... the cache expires fast — for Claude, ~5 minutes当たり前。だから連続実行では効く
スレッドは伸びる一方The thread only grows. Each wake-up appended to the same session当たり前。だから会話が続く

三つ目と二つ目の噛み合わせが効きます。起動間隔がキャッシュ寿命より長い定期実行は、 毎回フルプライスで全履歴を読み直します。5 分キャッシュに対して 10 分おきの起動を組むと、 「休んでいる間は無料」ではなく「起きた瞬間に過去全部を定価で読み直す」になり、 その量は昨日より今日のほうが多い。

ここで効いてくるのが、Unblocked の Dennis Pilarinos 氏がエージェントのトークン消費をまとめた記事(2026-06-10)で 挙げている context rot です。氏はコンテキストを context behaves as a limited resource with diminishing returns と説明します。 トークンが積み上がるほど実効的な注意予算は薄まり、初期の指示の想起率が落ちる—— 払う量は増え、得られる質は落ちる。壊れているのはコストだけではありません。

ステップ上限を 10 から 20 にすると、請求書は 2 倍ではなく約 4 倍になる

見積もりが外れる本体はここです。Multigrid の Anti-Pattern: The Unbounded Agent(2026-08-03 更新)から。

Each turn re-sends the conversation so far, so if turns add roughly constant length, total input tokens across an n-step run grow with n squared rather than n. Doubling the step limit from ten to twenty does not double the worst-case bill; it roughly quadruples the input half of it.

ステップ上限を 10 から 20 に緩めることは、最悪ケースの請求書を 2 倍にする行為ではなく、 その入力側をおよそ 4 倍にする行為です。見積もりが外れるのは暴走したからではなく、 足し算の見積もりを掛け算の現象に当てたからです。

倍率の出発点も見ておきます。Anthropic の Multi-agent research systemagents typically use about 4× more tokens than chat interactions, and multi-agent systems use about 15× more tokens as chats と書いています。ただしこれは一回あたりの 倍率で、前段の 一回の実行のなかで効く別の増幅です。測っている対象が違うので、 二つを掛けて「何倍」とは言えません(そう書いた出典はありませんし、本稿も出しません)。 言えるのは、マルチエージェントで長めに回す構成は、性質の異なる二つの増幅が それぞれ効く場所に立っているということだけです。

三つを重ねると、単独のどの記事にもない一文が残ります。常時稼働の請求書は、稼働時間では なくステップ数の二乗で伸びる。

なお、失敗時のリトライが似た増幅を起こす件は en 刊の retry storms の回で別途扱っています。正常系のループと失敗系の再試行は 機序が違うので、上限も別に引く必要があります。

止まる箇所は三つある——ステップ数・支出・ファンアウトは別々に縛る

「上限を入れました」で安心できないのは、入れる箇所が一つではないからです。 前掲の Multigrid は失控を三種に分けています。

種類原文他の上限では止まらない理由
Step countThe agent retries the same failing tool, or oscillates between two states, or plans a plan to plan安いステップの無限往復は、支出上限にかかるまで延々と回る
SpendSteps are bounded but each step grows. The transcript accumulates, so step twenty re-sends everything from steps one to nineteenステップ数を縛っても、一歩あたりが肥大すれば効かない
Fan-outThe agent spawns sub-agents or parallel tool calls, each of which has its own step budget親の予算を、子が独立に消費する

三つ目が一番見落とされます。サブエージェントを生やす構成では、子はそれぞれ自分のステップ予算を 持っている。親に 20 ステップの上限を置いても、親が 5 体生やせば総ステップは親の上限とは 無関係に決まります。同記事はこの結末を A per-agent budget under fan-out is how a fifty-cent cap becomes a fifty-dollar run と 書いています——50 セントのつもりの上限が 50 ドルの実行になるのは、上限をエージェント単位で 置いたからです。処方も同じ文にあります:予算はタスクに紐づけ、子を生やしたら 同じ予算オブジェクトを渡す(新しいものを与えない)。

同記事の中心の一文がこれです。

The model deciding is a heuristic; a bound is a guarantee. You want both, and only one of them can be relied on when the heuristic is the thing that has gone wrong.

モデルが「もう十分だ」と判断するのはヒューリスティック、外側の bound は保証。両方あっていい。 ただし壊れているのがそのヒューリスティック自身であるとき、頼れるのは片方だけです。 自分が壊れていることを壊れている当人に検知させる設計——「もっと賢いモデルにすれば止まる」 という方向が効かない理由がここにあります。

prompt に書いた予算は助言、ゲートウェイの上限は保証

では上限をどこに書くか。Future AGI の Vrinda Damani 氏の ループのコスト制御をまとめた記事(2026-08-01)が明快です。

A line like “stop once you have spent ten dollars” is a suggestion the model can ignore, especially when it is focused on finishing the task. The cap has to sit in your code or at your gateway, where it aborts the next call whatever the agent decides.

モデルはタスクの完遂に最適化されています。「節約しろ」と「終わらせろ」が衝突すれば後者が勝つ。 prompt に予算を書く設計は、守るかどうかの判断を、超えたい当人に委ねているわけです。 同記事の挙げる強制層は四つ——呼び出し前の budget cap、リトライ上限、ループ検出、 ログとコスト帰属。最初の一つだけが「止める」機能で、残りは「気づく」機能です。

実装例もあります。Future AGI は自社ドキュメントで、組織・キー・ユーザー・モデル単位の USD 建て上限を日次・週次・月次・累計で強制する(使い切ると新規の呼び出しを承認しない)と 説明しています。上限がキーの属性なら、その鍵を持つエージェントが何体いようと交渉の余地はありません。

pirouter でも、上限はキーの属性として持たせる設計として進めています(設計方針であって 提供中の機能の説明ではありません。実装状況はドキュメントを参照)。 鍵に有効期限・スコープ・上限を持たせる考え方はエージェントに渡す鍵の形、 一回の呼び出しの単価はコンテキスト注入の請求書で扱いました。 本稿の関心は、その呼び出しが何回起きるかです。

常時稼働は選択肢のままでいい。交渉不可能にすべきなのは境界のほうだけ

Eggletric 氏の「理想は、最小のトークンで狙った出力(ゴール)に到達すること」には同意します。 ただし本稿の結論は「回すな」ではなく、回す前に止まる場所を自分で決めておけです。 常時稼働そのものは善でも悪でもない。敗北になるのは、止める権限を止まるべき当人に 預けたときだけです。順番としては、

  1. ステップ数・支出・ファンアウトに、別々の上限を置く(一つで代用しない)
  2. その上限を prompt ではなく、アプリのコードかゲートウェイのどちらかに書く
  3. 起動間隔をキャッシュ寿命と突き合わせる——長ければ、毎回フルプライスの再読が乗る

2 の「どちらか」は好みではなく、数えたい対象がプロセスの内側にいるか外側にいるかで 決まります。ステップ数も支出も、呼び出しが同じプロセスを通るならアプリ層のカウンタで足ります。 ファンアウトだけは違う——子エージェントは自分の予算を持って独立に API を叩くので、 アプリ層は自分が知らない呼び出しを数えられません。残高が複数のプロセスにまたがった時点で、 勘定はキーの側=ゲートウェイに移ります。 単一プロセスで子を生やさないなら、要りません。

3 が合わないときは、間隔を詰めるのではなくセッションを切る。伸び続けるスレッドを 短い間隔で起こしても再読の総量は減りません。状態はファイルに置いて、毎回新しい セッションで拾い直すほうが安くつきます。

ここに書いた数字は全部よそのものです。自分の構成の n がいくつなのかは、 自分のログにしか書いていません。