TL;DR
- AIエージェント運用の進化モデル「プロンプト → ループ → スワーム → グラフ」を、実在の自律トレーディングシステム(trader)に当てはめて自己診断した。
- 結論:trader はすでに Stage 3(スワーム)であり、Stage 4(グラフ)の性質も一部先取りしている。「スワームを導入する」という新規タスクは存在しない。
- 段階モデルは ツール名(Slate, LangGraph…)ではなく「性質(property)」で自己診断すべき。「並列がネイティブか」「失敗がノードに限定されるか」を問えば、すでに満たしているものを買い直さずに済む。
- グラフランタイムへの移行(Stage 4 化)は、測定可能なエッジが無いため非推奨。記事自身が「価値は考え方でありツールではない」と言っている。
- 本当に埋めるべき穴は2つだけ:即時 maker-checker(別コンテキスト検証層) と レートリミット専用のサーキットブレーカー/バックオフ。
この記事は、同じ4段階モデルを設計側から解説した「グラフエンジニアリング入門 — AIエージェントで多因子アルファモデルを組む「4段階」の到達点」の姉妹編にあたる。あちらが「これから組むならどう設計するか」なら、こちらは「もう動いているシステムを段階モデルの鏡に映すとどう見えるか」だ。
きっかけ:段階モデルに「名詞」で反応してしまう罠
AIエージェント運用を4段階で整理するフレームが流行っている。
- プロンプト — あなた自身がループ。閉じれば何も残らない。
- ループ — スクリプトで包み、スケジュールで発火。状態を持ち、自走する。
- スワーム — ループを役割ごとに多数のエージェントへ扇状展開。信号生成・検証・執行を別エージェントが担う。ただし調整は手書きの Python グルーコード。
- グラフ — 協調構造を一度だけ宣言的に記述。並列・待ち・再試行・エスカレーションをランタイムが知っている。
この手のモデルを読むと、つい「じゃあ次はスワームを導入しよう」「グラフに移行しよう」と、段階を名詞(=導入すべきツール)として消費したくなる。これが罠だ。段階モデルの正しい使い方は、記事も書いているとおり「今どこにいるかを名指しする」ことにある。名指しを飛ばして「導入」に走ると、すでに持っているものを別の名前で買い直すことになる。
そこで、実在の自律トレーディングシステム(日本株・BTC を対象にシミュレーション運用中のシステム。以下 trader)を題材に、まず現在地を実装レベルで名指ししてみた。
現在地を実装で名指しする
段階を「性質」に分解し、trader のコードがそれを満たすかを確認した。抽象論ではなく、実装の実態で判定する。
| スワーム/グラフが要求する性質 | trader の実装 | 判定 |
|---|---|---|
| 役割ごとにエージェントを扇状展開 | technical / fundamental / sentiment / risk / researcher / portfolio / reviewer / screener / strategy_explorer の分業(各エージェントに専用プロンプト・モデル・timeout) | ✅ |
| 並列と逐次を分ける | 銘柄間は ThreadPoolExecutor(max_workers=3) で並列。銘柄内は依存に従い逐次(technical → sentiment → risk → researcher)。全銘柄の per-symbol 計画を最後に portfolio が横断統合=同期ポイント | ✅ |
| 役割ごとにモデルを使い分ける | 数の出る単純作業(technical/fundamental/sentiment/risk/reviewer)は高速モデル、判断が要る統合(researcher/portfolio)は強い推論モデル | ✅ |
| エージェント間のデータ受け渡し | 前段の結果(JSON)を次段の user_message に「参考情報」として注入。ツールデータは銘柄ごとに1回だけ取得しキャッシュ共有 | ✅ |
| 失敗をノードに限定(全体を殺さない) | per-symbol 失敗は as_completed で捕捉し空結果に差し替え、他銘柄は継続。個別エージェント失敗は例外を握って error 付き結果を返し、後段は欠損コンテキストのまま degrade | ✅ |
| 協調構造を宣言的に一度だけ記述 | 手書きの Python グルーコード(orchestrator / evaluation_pipeline)で調整。宣言的ではない | ❌(=Stage 3 の定義そのもの) |
| 状態永続化 | scan cursor(分割バッチの進捗をファイル保存)・learnings(SQLite)・singleton lock はある。ただしパイプライン途中状態からの再開は無く、日次実行は毎回まっさら再計算 | △ |
読み方はこうだ。「宣言的な協調記述が無く、手書きグルーコードで束ねている」というのは Stage 3(スワーム)の定義そのものであって、欠陥ではない。trader は「スワームに満たない何か」ではなく、教科書どおりのスワームなのだ。
記事が「グラフで解決する」と言う3つの壁を、trader はどう吸収しているか
段階モデルの元記事は、「スクリプト(手書きグルー)は3つの瞬間に壊れる。だからグラフが要る」と主張する。ではその3つの壁を、trader は Stage 4 のランタイム無しでどう処理しているか。
壁① あるエージェントが別のエージェントの完了を待つ
trader は依存関係を ThreadPoolExecutor と as_completed の合流点で表現している。銘柄内は「technical の結果を context に載せて sentiment を呼ぶ」という逐次依存、銘柄間は独立並列、最後に portfolio が全結果を待って統合する。待ち合わせは同期ポイントとして明示的にコードに存在する。グラフランタイムが自動でやることを、trader は手で・しかし正しく配線している。
壁② 状態をサイクルをまたいで保持する
trader の周回モデルは「毎日まっさらに再計算する日次バッチ」だ。ここが重要で、trader は途中状態の持ち越しを”必要としない”設計を選んでいる。持ち越すべき知識(過去の計画 vs 実結果の学習)は reviewer が SQLite の learnings に落とし、次周回の researcher/portfolio に還流する。分割スキャンの進捗だけは scan cursor で持つ。つまり「状態をまたぐ」という壁は、必要な粒度でだけ永続化し、不要な途中状態は捨てるという判断で回避されている。グラフの「全状態を永続化」は、日次バッチには過剰だ。
壁③ 異なるモデルで複数ループを並列に回す
trader はすでに sonnet 系と opus 系を役割ごとに使い分け、銘柄並列で回している。同時 CLI 起動は Semaphore(3) で制限し、各エージェントに個別 timeout(180s〜900s)を設定。「複数モデル・複数並列」は実運用済みで、壁になっていない。
記事の失敗談(「あるエージェントがレートリミットで詰まり、翌朝はパイプライン全体が死んでいた」)に対して、trader は 例外を握って degrade する・timeout で必ず打ち切る・銘柄を独立並列にするという防御的コードで、“全体即死”を構造的に起きにくくしている。グラフが構造で与えるはずの「失敗のノード限定」を、trader は規律あるエラーハンドリングで既に達成している。
だから「スワーム導入」はタスクとして存在しない
ここまでを一言でまとめると:
trader は「スワームを入れるべきシステム」ではなく、「すでにスワームであり、Stage 3 の失敗モードの多くを防御的に潰し終えたシステム」である。
段階モデルの価値は「次に買うべきツール」を教えることではなく、「今の自分の性質」を鏡に映すことにあった。鏡に映してみたら、trader はもうスワームだった。新規導入すべき”スワーム”という名詞は、どこにも残っていない。
では Stage 4(グラフ化)に進むべきか → 非推奨
「スワームなら次はグラフだ」と反射しそうになるが、ここでも性質で判断する。
グラフランタイム(Slate / LangGraph 等)が構造的に解決すると謳う失敗モード(待ち・状態・並列・ノード限定失敗)は、前章で見たとおり trader が既にコードで満たしている。したがってグルーコードを宣言的グラフに書き換えても、得られるのは「同じ性質の別実装」であって、システムの判断品質(=リターン)を測定可能に改善しない。
trader の文化は「効果をバックテストで測ってから ship する」だ。この規律に照らすと、リターンにエッジが出ないランタイム swap は、大規模な移植コストに見合わない。そして何より、段階モデルの元記事自身がこう書いている——「価値は”協調構造を宣言的に設計する”という考え方であって、どの製品を使うかは二の次だ」。その考え方(並列と逐次を分ける・役割でモデルを分ける・失敗をノードに閉じる)を trader はすでに体現している。考え方を持っているなら、それを載せ替えるためだけのランタイム移行は不要だ。
「不要」で終わらせない:本当に埋めるべき穴は2つ
「スワーム導入は不要/グラフ化も不要」は、「現状で完璧」という意味ではない。段階モデルの移植可能な設計原則を trader に当ててみると、まだ満たしていない性質が2つだけ残る。ここは素直に効く。
① 即時 maker-checker(作り手と検証者を別コンテキストに分ける)
これは段階モデルの核心原則で、trader の唯一の明確なギャップだ。現状の「検証」は次のいずれかで、生成物を別コンテキストが即座に反証しにいく層が無い:
- risk エージェント → 同一生成パスの一部(独立した検証者ではない)
- pydantic バリデーションや各種 clamp → 決定的コードによる範囲矯正
- reviewer → 別周回・事後のフィードバックループ
- 人間の承認 → 実質の checker は人間であって別 AI ではない
maker-checker(four-eyes principle、Anthropic の Evaluator-Optimizer、Andrew Ng の Reflection に対応)は「同一モデル・同一コンテキストの自己検証は”検証”ではなく”二度実行”にすぎない」という原則に立つ。この「作り手に自分を検証させない」という発想は、過去記事「AIエージェントにリファクタさせるときの「完了の定義」の引き方」の敵対的レビュー、そして「「計画するAI」と「書くAI」を分ける開発手法」の承認ゲート設計とも一直線につながる。trader の設計思想(自己検証を検証と呼ばない)とも完全に一致するので、思想的な追加コストはゼロだ。
ただし trader 流に、導入前に効果を計測する。過去の計画に maker-checker を遡及適用し、「何件をフラグ/反転したか」を測ってから常設化するのが筋で、無検証で入れる話ではない。
② レートリミット専用のサーキットブレーカー/バックオフ
段階モデルの失敗談そのものが、trader の残存リスクに直結する。現状の緩和は Semaphore(3) + timeout retry のみで、429/レート超過を検知して全体を一時停止する機構・指数バックオフ・キュー退避は未実装(エラー分岐は timeout と auth の2種だけ)。加えて単一スケジューラ構成のため、長時間ジョブ(portfolio は最大900s)が後続ジョブの発火を圧迫しうる。ここはランタイムを載せ替えるまでもなく、インフラ耐障害性の素直な穴埋めとして効く。
持ち帰り:段階モデルは「名詞」ではなく「性質」で使う
- 段階モデルは自己診断の鏡であって、購買リストではない。 「スワームを導入」ではなく「自分はもうスワームの性質を満たしているか?」と問う。
- 性質で判定すると、買い直しを避けられる。 trader は並列・役割別モデル・失敗のノード限定を既に満たしていた。名詞で反応していたら、同じものを別の名前で作り直していた。
- 次の段階へ進む理由は「順番だから」ではなく「測定可能なエッジがあるから」。 グラフ化はエッジが無いので見送り。
- “不要”の結論は、残った本物の穴を浮かび上がらせる。 全部を否定するのではなく、maker-checker とレートリミット耐性という性質のギャップ2つに注意を集中できる。
「新しい段階が発表された → 導入しよう」ではなく、「その段階が要求する性質を、自分はもう満たしているか」。この問いの立て方こそが、マルチエージェント時代に無駄な移植を避ける唯一の防具だと思う。
補章:スワームはどう「実現された」のか —— 開発史からの裏づけ
ここまでの「スワーム導入はタスクとして存在しない」という主張は、trader の git 履歴を辿ると歴史的に証明できる。結論を先に言うと:trader のスワームは「スワームを構築する」という工程で実現されたのではなく、小さな役割分業コアから issue 駆動で”性質が後から積み上がって”実現された。
二層構造:設計されたコア + emergent なハードニング
層1:初回コミットで設計された骨格(2026-02-22)
最初の1コミットで、いきなり次が一括投入されている。
- 5 エージェント分業(technical → fundamental → sentiment → risk → researcher)
- ただし完全逐次(前段の結果を context に積み上げるだけで、並列は無い)
- 個別エージェントの例外を握って
AgentResult(error=...)を返す=「1ノード失敗で全体を落とさない」degrade 思想は当初から内蔵
この時点の trader は、4段階でいえば Stage 2(ループ)に役割分業を足しただけで、スワームの中核性質(並列がネイティブ/失敗がノードに限定)はまだ満たしていない。「役割で分けた逐次パイプライン」に過ぎなかった。
層2:スワームの”性質”は後から issue 駆動で付いた
スワームらしさを与える性質は、すべて後発で、しかもバラバラの issue に紐づいている。
| 時期 | 何が入ったか | 契機 |
|---|---|---|
| 2026-02-23 | SDK → claude --print CLI に切替(SDK 期間はわずか1日) | 運用調整 |
| 2026-02-26 | 銘柄間並列(ThreadPoolExecutor + as_completed)+ Semaphore で同時CLI制限 + 銘柄単位の失敗隔離 | #69 |
| 2026-03-03 | portfolio 統合フェーズ(=同期ポイント)追加 | — |
| 2026-03-18 | strategy_explorer 追加 | #226 |
| 2026-03-21 | reviewer(事後フィードバックループ)追加 | — |
| 2026-03-26 | 銘柄内(エージェント間)並列 | #281 |
| 2026-04-21 | CLI timeout の延長リトライ | #670 / #672 |
| 2026-07-02 | 認証 fail-fast プローブ + OAuth refresh 回復 | #1980 |
エージェント数は 5 → 9+ へ、並列は「無 → 銘柄間 → 銘柄内」へ、耐障害性は「握って continue だけ → Semaphore → timeout retry → auth 回復」へと、運用で踏んだ障害を issue 化して潰すパターンで一段ずつ積み上がった。
「導入手順でスワーム化した」わけではない
していない。「スワームを構築する」という工程・成果物はどこにも存在しない。傍証:
- orchestrator.py は 66 commit のうち約 74% が issue 番号付き、scheduler.py は 149 commit のうち約 79% が issue 番号付き(開始 2026-02、最新 2026-07 まで継続的に拡張)。
- スワームの各性質(並列・失敗隔離・レート制御・エージェント追加)が、別々の issue(#69 / #281 / #670 / #1980…)に紐づいて別々の時期に入っている。
- 「スワーム化」「マルチエージェント基盤整備」のようにまとめて設計した痕跡の commit は無い。
開発手順の実態は「小さな役割分業コアを置く → 運用で壊れる → issue で1性質ずつ潰す」の反復だ。その反復の副産物として、気づけばスワームの性質を満たしていた。
だから「導入」ではなく「診断」なのだ
この開発史は、本稿の主張をそのまま補強する。trader に「スワーム導入」がタスクとして存在しないのは、そもそもスワームが discrete な導入物ではなく、性質の accretion(沈着)として emergent に出来上がったからだ。issue 駆動で積み上げ終えた性質を、今さら「スワームを導入しよう」と名詞で構えて別名で買い直すのは筋が悪い。
段階モデルは「導入する対象」ではなく、「issue 駆動の property accretion が今どこまで達したかを測る物差し」である——これが、コードの現状(本編)と開発史(本補章)の両面から言える結論だ。
補章2:開始時の plan.md はこう書くべきだった
本編と補章の分析(=スワームは設計ではなく issue 駆動の property accretion で実現された)を逆算すると、開発開始時の plan.md が書くべきだったのは「アーキテクチャの完成形」ではなく「性質の獲得順序と、それを積み上げる方法(method)」だったと言える。
後知恵バイアスを避ける:開始時に foreseeable だったか
まず「開始時点で現実的に書けたこと/書けなかったこと」を分ける。ここを混ぜると単なる後知恵になる。
| 項目 | 開始時に書けたか | 理由 |
|---|---|---|
| degrade-first(1ノード失敗で全体を落とさない) | ✅ 書けた(実際に初回で実装済み) | LLM/subprocess は必ず失敗する。設計原則として自明 |
| 外部境界の障害を”来る前提”で列挙(rate limit / auth 失効 / timeout) | ✅ 書けた | CLI 駆動 LLM システムの構造的必然。#69/#670/#1980 は「予見可能な種類」 |
| maker-checker(別コンテキスト検証) | ✅ 書けた(今も未充足のギャップ) | four-eyes / Reflection は既知原則 |
| evidence-first(BT で測ってから ship) | ✅ 書けた | 実際の文化。方針として最初に宣言する価値 |
| エージェント数(5→9+)・並列粒度・具体 issue | ❌ 書くべきでない | 運用してみないと分からない。pin すると害になる |
結論:plan.md は 完成アーキテクチャを描くのではなく、「守る不変条件 + 獲得すべき性質のチェックリスト + 積み上げの方法 + 未獲得を検知する計器」を宣言すべきだった。
書くべきだった plan.md(骨子)
0. この文書の性格 — 完成形は pin しない。不変条件/性質/方法/計器だけを規定する。
1. Day 1 の設計コア — 最小の役割分業 + degrade-first + 永続化と人間ゲート。
2. 段階的に獲得する性質(受け入れ基準)—
[ ] 並列がネイティブ [ ] 失敗のノード限定 [ ] 外部境界の耐障害性
[ ] 役割ごとのモデル使い分け [ ] maker-checker(別コンテキスト検証)
3. 方法 — issue 駆動で1性質ずつ / evidence-first(BTで測って ship) /
段階モデルは「導入対象」でなく「性質の到達度を測る物差し」。
4. 計器 — 未獲得の性質(例: maker-checker)に「無いと気づける」観測を置く。
5. non-goals — 完成形の事前固定 / 性質を満たすためだけの外部ランタイム導入。
この plan.md が防げたはずの実際の摩耗
- SDK→CLI が1日で逆戻り:§3 の evidence-first(実行モデルを先に検証)があれば避けられた可能性。
- rate limit / auth を運用で踏んでから対処(#69 / #1980):§2 に受け入れ基準として最初から掲げていれば、後手でなく計画的ハードニングにできた。
- maker-checker が今も未充足:§2 のチェックリスト+§4 の計器があれば「無いことに気づける」状態を最初から作れた。
メタ教訓
plan.md に書くべきだったのは「スワームを作る」ではなく「性質を獲得し続ける(そして未獲得の性質に常に気づける計器を置く)」という姿勢そのものだ。これは trader が後に docs/architecture/autonomous-improvement.md に育てた設計原則(完了境界を広く取る/観測と制御を混同しない/maker-checker)を、開始時点で seed しておくことに等しい。
良い plan.md とは完成図ではなく、property checklist + method + 計器の宣言である——これが本稿(コード現状)・補章(開発史)・補章2(あるべき初期計画)の三点から言える最終結論だ。
本稿は、AIエージェント運用の4段階モデル(プロンプト→ループ→スワーム→グラフ)を、実在の自律トレーディングシステムのコードベースと git 履歴に当てて自己診断した記録です。ツール名・製品名は例示であり、特定製品の推奨・非推奨を意図しません。commit 日付・issue 番号は調査時点の履歴に基づきます。