夜間に走らせている記事生成の補助パイプラインを、新しい Antigravity CLI に載せ替えた朝のことです。動力が高速なモデルに替わり、1ステップあたりの応答は体感で3〜4倍ほど速くなっていました。当然、全体のスループットも同じだけ伸びると思っていました。
ところが、実測してみると改善はおよそ1.4倍に留まっていました。エージェントの「考える時間」は確かに短くなったのに、パイプライン全体はそれほど速くなっていなかったのです。
理由を追っていくと、設計の前提そのものが古くなっていたことに気づきました。モデルが遅かった頃に「待ち時間を埋める」ために組んだ構造が、速くなった途端に足を引っ張っていたのです。個人開発で複数のアプリと媒体を並行運用していると、こうした自動パイプラインの効率は地味に効いてきます。速度が変わったときに、設計のどこを組み直すべきか。今回はその判断軸を整理します。
速度が上がると、待ち時間ではなく「検証」が律速になります
遅いモデルを前提にした並行パイプラインは、たいてい「推論待ちの時間をいかに隠すか」を中心に組まれています。複数のタスクを同時に投げ、片方が考えている間にもう片方の結果を処理する。推論レイテンシが支配的なうちは、これで全体がきれいに速くなります。
ところが推論が4倍速くなると、相対的に他の処理が前面に出てきます。私のパイプラインで律速になっていたのは、各ステップの後に走らせていた検証処理でした。生成物のフォーマット確認、リンク切れチェック、ビルド可否の判定。これらは外部プロセスやネットワークに依存するため、モデルが速くなっても短くなりません。
つまり、速度を上げると「推論 : 検証」の比率が逆転します。以前は推論が8割・検証が2割だったものが、推論2割・検証8割になる。このとき検証を据え置いたまま並行度だけ上げても、検証の待ち行列が膨らむだけで全体は速くなりません。最初に向き合うべきは、この比率の逆転です。
タスクの粒度を小さく刻み直す
遅いモデル時代の定石は「1回の呼び出しでまとめて大きな仕事をさせる」ことでした。呼び出し1回あたりのレイテンシが重いので、往復回数を減らすのが合理的だったからです。
速くなると、この前提が崩れます。往復が軽くなった分、大きな単位は逆に不利になります。大きなタスクは一度失敗すると、やり直しのコストも大きいからです。1回で5ファイルを生成させて4ファイル目で失敗すると、成功した3ファイル分も含めて巻き戻すことになります。
私はこのパイプラインで、生成単位を「記事1本まるごと」から「セクション単位」へ刻み直しました。失敗の影響範囲が1セクションに閉じ、リトライも軽くなります。粒度を小さくすると往復回数は増えますが、1往復が安くなった今ならその増加は吸収できます。判断の目安として、私は「1タスクの失敗で巻き戻る作業量が、そのタスク自体のコストを上回るなら、粒度が大きすぎる」と考えています。
並行度の上限は「速さ」ではなく「ブラスト半径」で決める
速くなると、つい並行度を上げたくなります。同時に走らせるエージェントを2本から8本に増やせば、単純計算では4倍速くなるはずだからです。
けれども並行度の上限は、速度から逆算してはいけないと考えています。決め手はブラスト半径、つまり「同時に走っている1本が暴走したとき、どこまで被害が及ぶか」です。8本のエージェントが同じリポジトリに同時に書き込めば、競合とロールバックの地獄が待っています。速くなったぶん、暴走も4倍速く広がります。
私は並行度を、共有リソースの単位で区切るようにしています。書き込み先が分離できるタスク(別ディレクトリ・別ブランチ)は並行度を上げ、共有状態に触れるタスクは直列に落とす。具体的には、独立した生成タスクは最大6並行、共有設定ファイルを触る統合ステップは1並行、という形です。速度はあくまで「分離できた範囲の中で」効かせます。
検証ループを2段構えにする(安いチェックを前に)
検証が律速になったとき、検証そのものを速くする発想に行きがちですが、より効くのは「安い検証を前に、高い検証を後に」並べ替えることです。
私のパイプラインでは、検証を2段に分けました。第1段は数十ミリ秒で終わる静的チェック(必須フィールドの有無、禁止語、フォーマット)。第2段は数秒かかる重い検証(ビルド、リンク到達性、整合性スキャン)。第1段で弾けるものを第2段に流さないだけで、重い検証の実行回数が体感で半分以下になりました。
これは速度が上がったからこそ効く工夫です。生成が速いと、第1段で弾かれた生成物を作り直すコストが小さい。「とりあえず生成して安いチェックで素早く弾く」というループが、遅いモデルでは割に合わなかったのに、速いモデルでは最も効率的な戦略になります。検証は止めるのではなく、順番を組み替えるものだと捉え直しました。
コスト上限とリトライ予算を設計に組み込む
速度はコストの形を変えます。1回が安く速いと、リトライへの心理的なブレーキが外れ、いつのまにか何十回も再試行していた、ということが起こります。速くなったぶん、暴走したときの請求も速く積み上がります。
そこで私は、リトライを「無制限の善意」ではなく「予算」として設計に埋め込むようにしました。タスクごとにリトライ上限を持たせ、上限に達したらエージェントに任せず人間のキューへ落とす。さらにパイプライン全体に時間あたりの呼び出し上限(レートリミット)を設け、想定外の連鎖リトライが起きても1時間あたりのコストが頭打ちになるようにしています。
目安として、私は1タスクのリトライ上限を3回に置いています。3回同じところで失敗するなら、それは入力か設計の問題であって、4回目で直る見込みは薄いからです。速くなった環境ほど、この種の「止める設計」を先に入れておく価値が高いと感じています。
実際に組み直した非同期パイプラインの骨格
ここまでの判断をまとめると、設定はおおむね次のような形になります。実際のオーケストレータはもっと複雑ですが、骨格を抜き出すと意図が見えやすくなります。
# pipeline_config.py — 高速モデル前提で組み直した並行パイプライン設定
from dataclasses import dataclass, field
@dataclass
class StageBudget :
name: str
max_concurrency: int # ブラスト半径で決める(速度ではない)
retry_limit: int = 3 # 同じ箇所で3回失敗したら人間キューへ
cheap_checks: list = field( default_factory = list ) # 第1段: 数十ms
heavy_checks: list = field( default_factory = list ) # 第2段: 数秒
STAGES = [
StageBudget(
name = "generate-section" , # 粒度: 記事ではなくセクション単位
max_concurrency = 6 , # 書き込み先が分離できるので並行可
cheap_checks = [ "required_fields" , "banned_words" , "frontmatter" ],
heavy_checks = [ "build_ok" , "link_reachable" ],
),
StageBudget(
name = "integrate-index" , # 共有設定ファイルに触る統合 step
max_concurrency = 1 , # 共有状態 → 直列に落とす
retry_limit = 2 ,
heavy_checks = [ "consistency_scan" ],
),
]
# 全体のレートリミット(時間あたり呼び出し上限)でコストを頭打ちにする
GLOBAL_RATE_LIMIT_PER_HOUR = 240
def gate (stage: StageBudget, artifact) -> bool :
# 第1段(安い)で弾けるものは第2段(高い)に流さない
for check in stage.cheap_checks:
if not run_cheap(check, artifact):
return False
for check in stage.heavy_checks:
if not run_heavy(check, artifact):
return False
return True
このコードで本質的なのは関数の中身ではなく、「並行度・リトライ・検証順序・レートリミットを、速度とは別の軸で明示的に持っている」という構造です。速さは可変ですが、ブラスト半径やコスト上限は速さに引きずられて勝手に動いてはいけません。ここを定数として外に出しておくと、次にモデルがさらに速くなったときも、設計を壊さずにスループットだけを引き上げられます。
組み直した結果、当初1.4倍だったスループットは実測で約2.9倍まで伸びました。推論が速くなった効果を、検証と並行度の再設計でようやく回収できた形です。
組み直すときの順番 — 本番で安全に効かせる
実際に既存パイプラインへ手を入れるときは、いきなり並行度を上げないことが大切です。順番を誤ると、速くなる前に壊れます。私が本番で踏んでいる手順は次の通りです。
まず「推論 : 検証」の比率を1回だけ計測する。逆転していなければ、そもそも組み直す必要はありません
検証を安い第1段と高い第2段に分け、安い方を前に並べ替える。ここはリスクが低く、効果が大きい一手です
タスクの粒度を、失敗時の巻き戻し量が小さくなる単位まで刻む
共有リソースに触れるステップを洗い出し、そこだけ並行度を1に固定する
最後に、分離できた範囲でだけ並行度を上げる。リトライ上限とレートリミットを入れてから上げる
この順番には理由があります。並行度を最後に回すのは、検証と粒度を整える前に並行度だけ上げると、壊れたときの原因切り分けが一気に難しくなるからです。私は癒し系の壁紙アプリを App Store と Google Play で運用しながら、この補助パイプラインを夜間に走らせています。本番のデータに触れる処理ほど、こうした「壊さない順番」を守る価値が高いと感じています。落とし穴は、速度に浮かれて一度に複数の軸を変えてしまうことです。1軸ずつ変え、そのたびに比率を測り直してください。
体感が変わったあとに残る、人間の仕事
速度が上がって最も変わったのは、数字よりも自分の役割でした。エージェントが速く動くほど、人間が向き合うべきは「個々の実行」ではなく「設計の前提」に移ります。並行度をいくつにするか、何を直列に守るか、どこで人間に戻すか。速さはこうした判断を肩代わりしてはくれません。
6月18日の旧 CLI 提供終了を前に、自動化を載せ替える方は多いと思います。そのとき、ただ新しい CLI に差し替えるだけで終わらせず、「速くなった前提で設計を組み直す」一手間を入れてみてください。差し替えだけでは1.4倍、組み直すと2.9倍。同じモデルでも、設計次第でここまで変わります。
まずは手元のパイプラインで「推論 : 検証」の比率を一度だけ計測してみることをお勧めします。そこが逆転していたら、この記事の組み直しがそのまま効くはずです。最後までお読みいただき、ありがとうございました。