8月15日、Quinton Wallが「Loops and beads: orchestrating AI agents with Postman」と題した記事を公開した。この記事では、AIエージェントのオーケストレーションを「ループ」と「ビーズ」という2つのパターンで実装し、Postmanを使って実際にコードで比較する方法について詳しく紹介されている。
LLMを使ったエージェントの普及が加速するにつれ、「どう動かすか」より「どう組み立てるか」が設計の核心になってきた。単一のプロンプトで完結するタスクが減り、複数のツール呼び出しや外部APIとの連携が絡む複雑なワークフローが増えた結果、オーケストレーション層の設計が品質と性能を大きく左右するようになっている。
筆者のQuinton Wallは、この「組み立て方」として2つのパターンを整理している。ループ(loop)とビーズ(bead)だ。「ビーズ」はやや耳慣れない造語だが、一言で言えば「依存関係を持つ小さな処理単位をグラフとして繋いだもの」で、依存関係のないビーズは並列実行される点が最大の特徴だ。
ループとビーズ:何が違うのか
ループエージェントは、モデルとの1本の会話を「終わった」とモデルが判断するまで続ける構造だ。ツールの定義を渡し、モデルがツール呼び出しを要求するたびに実行して結果を返す。ClaudeのMessages APIはステートレスなので、毎ターン会話履歴を全部送り直す。いわゆるReActパターン(Reasoning + Acting)で、ほとんどのエージェントフレームワークのデフォルトでもある。
ビーズエージェントは、グラフを事前に定義する構造だ。各ビーズ(bead)は「名前・処理・依存関係」を持つ小さな処理単位で、依存するビーズが完了した時点で実行される。依存関係のないビーズは並列実行される。チャットループよりも、ビルドパイプラインやデータ処理のDAG(有向非巡回グラフ)に近い設計思想だ。
使い分けの基準はシンプルだ。
- ループ:次のステップが前のステップの結果に依存する、会話的・探索的なタスク
- ビーズ:作業の構造が事前にわかっていて、並列実行できるタスクがある場合
同じエージェントを2通りで実装する
Quinton Wallは「このAPIコレクションは健全か?」という問いを題材に、両パターンのコードを書いた。タスクに必要な情報は2つ——Postman Collectionのサマリーと、Postman Monitorの実行結果——で、互いに依存関係はない。
ループ版
ループ版の核心部分は以下だ。モデルがツールを要求するたびに実行して結果を返し、tool_use以外で止まるまで回す。
while True:
response = await anthropic.messages.create(
model=MODEL, max_tokens=1024, tools=TOOLS, messages=messages
)
messages.append({"role": "assistant", "content": response.content})
if response.stop_reason != "tool_use":
break
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = await call_tool(block.name, block.input)
tool_results.append(
{"type": "tool_result", "tool_use_id": block.id, "content": json.dumps(result)}
)
messages.append({"role": "user", "content": tool_results})
シンプルで読みやすい。ただし問題がある。Claudeは一度に一つのことしか要求できないため、コレクションを取得して待ち、それからモニターを実行して待つ。2つの処理は独立しているのに、直列で動く。
ビーズ版
ビーズはシンプルなデータクラスで表現する。
@dataclass
class Bead:
name: str
run: Callable[[dict, dict], Awaitable[Any]]
deps: tuple[str, ...] = ()
グラフランナーは「依存関係が解決済みのビーズ」を層ごとに抽出し、asyncio.gatherで並列実行する。
async def run_graph(beads: list[Bead], context: dict) -> dict[str, Any]:
done: dict[str, Any] = {}
remaining = {b.name: b for b in beads}
while remaining:
ready = [b for b in remaining.values() if all(d in done for d in b.deps)]
if not ready:
raise RuntimeError(f"Unmet bead dependencies: {list(remaining)}")
results = await asyncio.gather(*(b.run(context, done) for b in ready))
for bead, result in zip(ready, results):
done[bead.name] = result
del remaining[bead.name]
return done
このエージェントのグラフは4つのビーズで構成される。
beads = [
Bead("classify_intent", bead_classify_intent),
Bead("fetch_collection", bead_fetch_collection, deps=("classify_intent",)),
Bead("run_monitor", bead_run_monitor, deps=("classify_intent",)),
Bead("build_report", bead_build_report, deps=("fetch_collection", "run_monitor")),
]
classify_intentが最初に動き、質問の意図を高速に判定する(Claude Haikuを使用)。fetch_collectionとrun_monitorはどちらもclassify_intentにしか依存しないため、この2つが並列実行される。最後にbuild_reportが両方の結果をまとめる。4ビーズ・3層構造だ。
実測でどれだけ速いか
スクリプトには--demoフラグがあり、実際のPostman APIキーなしに動作確認できる(コレクション取得に1.2秒、モニター実行に1.8秒の遅延をシミュレート)。
pip install anthropic httpx python-dotenv
echo "ANTHROPIC_API_KEY=sk-ant-..." > .env
python3 postman_loops_and_beads.py --demo --pattern compare
実行結果はこうなる。
=== loop pattern ===
[loop] wall clock: 3.02s
=== beads pattern ===
[beads] wall clock: 1.83s
beads finished faster (loop: 3.02s, beads: 1.83s) because independent beads ran in parallel.
ループの所要時間は2つの遅延の合計(1.2 + 1.8 = 3.0秒)に近い。ビーズの所要時間は2つの遅延の最大値(1.8秒)に近い。独立した処理を並列実行するだけで、この差が生まれる。
実際のPostman APIに対して実行する場合は--demoを外し、.envにPostman APIキーを追加するだけだ。
python3 postman_loops_and_beads.py --pattern beads \
--collection <your_collection_id> --monitor <your_monitor_id>
ビーズのもう一つの利点:再実行の粒度
並列実行以外にも、ビーズには見落とされがちな利点がある。失敗したビーズだけをリトライできる点だ。
ループでセキュリティ監査が途中で失敗した場合、テストも含めて最初からやり直すことになる。ビーズグラフなら失敗したビーズだけを再実行すれば済む。ステップ数が増えるほどこの差は大きくなる。
また、classify_intentの判定次第で特定のビーズをスキップする「条件分岐」も自然に実装できる。分岐ロジックがプロンプトの中に埋まるのではなく、グラフの構造として明示される点も保守性に寄与する。
試し方
git clone https://github.com/quintonwall/loops-and-beads.git
cd loops-and-beads
pip install anthropic httpx python-dotenv
cp .env.example .env # キーを記入
Postman plugin for Claude Codeを使っている場合は、同じメッセージでテストとセキュリティ監査を同時に依頼してみると、どのコマンドが並列に実行されるかを直接確認できる。インストールはこちらから。
詳細はLoops and beads: orchestrating AI agents with Postmanを参照していただきたい。