グラフエンジニアリング:1 つのプロンプトから 1,000 個の AI エージェントを並列実行する方法

@0xWast3
英語1 日前 · 2026年7月22日
146K
151
19
13
376

TL;DR

AI エージェントのためのグラフエンジニアリングに関する技術的な深掘り解説。真の依存関係を特定し、並列実行を用いてワークフローをスケールさせる方法を実演します。

2026 年にマルチエージェント システムを構築している人は、今でも直線的な処理を書いています。ステップ 1、次にステップ 2、そしてステップ 3 — それぞれが前のステップを待っています。ここでは、なぜそれが遅いのか、そしてその修正方法を説明します。

wast3 - inline image

誰もチェックしていない問題

あなたはマルチステップ エージェントを構築しました。それは動作します。しかし、遅いです。

あなたはモデルがボトルネックだと思い込んでいます。しかし、そうではありません。

ボトルネックは、あなたが描いた形状です。チェーン — ステップ 1 はステップ 2 を待ち、ステップ 2 はステップ 3 を待つ — は、それらのステップの半分が互いに何の関係もない場合でも、逐次実行を強制します。

「このドキュメントを要約して、天気を確認する」というのは、2 つの独立した仕事が 1 つのワークフローとしてまとめられたものです。天気のタスクは要約を必要としません。これまで一度も必要としたことはありません。しかし、それをチェーンとして書くと、とにかく待つことになります。

この無駄な待ち時間が、数十のステップにわたって増幅され、ランタイムの大部分を消費しているのです。

第1章 - ループ vs グラフ

ループは、自己改善の 1 つの単位です。

text
1何かを試す → 結果を確認する → 調整する → もう一度試す

それが原子です。1 つのエージェント、1 つのメトリクス、収束するまでサイクルします。

ループには既知の障害モードがあります。それは、測定したものだけを最適化し、それ以外は無視することです。チケットを早くクローズするように調整されたサポート ボットは、チケットを早くクローズします — その間、満足度は静かに低下します。ループは自身のメトリクスの外側を見ることができません。これが、エージェント アーキテクチャに現れるグッドハートの法則です。

グラフは設計によってこれを修正します。1 つの数値を追いかける 1 つのループの代わりに、互いに監視し合い、修正し合うループのネットワークを構築します。ノード A の出力はノード B に供給されます。ノード C は独立して実行され、両方をチェックします。システム全体を駆動する単一のメトリクスはありません — 構造が駆動します。

wast3 - inline image

エージェント システムにとって、これは 1 つの具体的なシフトを意味します。すべてを上から下まで行う 1 つのエージェントを書くのをやめることです。最初に作業の形状を設計します — 何が何の前に起こる必要があるか、何を同時に実行できるか、何が実際に待つ必要があるか。

第2章 - ノード、エッジ、そしてそれらを区別するテスト

グラフには正確に 2 つのコンポーネントがあります。

ノード — 1 つの作業単位。1 つのエージェント、1 つのジョブ、1 つの入力、1 つの出力。

エッジ — 実際の依存関係。ノード B の入力にはノード A の出力が必要です。

ほとんどの人が犯す間違いは、デフォルトで「そして」をエッジとして扱うことです。

text
1「このコードベースを読んで、変更ログを書いて」
2「価格ページを取得して、競合他社の機能を要約して」

ワークフロー内のすべての「そして」に対して、1 つの質問をしてください。

次のステップは実際に前のステップの出力を読み取りますか?

はいの場合 → 実際のエッジ。順序を維持します。

いいえの場合 → エッジなし。待機は無駄です。並列実行します。

2 つのタスク間の境界をデータが通過しない場合、それらは独立しています — そして、逐次実行している独立したペアはすべて、無料で捨てているランタイムです。

以下は、コードに適用されたテストです。

python
1from dataclasses import dataclass
2
3@dataclass
4class TaskNode:
5 id: str
6 prompt: str
7 depends_on: list[str] # IDs of nodes this one actually needs
8
9def has_real_edge(node_a: TaskNode, node_b: TaskNode) -> bool:
10 """
11 コア グラフ エンジニアリング テスト:
12 node_b のプロンプトは実際に node_a の出力を必要としますか?
13 """
14 return node_a.id in node_b.depends_on
15
16# 例:ほとんどの「チェーン」は 2〜3 の実際の依存関係グループに集約される
17nodes = [
18 TaskNode("audit_routes", "List all API route files", []),
19 TaskNode("check_auth", "Check auth middleware coverage", []),
20 TaskNode("fetch_weather", "Get today's weather", []),
21 TaskNode("summarize", "Summarize route + auth findings",
22 depends_on=["audit_routes", "check_auth"]),
23]
24
25# audit_routes、check_auth、fetch_weather の間にはエッジがない
26# これらは並列実行される。実際のエッジを持つのは "summarize" だけです -- 待機が発生します。

