Astraに合わせてCodexのオーケストレーションを組み直して使用量を抑える
目次
Codexを使って作業している仕事があって、今まではSolで動かしていた。
そこにAstraが来たので安易に差し替えて、あとはよろしくとGoalスキルに投げてみたら、
朝起きたら止まっていた。
週間制限のリセット直後から動かし始めたのに、半日持たず100%使い切った。
流石にちょっと酷いので、どうなってるのか調べてみた。
無駄にリセットさせられた
止まったところから再開するために1回リセットして、今度はEffortを下げて動かしてみた。
結果的には似たようなもので、もう1回リセットする羽目に。
何にそれだけ使ってるのか。
現在の作業では直球でメインのモデルを使っているわけではなく、
オーケストレーションを組んで、下位モデルを指揮して作業するようにAGENTS.mdを組んでいる。
通常ではAstraで全部動かすということはないはずだが、実際Solでは普通に動いていたが、Astraは全部自分に昇格していた。
AGENTSの内容は読んでいるが、より作業がうまく動くようにはこっちのほうがいい、というので勝手に作業を変えるところが見受けられた。
それだけならいいが、みていると下位モデルに対しての完了報告、ポーリングがかなり激しい。
これもPythonなどのスクリプトで定期実行しているならいいが、LLMとして叩いていてコンテキスト圧縮する原因となっている。
ようするにAstraは、ポン出しではない他の作業の続きや構造改善などの作業の時は、Solと同じように使うと消費量が激しすぎる、ということのようだった。
ということでもっとガッチガチに縛って動かせばなんとかなるか?ということで1日叩いてみた。
ポーリング時間の調整
手元のCodex CLIは0.153.4。ウェイトの最小時間設定があるので、時間を伸ばしてみた。
[features.multi_agent_v2]
enabled = true
min_wait_timeout_ms = 120000
default_wait_timeout_ms = 120000
最低時間なので延ばしすぎると今度は確認をしに行かない可能性もある。この辺りは動かして自分の環境で調整がいると思う。
AGENTS.mdの方も合わせて変更。
サブエージェントの作業の確認は120秒待機を基本にして、120秒を超えそうな作業なら上限の範囲でその2倍以上に設定させる。
この設定時間より下は許さない。
これでワーカー役やマネージャー役のエージェントの完了通知を待つことを基本とさせ、人間が今すぐ状況を知りたいと言ったときだけデータを取りに行かせる。
ここで、プロセス監視のためのエージェントを使おうとするのは絶対に禁止にする。
代わりに実行中のプロセスの監視はランタイムにやらせることを基本とすることで、無駄なエージェントが立たないため、無駄な消費を抑える。
こちらの作業環境ではデフォでは60秒で設定されていたが、今の作業だと60秒では短すぎて、数十分待たせてもいい感じではある。しかしどこで終わるかよくわからないので、下限を伸ばして、あとは作業分量で上に伸ばせという運用の方が、自由度高そうなのでそっちで設定。
役割を明確に分ける
とりあえず、Astraをオーケストレーターに置いて、その下にSolの工程マネージャー、さらに下にLuna・Terra・Solのワーカー、それとは独立したSolのレビュワー、という運用で整理。
人間の組織でも、上が下に口出しまくるといいことがない。
「オーケストレーターは実装ではなくシニアマネージャーとして振る舞ってほしい」という強目の指定。
規模が小さいとか自分でやったほうが速いといった理由も認めない。
逆に、作業が明確で範囲も限られているなら、間に挟むマネージャーのほうを省く。
| 役割 | 持つもの | 持たないもの |
|---|---|---|
| オーケストレーター | 目的、優先順位、権限、割り当て、証拠での最終判断 | 実装、テスト実行、反映、記録更新 |
| 工程マネージャー | 割り当て、依存関係、指示とパスの補正、修正ループ | 実装、テスト実行、反映、記録更新 |
| ワーカー | 1件の作業と、それに対応する短い確認の実行 | 別エージェントの起動、範囲外の判断 |
| レビュワー | 実際の差分と証拠の確認、可否の判定 | 仕様の拡張、無関係な整理 |
過程は要約して渡す
オーケストレーションだけ考えると綺麗な構成かなと思ったが、よく考えてみると、
中間管理職のマネージャーに実装の結果、テストの出力、レビュー内容、反映、反映後の検証を全部読み込ませ続けると、Solが第二のAstraになる。
まあ過重労働気味だし、そもそもコンテキストが溢れてしまう可能性が高い。
そこで、それまでAstraに上げる直前だけ要約していたのを、エージェント間の受け渡し全部で要約するようにした。
余計なことは省く
要約だけ渡すと判定材料が前のモデルの言ってることだけになるので、そこからの指示が出せない。
例えば、変更をコミットで固定して渡してもいいし、引き継ぎ用のMarkdownでもいい。何かしら材料を渡すようにしないといけない。
要は判断に余計な材料を上げなければいい。原本は参照できる成果物として保存しておいて、マネージャーやオーケストレーターが受け取るのは要約と参照先だけにする。
こうすることで再度のファイル走査も抑えさせることにした。とにかくコンテキストを溢れさせない、1個のエージェントに作業を集中させない、短い仕事に分解させてやらせる。
ただしレビュワーだけは例外として、要約だけで判断せず、実際の差分などを参照先から自分で確認させることにした。
レビューまで要約で済ませると、あーOKっぽいですね、という事実だけが上に伝わって、中身を誰も確認しない、ほんとにOKかどうかはわからない、ということに。
コミットは毎工程での必須作業にはしていない。
作業ツリーが汚れたままの状態で差分からハッシュを取ることもあるので、どのコミットを基準にしているか、未コミットの差分がどれか、どの環境で、いつ時点のものかは別々に書き分ける。
ブランチ切ったりワークツリーという手もあるが、ちょっとオーケストレーションで並列作業する時に馴染まないので、運用上はこれでいけるだろという感じで。
工程マネージャーは、区切った工程を終えたら終了させる。無関係な作業の履歴を抱えたまま次の工程へ回されると、マネージャーがどっかでおかしくなるので。
エージェント間の連絡も縛る
要約を書かせるのはいいが、自由な文章で書かせるとそれはそれで長くなる可能性が高い。
各エージェントが好きな感じで書いてこられると困る。
そこで上位へ返す要約JSONの書式を強制した。
| 項目 | 中身 | 制限 |
|---|---|---|
| status | completed / needs_action / blocked のいずれか | ー |
| summary | 何が起きたか | 1文120字以内 |
| changes | 変更点 | 最大3件、各80字以内 |
| evidence | 参照先と、そこでの検証の成否 | 最大3件、参照は省略しない |
| risks | 危ないところ | 最大3件、各80字以内 |
| unverified | 確認できていないところ | 最大3件、各80字以内 |
| next_action | 次にやること | 1文120字以内、なければ none |
| escalation | 上へ上げる判断事項と推奨案 | null、または120字以内 |
該当がなければ空の配列。3件に入らないときは全件を成果物に保存して、省略した件数と evidence の何番目かを指す短い参照だけ残す。重大な失敗と未確認は省略しない。ここ省くとバグるので。
{"status":"completed","summary":"待機の既定を120秒へ変更し、指示書の待機節を置き換えた","changes":["グローバル設定へ待機キーを追加","指示書の待機・通知節を置換"],"evidence":["<コミットハッシュ> / 索引テスト pass"],"risks":[],"unverified":["実行中セッションには上位の60秒制約が残る"],"next_action":"新しいセッションで待機の実効値を確認する","escalation":null}
status の completed は、担当した範囲が終わったという意味。
全体の完了を待った上でフラグが立つわけではないが、レビューが通っただけで担当範囲の完了になるとそれはそれで後が困るのでそこでは立たない。
レビュー、反映、反映後の検証には、それぞれ何を確認したかを書く詳細なJSONがもともとある。そちらは原本として残したまま、共通の8項目からは evidence で参照する。
結局Astraはオーケストレーター降板
最後に、Astraをオーケストレーターに常駐させる必要があるのかを見直した。
ここまでの仕事は目的の管理と証拠の判定に絞られていて、重い作業である探索も実装もしない。
一番重いモデルを置き続ける理由がほんとにあるのか?少なくともここの作業では、ない。
通常はSolのmediumをオーケストレーターに置く方針に変更。
工程マネージャーが要るときもSolのmedium、実装はLuna・Terra・Solから作業の重さで選ぶ、
レビュワーは会話を引き継がない別インスタンスのSolのmedium、というふうに配置変更。
Astraはメインの作業導線から外して、例外の助言役だけに残した。
flowchart TD
R[オーケストレーター Sol medium] --> M[工程マネージャー Sol medium]
M --> W1[ワーカー Luna]
M --> W2[ワーカー Terra]
M --> W3[ワーカー Sol]
M --> RV[レビュワー Sol<br/>会話を引き継がない]
W1 --> A[成果物<br/>差分・ログ・原本]
W2 --> A
W3 --> A
A --> RV
W1 -. 報告JSON .-> M
W2 -. 報告JSON .-> M
W3 -. 報告JSON .-> M
RV -. 報告JSON .-> M
M -. 報告JSON .-> R
R -. 例外条件のみ .-> AS[Astra 助言役]
AS -. 助言 .-> R
Astraを呼ぶ条件は具体的に列挙した。
| きっかけ | 条件 |
|---|---|
| 判断の不一致 | マネージャーとレビュワーの判断が実質的に食い違う。同じ重大な指摘が2回の修正とレビューの後も解消されない |
| 範囲の変更 | 作業範囲そのものを変える必要がある |
| 影響の大きい変更 | 公開APIの取り決め、DBのスキーマ、認証、マイグレーションを変える。巻き戻せない、または破壊的な影響が具体的に判明している |
| 決着しない設計 | 範囲を区切って検討した後も、妥当な設計が複数あって決まらない |
| 証拠不足 | 求められた完了に必要な証拠が足りない。ローカルで確かめられる事実を確認した後も明示的に詰まっている |
呼ばない条件も同じだけ書いた。
| 呼ばないもの | 扱い |
|---|---|
| 難しそう、時間がかかりそう | 難易度とかかる時間だけでは条件にしない |
| 細かい指摘が2件たまった | 重大な指摘が2回解消されなかった場合とは別に数える |
| 証拠が足りない | 追加の検証が要るか未完了かのどちらかで、Astraが必須の確認を省けるわけではない |
| ユーザーの権限に関わる判断 | Astraは代行せず、実装もしない |
| 同じ事実のままの再エスカレーション | 助言を返したらSolへ責任が戻る |
ここをもっとファジーに、「なんかこういう状態になったら呼んで」にすると、全く呼ばないか年中呼ばれるかの両極端がありうる。
こういうのは大体機械的に判定させた方がいい。
実際に動かしての事故
この構成で実際に回してみたら、半自動化してあるBacklogから取得した課題の件数と、こちらが指定した件数が合っていなかった。
それでもSolはそのまま作業を始めた。理由としては、取得スクリプトに関連カテゴリーの指定が入っていなかった、と申告してきた。
ただ、こちらが言った数と明確に合っていないのだから、その時点で確認を入れてほしい。確認せずに進んだSolは、思考的にちょっと弱いと思えた。
Astraをオーケストレーターに置いていたときは、同じ不備のあるスクリプトでも取得をやり直させていた。
推論の深さの影響もありそうなので、オーケストレーターをSolのhighへ上げた。
そもそもAstraに入れ替える前はHighでやってたので、まあ妥当なのかも。
highへ変えたあとの挙動
highへ変更後、Backlogを再取得した際には途中で追加した課題も認識し、既存課題との依存関係を見て処理順を組み直した。
追加課題は最後へ回すかもと最初に言い出したが、途中で処理可能と判断して挿入し、並列実行できない理由も説明してきた。
少なくともこのケースでは、mediumで見られた判断の弱さがなく、こちらの思った通りの挙動ではあった、と思う。
| オーケストレーター | 今回観測した挙動 |
|---|---|
| Sol / medium | ワーカーの報告と人間の申告の食い違いを見逃した |
| Sol / high | Backlogを再取得し、追加課題込みで処理順を組み直した |
| Astra | 従来から再取得と再判断はできていたが、消費が非常に大きい |
構成変更後のSol運用では、約90分動かして途中で追加指示も出したが、表示上の使用量は1%未満の減少だった。
Astra運用時との厳密な比較ではないため、めちゃくちゃ効率的に動いた!という判定はできないが、少なくともAstraの自由にさせるよりはマシなようだ。
mediumからhighへ変えたことによる目立った差も、使用量表示には今のところ見えていない。
highを使っているのは、Astraを置いていたオーケストレーター1箇所だけになる。
工程マネージャーはSolのmedium、実装はLuna・Terra・Sol、レビュワーはSolのmediumのままで、下までhighにする理由は今のところない。
この辺も動かしてみて上がってきたものを見ないとなんとも言えないが、ほんとにやばいのしか上がってこないようならレビュワーが何か言うだろう。