あなたの現在の「A を実行、次に B、次に C」エージェントは、技術的にはすでにグラフです。それは、可能な限り最悪のグラフ — C が停止すると、下流の何も実行されない単一のチェーン — にすぎません。

第3章 - 最初のグラフを構築する

wast3 - inline image

要件:

  • Claude Code(Dynamic Workflows をサポートする最新バージョン)
  • Max、Team、または Enterprise プラン — ワークフローはデフォルトでオン。Pro の場合は手動で有効化。

実際のリポジトリを開いてください。おもちゃの例ではありません — その効果は実際の規模でのみ現れます。

最初のグラフを開始するプロンプト:

text
1このコードベース内のすべてのルート ファイルを監査するワークフローを作成します。
2
3各ルート ファイルについて、独立してチェックします:
4- 認証ミドルウェアが存在する
5- すべてのパラメータに入力検証がある
6- レート制限が設定されている
7- エラーハンドリングがスタック トレースを漏洩しない
8
9これらのチェックをすべてのルート ファイルにわたって並列実行します —
10互いに依存していません。
11
12すべてのファイルのチェックが完了したら、重要度(critical、warning、info)ごとにグループ化された
131 つの統合レポートを生成します。
14
15統合ステップは、すべてのチェックが完了するのを待つ必要があります。
16その前のすべてのステップは待つべきではありません。

プロンプト自体に埋め込まれた構造に注目してください。並列作業が明示的に呼び出され、唯一の実際の依存関係(すべてのチェックが完了するのを待つ統合)が明示的に名前付けられています。エージェントがグラフを推測することを期待しているのではなく、あなたがそれを説明しているのです。

内部で何が起こっているか — オーケストレーションの簡略版:

python
1import asyncio
2from anthropic import Anthropic
3
4client = Anthropic()
5
6async def audit_route_file(filepath: str) -> dict:
7 """1 つのノード。他のすべてのルート ファイルから独立して実行されます。"""
8 response = await client.messages.create(
9 model="claude-sonnet-5",
10 max_tokens=1000,
11 messages=[{
12 "role": "user",
13 "content": f"""Audit this route file for:
14 - auth middleware, input validation,
15 rate limiting, error handling
16
17 File: {filepath}
18
19 Return JSON: {{"file": "", "issues": [], "severity": ""}}"""
20 }]
21 )
22 return {"file": filepath, "result": response.content[0].text}
23
24async def consolidate(results: list[dict]) -> str:
25 """唯一の実際のエッジ -- すべての監査ノードが完了するのを待ちます。"""
26 response = await client.messages.create(
27 model="claude-opus-4-8",
28 max_tokens=2000,
29 messages=[{
30 "role": "user",
31 "content": f"""Consolidate these {len(results)} route audits
32 into one report grouped by severity:
33
34 {results}"""
35 }]
36 )
37 return response.content[0].text
38
39async def run_graph(route_files: list[str]):
40 # ファンアウト -- すべての独立したノードが並行して実行される
41 audit_tasks = [audit_route_file(f) for f in route_files]
42 results = await asyncio.gather(*audit_tasks)
43
44 # ファンイン -- 実際の依存関係を持つ唯一のノード
45 report = await consolidate(results)
46 return report
47
48# 40 個のルート ファイル、1 つのプロンプト、1 回の並列パス
49results = asyncio.run(run_graph([
50 f"routes/{f}.py" for f in ["auth", "users", "billing", "orders"]
51 # ...36 more

40 回のシーケンシャルな API 呼び出しがそれぞれ約 8 秒かかると、5 分以上になります。同じ 40 回の呼び出しを並列にファンアウトすると、15 秒未満になり、すべての合計時間ではなく、最も遅い単一ファイルによって制限されます。

第4章 - グラフが実際に壊れる場所

グラフ エンジニアリングは、予測可能な 3 つの場所で失敗します。発生する前に知っておきましょう。

コンテキストの崩壊。 1,000 個のノードをファンアウトし、その 1,000 個すべての出力を 1 つの統合ステップにフィードしようとすると、合成が始まる前にコンテキスト ウィンドウを超えてしまいます。

修正方法: ファンインを階層化します。ノードを 20〜50 のバッチにグループ化し、各バッチを要約してから、生の出力ではなく要約を統合します。

python
1async def layered_consolidate(results: list[dict], batch_size: int = 30):
2 """階層的なファンイン -- 大規模な生の出力を合成しないでください。"""
3 batches = [results[i:i+batch_size]
4 for i in range(0, len(results), batch_size)]
5
6 batch_summaries = await asyncio.gather(*[
7 summarize_batch(batch) for batch in batches
8 ])
9
10 # 最終的な統合は、1,000 の生の結果ではなく、要約に対して機能します
11 return await consolidate(batch_summaries)

誤った独立性。 2 つのノードのプロンプトが互いに参照していないため、独立していると想定しますが、両方が同じファイルに書き込んだり、同じレート制限のある API にヒットしたりします。それは隠れたエッジです。

修正方法: 共有データだけでなく、共有リソースも監査します。書き込み競合がある 2 つのノードは、データ依存関係がゼロでもエッジが必要です。

サイレント ノード障害。 チェーンでは、1 つの障害ですべてが停止します — 煩わしいですが明らかです。グラフでは、200 個中の 1 つの障害ノードが、完全に見えるレポートに紛れ込む可能性があります。

修正方法: すべてのファンイン ステップは、合成前にノード数を期待数と照合し、不完全なデータで静かに処理するのではなく、ギャップを明示的にフラグします。

python
1async def safe_consolidate(results: list[dict], expected_count: int):
2 if len(results) < expected_count:
3 missing = expected_count - len(results)
4 print(f"WARNING: {missing} 個のノードがサイレントに失敗しました。"
5 f"レポートは不完全になります。")
6 return await consolidate(results)

第5章 - 実際のフリートへのスケーリング

wast3 - inline image

パターンが 40 ノードで機能すれば、数百へのスケーリングは、第 2 章以降で正しくグラフを構築していれば、再設計ではなく設定変更です。

完全なプロダクション形状:

text
1 オーケストレーター
2 |
3 +--------+-------+-------+--------+
4 v v v v v
5 ノード 1 ノード 2 ノード 3 ... ノード N
6 (並列、相互にエッジなし)
7 | | | |
8 +--------+-------+-------+-------+
9 v
10 バッチ要約 <- 階層的ファンイン
11 (30個ずつのグループ)
12 v
13 最終レポート <- 唯一の真のエッジ

オーケストレーターの唯一の仕事は、タスクをノードに分解し、実際のエッジを特定し、ディスパッチすることです。それ自体は作業を行いません — グラフを描くだけです。

python
1async def orchestrate(task: str, resources: list[str]):
2 """
3 オーケストレーター ノード -- 分解は行うが、実行はしない。
4 """
5 plan = await client.messages.create(
6 model="claude-opus-4-8",
7 max_tokens=2000,
8 messages=[{
9 "role": "user",
10 "content": f"""Task: {task}
11 Resources available: {resources}
12
13 Decompose into a graph:
14 - List each independent node (no shared edges)
15 - List any real dependencies between nodes
16 - Group nodes into fan-in batches if count > 50
17
18 Return JSON with: nodes, edges, batch_groups"""
19 }]
20 )
21
22 graph = parse_plan(plan.content[0].text)
23
24 # 独立したノードを並列実行
25 node_results = await asyncio.gather(*[
26 execute_node(n) for n in graph["nodes"] if not n["depends_on"]
27 ])
28
29 # 次に、実際のエッジのみを尊重して依存ノードを実行
30 final = await execute_dependent_chain(graph["edges"], node_results)
31
32 return final

これが、グラフ エンジニアリングが表す実際のシフトです。あなたはすべてのステップを書く人ではなくなり、依存関係構造を設計する人になります。エージェントがノードを埋めます。あなたはエッジを所有します。

直線ではなくグラフで考えると何が変わるか

40 ステップのリニア エージェントには、40 のシーケンシャルな障害ポイントと、最も遅い単一ステップの 40 倍のレイテンシがあります。

同じ 40 の作業単位を持つグラフには、実際の依存関係の数(通常はほとんどのワークフローで 3〜5)の並列障害ポイントがあり、レイテンシは総ステップ数ではなく、最も遅いレイヤーによって制限されます。

それはわずかな高速化ではありません。5 分かかるワークフローと 15 秒かかるワークフローの違いであり、まったく同じ基盤となる作業を実行しています。

モデルは決してボトルネックではありませんでした。あなたが描いた線がボトルネックだったのです。

これは、2026 年 7 月時点のマルチエージェント オーケストレーション パターンの技術的な内訳です。コード例は説明用です — 大規模にデプロイする前に、エラーハンドリング、レート制限、およびリトライ ロジックを運用環境に合わせて調整してください。

お読みいただきありがとうございます。

YouMindで再制作

Turn one viral article into a full content workflow

Collect the source, decode the pattern, create assets, draft the story, and distribute from one AI workspace.

Explore YouMind
クリエイターのために

あなたの Markdown をきれいな 𝕏 記事に

自分の長文を投稿するとき、画像・表・コードブロックを 𝕏 向けに整形するのは手間がかかります。YouMind は Markdown 全体を、そのまま投稿できるきれいな 𝕏 記事に変換します。

Markdown → 𝕏 を試す

解読すべきパターンをもっと

最近のバイラル記事

バイラル記事をもっと見る