Agent Mentor Learn
ループからグラフへ: エージェントシステムのオーケストレーション工学 · 第 1 回 / 全 6 回

レッスン1: 1つのループでは足りないとき

学習目標:

  • 単一ループのエージェントが壊れる実際のタスクを使い、「もっと大きいウィンドウにすればいい」では形の問題が解けないことを示す
  • ワークフローとエージェントのアーキテクチャ上の区別を述べ、「誰がプランを持つか」で任意のシステムをその軸上に置く
  • 上へ移るためのトリガーと、留まるための条件を列挙し、レイテンシとトークンコストを最初にテーブルへ載せる

前提: このシリーズの最初の11コースを修了し、stop_reason駆動のハーネスループを手書きできること(コース7「エージェントハーネスの基礎: ループと制御」) | 次: レッスン2 >>

モジュール30で、何かがおかしい

バックエンドのリポジトリを、社内RPCフレームワークのv1からv2へ移行することになりました。着手する前にインベントリが必要です。リポジトリには40のモジュールがあり、各モジュールに移行アセスメントが要ります——リスクポイントを列挙し、変更の規模を見積もり、依存マニフェストを添える。難しい作業ではありません、ただ数が多いだけです。手元には、このシリーズのコース7で書いたあのハーネスがあります:

(ハーネスとは、モデル呼び出しを包むホスト側のコードのことです: リクエストを送り、モデルが使いたがったツールを実行し、結果を押し戻し、続けるかどうかを決める。)

40モジュールのリストを一度にまとめて渡し、「1つずつアセスメントして、モジュールごとに1本のレポートを」と書いて、コーヒーを淹れに行きます。

最初の5モジュールは見事です: 呼び出し箇所をgrepで洗い出し、設定を読み、テストファイルを確認し、レポートは期待していたより詳細です。

モジュール15のあたりで戻ってログを確認します。messages配列はすでに壮観です: 最初の14モジュール分のgrep出力、まるごと読み込まれた設定ファイルの塊、ファイル書き込みの成功レシート、いったん進んで放棄された経路の痕跡——それらがまだ全部、同じタイムラインの上に載っています。この内容のどれも間違ってはいませんでした——どれもその時点では必要でした。しかし今の役割は1つに縮んでいます: 場所を取ること。

モジュール30で、品質が崩れます。名前が似ているという理由でモジュール27の結論をモジュール30にコピーし、それまで毎回やっていた「カスタムインターセプタの確認」ステップを黙って飛ばし、モジュール34ではアウトプットのフォーマットまで揺らぎ始めます。

最初に浮かぶ反応は、おそらくこうです: もっと大きいコンテキストウィンドウを持つモデルに切り替える。

その反応は半分までしか連れて行ってくれません。ウィンドウを2倍にすれば、崩壊点はおそらくモジュール30から55へ動きます。次のリポジトリは120モジュールです。問題を解いたのではなく、執行猶予を買っただけです。

実際に尽きているのはウィンドウではなく、「1つのループ」という形です。40の独立したアイテムが、1本のタイムライン、1つの注意予算を無理やり共有させられています。モジュール30のアセスメントの品質が、最初の29モジュールがどれだけ残りかすを残したかに左右される——この2つは互いに何の関係もないのに、です。

このコースがやるのは、その形を取り替えることです。

まず公式の用語を整理する

エージェントは高度なタスクを扱えますが、その実装はしばしば単純です。典型的には、環境からのフィードバックに基づいてループの中でツールを使うLLMにすぎません1。このシリーズのコース7で書いたあのwhileが、まさにそれです、1行も違いません。だから自分の位置を確認しておいてください: あなたはすでにエージェントを作っており、このコースはゼロから始まるわけではありません。

1つ上のレイヤーへ。Anthropicはこれらのバリエーションをすべてエージェント的システム(agentic systems)(平たく言えば、モデル、ツール、そして何らかの制御フローから組み上げられ、自力で複数ステップを歩けるシステム)と分類しますが、この広いカテゴリの内側で、重要なアーキテクチャ上の区別を引きます1:

  • ワークフローとは、LLMとツールが、あらかじめ定義されたコードパスを通じてオーケストレーションされるシステムです1。「あらかじめ定義されたコードパス」がキーフレーズです——次に何が起きるかは、コードに書き込まれています。
  • 一方エージェントとは、LLMが自分自身のプロセスとツールの使い方を動的に方向づけ、タスクをどう達成するかのコントロールを保持しつづけるシステムです1。次に何が起きるかは、モデルがその場で決めます。

これから数レッスンで繰り返し使う、もう1つの基礎的な用語。コンピューティングにおいて、決定的(deterministic)なシステムは同じ入力に対して毎回同じ出力を生みますが、非決定的(non-deterministic)なシステム——エージェントのような——は同じ開始条件からでも異なる応答を生成しえます2

この定義をあなたのwhileに当てはめると、2つのものが縫い合わされているのが見えます: リクエストをどう送るか、ツール呼び出しをどう実行するか、いつ止めるか——これらは決定的で、あなたがコードに書きました。一方「次に何をgrepするか、このレポートは書き終わったか」——これらは非決定的で、モデルがその場で決めます。これから行う手術は、この2つの半分のあいだで決定権を動かすことです。

「誰がプランを持つか」という軸

Claude Codeのドキュメントは、これをもっと直接的に問います: サブエージェント、スキル、エージェントチーム、ワークフローは、どれも複数ステップのタスクを実行できます。違いは、誰がプランを持つかです3

(「サブエージェント」=自分専用のコンテキストウィンドウの中で独立に働き、サマリーだけを返すアシスタント。「ファンアウト」=複数のサブエージェントを同時に働かせるために送り出すこと。どちらの用語もこのシリーズのコース6で扱いました。)

この一文は、似て見える一群のアプローチを切り分けます。「40モジュールのアセスメントを実行する」で見てみましょう:

  • 1つの会話の中で、モデルに40件すべてを進めさせる——プランはモデルの手にあり、しかも暗黙的で、会話履歴の中に隠れています。意図した経路を推測するには、ログを掘るしかありません。
  • モデルをオーケストレーターにして、どのモジュールにどのサブエージェントを送り出すかを毎ターン決めさせる——プランは依然としてモデルの手にあり、少しだけ明示的になっただけです。
  • スクリプトを書き、そのスクリプト自身が40モジュールをforで回す——プランはコードの中にあります。ファイルを開いて最後まで読めますし、明日そのまま同じものを走らせられます。

3つ目のアプローチには正確な記述があります: ワークフローはプランをコードへ移します。ワークフロースクリプト自身がループ、分岐、中間結果を保持するので、Claudeのコンテキストには最終的な答えだけが載ります3。そして中間結果はClaudeのコンテキストに着地せず、スクリプトの変数の中に留まります3。モジュール27のgrep出力はJavaScriptの配列の中に留まるので、モジュール30のアセスメントはそれを見ることが当然できません——モデルが無視することを学んだからではなく、そもそも見る機会が一度もなかったからです。

この軸の両端について、公式のガイダンスはそれぞれ適合性を一文ずつ与えています: より高い複雑さが正当化される場合、ワークフローは明確に定義されたタスクに対して予測可能性と一貫性を提供し、一方エージェントは、柔軟性とモデル主導の意思決定が大規模に必要とされる場面でより良い選択肢になります1

1つはっきりさせておくこと: このコースはこの軸を「決定性スペクトラム」と呼び、レッスン5の合成パターンを「グラフ」「ノード」「エッジ」と呼びます。これらのラベルはこのコース自身のエンジニアリング上の比喩であり、一次情報源には一度も登場しません——一次資料が与えているのは両端の定義(あらかじめ定義されたコードパス vs モデル主導の意思決定)1と、「誰がプランを持つか」というフレーミング3だけです。スペクトラムとグラフという比喩を借りるのは、実在するパターンを並べるのに便利だからです。公式ドキュメントのどこにもこれらの用語は出てこないので、公式の概念として提示しないでください。

上へ移るとき

「1つのループでは足りない」は直感のように聞こえますが、言語化できるトリガーがあります。

トリガー1: タスクが、1つの会話で調整できる以上のエージェントを必要とするとき、あるいはオーケストレーションを、読めて再実行できるスクリプトとしてコード化しておきたいとき3。前半は能力の問題、後半はエンジニアリングの問題です——1つの会話でぎりぎり調整できるとしても、「明日まったく同じように走らせられるか」はそれだけで理由になります。

トリガー2: タスクが、1つのエージェントがコンテキストに保持できるサイズより大きいとき、あるいは同じステップを多数のアイテムにわたって実行する必要があるとき3。この2文が合わさると、冒頭の40モジュールのシナリオそのものを描写します。2つ目の文に注意してください: アイテムの数それ自体が理由であり、各アイテムが難しいかどうかとは関係ありません。

トリガー3: 副次的なタスクがメインの会話を溢れさせてしまうとき。サブエージェントのドキュメントによるシナリオ記述はこうです: 副次的なタスクが、二度と参照しない検索結果、ログ、ファイルの中身でメインの会話を溢れさせてしまうときは、サブエージェントを送り出す——それは自分のコンテキストの中でその仕事をし、サマリーだけを返します4探索と実装をメインの会話の外に置くことで、コンテキストを温存するわけです4。このトリガーが処方しているのが「サブエージェントを送り出す」であることに注意してください——プランは依然としてモデルの手に残ります。それと「プランをコードへ移す」は別のことです。レベル2の演習の列BとCが、この区別を並べて示します。

このコードを見て、形を取り替えたあとがどう見えるかを掴んでください:

ループは相変わらずあのループです——runHarnessLoopの中身は、このシリーズのコース7で書いたあのwhileです。変わったのは1つだけ: 誰が40まで数えるか。以前はモデルが数えていました。今はforが数えます。

留まるとき

トリガーの信号の裏には、同じくらい長い逆向きのチェックリストがあり、こちらのほうが飛ばされやすいものです。

可能な限り最も単純な解を見つけ、必要になったときにだけ複雑さを増やすこと。それは、エージェント的システムをまったく作らないという意味かもしれません1しかし多くのアプリケーションでは、検索とコンテキスト内の例で単一のLLM呼び出しを最適化すれば、たいてい十分です1。関数名を12箇所で変えるあの仕事には、ハーネスも要らず、オーケストレーションも要りません——1回の呼び出しと1回のgrepで終わりです。

今日のマルチエージェントシステムに向かない領域があります: すべてのエージェントが同じコンテキストを共有する必要がある領域や、エージェント間の依存関係が多い領域です。原文は例を1つ挙げています——ほとんどのコーディングタスクは、リサーチよりも本当に並列化できるタスクが少なく、LLMエージェントは他のエージェントへのリアルタイムの調整と委任がまだ得意ではありません5。密結合な注文モジュールをリファクタリングしていて、変更が呼び出し元の連鎖に波及していく——これを5つのサブエージェントへファンアウトしても、遅くなって散らかるだけです。全員が同じものを見る必要があり、誰かが先に動いた瞬間、他の全員の情報が無効になるからです。

逆に、適合する条件も同じくらい率直に述べられています。マルチエージェントシステムが力を発揮するのは、重い並列化を伴い、単一のコンテキストウィンドウを超える情報を扱い、多数の複雑なツールとやり取りするタスクであり5、かつタスクの価値が、向上した性能の対価を払えるほど高いタスクである、と5。この3つの条件に当てはまる数が多いほど、上へ移る価値があります。

自律的なループのまま留めるべきタスクのカテゴリもあり、無理にオーケストレーションへ押し込むべきではありません: 必要なステップ数を予測するのが難しいか不可能で、固定された経路をハードコードできないオープンエンドな問題——これらはエージェントに渡してよく、多くのターンにわたって動く可能性があり、その意思決定をある程度は信頼できなければなりません1。Anthropic自身のリサーチシステムがこのタイプです: リサーチの仕事はオープンエンドな問題を含み、必要なステップを事前に予測するのが非常に難しい。複雑なトピックの探索に固定された経路をハードコードすることはできません、そのプロセスは本質的に動的で経路依存だからです5

つまり「オーケストレーションへ移るべきか」は一方向のプログレスバーではありません。40モジュールのアセスメントがオーケストレーションへ移るべきなのは、ステップが固定されていて数だけが多いからです。「メッセージキューをAからBへ替えるべきか」がオーケストレーションへ移るべきでないのは、何本の記事を読むことになるかすら分からないからです。

コストを先にテーブルへ載せる

5つのパターンを学びはじめる前に、帳簿を開きましょう。

エージェント的システムは、より良いタスク性能と引き換えに、しばしばレイテンシとコストを差し出します。このトレードオフが意味を持つのはどんなときかを検討すべきです1。ここに修辞は一言もありません: これは交換を記述しています。

どれくらい高いのか。Anthropicは自社のデータからの観測を一組出しています: エージェントは典型的にチャットのやり取りより約4×多くのトークンを使い、マルチエージェントシステムはチャットより約15×多くのトークンを使います5。だから彼らの結論はこうです——経済的に成り立たせるには、マルチエージェントシステムは、タスクの価値が向上した性能の対価を払えるほど高いタスクを必要とします5

この数字の文脈に注意してください: 自社のデータから来ており、普遍的なベンチマークではなく、「あらゆるオーケストレーションのアプローチが15×かかる」でもありません。しかし方向ははっきりしています: 「もっと多くのエージェント、もっと多くの並列」へ一歩進むごとに、請求書は一段跳ね上がります。手早く境界線を引いておくと、この倍率はマルチエージェントシステムをチャットと比べたものであって、「プランをコードへ移す」こと自体の値札ではありません——一次資料はオーケストレーションスクリプトの単独のコスト数値を一度も与えていません。40のモジュールが上へ移る価値を持ち、12件のリネームが持たない理由もここにあります——片方が「複雑」で片方が「単純」だからではなく、2週間の手戻りを節約する移行アセスメントなら、このコストを払えるからです。

これからの5つのレッスン

このコースの残りは、いちばん軽い形から始めて、合成へ向かって積み上げていきます:

  • レッスン2: チェイニングとルーティング: タスクを固定されたステップに分け、各ステップのあいだにプログラム的なゲートを置く。分類してから専用のプロンプトへ振り分ける。「プランがコードにある」の最も軽い形です。
  • レッスン3: 並列化: セクショニング(独立したサブタスクに分けて並列に走らせる)と投票(同じタスクを複数回走らせて多様な出力を得る)、そして結果をコードでどう集約するか。
  • レッスン4: オーケストレーター・ワーカー: 中央のLLMが動的にタスクを分解し、ワーカーLLMへ委任し、その結果を統合する。決定的な違いは、サブタスクがあらかじめ定義されていないことです。
  • レッスン5: 評価ループと、パターンをグラフへ合成する: 通過するか、それ以上進まなくなるまでチェック・修正・再チェックを繰り返し、それまでのパターンを縫い合わせる。そのレッスンでもう一度言明します: 「グラフ」はこのコース自身の可視化です。
  • レッスン6: ハンズオン: このシリーズのコース7で書いたあの単一ループのハーネスを、決定的なオーケストレーションスクリプトへ引き上げます。

このパターン分類は2024年の遺物ではありません: 現在のClaudeプラットフォームのマルチエージェントオーケストレーションのドキュメントも、独立に**並列化(独立したサブタスクを同時にファンアウトし、コーディネーターが結果を統合する)、専門化(ドメインに絞ったシステムプロンプトとツールを持つエージェントへルーティングする)、エスカレーション(複雑なサブタスクの一部について、より能力の高いエージェントやモデルに相談する)**を名指ししています6。皮は変わりましたが、骨格は同じです。

このコースが直前の2つとどう分かれるかについて、もう1つ。このシリーズのコース2はワークフローの概念を教えました——ステップ、状態、分岐、図のレベルでの理解。このシリーズのコース6はマルチエージェント協調の分業とコミュニケーションを教えました——ファンアウト、委任プロンプトが自己完結していること、プロデューサー・レビュアー。このコースはそのどちらも教え直しません。扱うのは制御フローそのものです: 誰が数えるのか、誰が分岐するのか、中間結果はどこへ行くのか、落ちたら何が起きるのか。手早い用語の橋渡し: このシリーズのコース6が「プロデューサー・レビュアー」と呼んだものを、一次資料はエバリュエーター・オプティマイザーと呼び1、Claude Codeのワークフローのドキュメントは独立したエージェント同士に互いの発見を敵対的にレビューさせることと呼びます3

相応性: すべては「測定可能な改善」を通過しなければならない

このコースは5つのパターンと、いくつもの合成方法を教えます。それらはすべて同じ但し書きを共有していて、原文は曖昧さがありません: これらのビルディングブロックは規範ではありません。開発者がそれぞれのユースケースに合わせて形づくり、組み合わせられる、よくあるパターンです。成功の鍵は、どんなLLM機能とも同じく、性能を測定し、実装を反復することです。繰り返します: 複雑さを足すのは、それが結果を明白に改善するときだけにすべきです1

「結果を明白に改善する」には具体的な裏付けが要ります。それを与えるのが、このシリーズのコース10の評価と、コース11の可観測性です: 評価セットがなければ、「ルーティングを足して本当に良くなったのか」をはっきり言えません。あの規範的テキストの結びは、この順序に従っています: 単純なプロンプトから始め、包括的な評価でそれを最適化し、より単純な解では足りないときにだけ、複数ステップのエージェント的システムを足すこと1

だから、各パターンを学び終えるたびに自分に問いかけてください: それを足したあとで結果が良くなったと示す数字を、自分は出せるか? 出せないなら、まだ足さないでください。

💻 演習

まとめ

  • このシリーズのコース7で書いたあのwhileはエージェントです——エージェントは高度なタスクを扱えますが、その実装はしばしば単純で、典型的には環境からのフィードバックに基づいてループの中でツールを使うLLMにすぎません1
  • これらのバリエーションはまとめてエージェント的システムと呼ばれ、その内側でアーキテクチャ上の区別が引かれます: ワークフローはLLMとツールがあらかじめ定義されたコードパスを通じてオーケストレーションされるシステム、エージェントはLLMが自分自身のプロセスとツールの使い方を動的に方向づけ、タスクをどう達成するかのコントロールを保持するシステムです1
  • その2つを分ける軸が「誰がプランを持つか」です: ワークフローはプランをコードへ移し、スクリプト自身がループ、分岐、中間結果を保持するので、Claudeのコンテキストには最終的な答えだけが載ります3。このコースはこの軸を「決定性スペクトラム」と呼び、レッスン5の合成の可視化を「グラフ」と呼びますが、どちらの用語もこのコース自身の比喩であり、一次資料には登場しません。
  • 上へ移るトリガー: タスクが、1つの会話で調整できる以上のエージェントを必要とするとき、あるいはオーケストレーションを、読めて再実行できるスクリプトとしてコード化しておきたいとき3。タスクが1つのエージェントがコンテキストに保持できるサイズより大きいとき、あるいは同じステップを多数のアイテムにわたって実行する必要があるとき3。副次的なタスクが、二度と参照しない中身でメインの会話を溢れさせてしまうとき4
  • 留まる条件: 可能な限り最も単純な解を見つけ、必要になったときにだけ複雑さを足すこと、それはエージェント的システムをまったく作らないという意味かもしれない1。多くのアプリケーションでは、検索とコンテキスト内の例で単一のLLM呼び出しを最適化すれば、たいてい十分1。共有コンテキストを必要とする領域やエージェント間の依存が多い領域は今日マルチエージェントに向かず、ほとんどのコーディングタスクはリサーチよりも本当に並列化できるタスクが少ない5
  • 自律的なループのまま留めるもの: オープンエンドな問題で、ステップ数を予測するのが難しく、固定された経路をハードコードできないもの1——リサーチ型の仕事が典型で、そのプロセスは本質的に動的で経路依存です5
  • 請求書を先に見ること: エージェント的システムは、より良いタスク性能と引き換えに、しばしばレイテンシとコストを差し出します1。自社データでは、エージェントはチャットより約4×、マルチエージェントは約15×多くのトークンを使い、経済的に成り立たせるにはタスクの価値がその向上を支えられる必要があります5
  • このコースが教えることはすべて同じゲートを通らなければなりません: 複雑さを足すのは、それが結果を明白に改善するときだけ1。単純なプロンプトから始め、包括的な評価でそれを最適化し、より単純な解では足りないときにだけ、複数ステップのエージェント的システムを足すこと1

>> レッスン2: つなぐ、振り分ける: チェイニングとルーティング

Footnotes

  1. Building Effective AI Agents — Anthropic Engineering — https://www.anthropic.com/engineering/building-effective-agents 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

  2. Writing effective tools for agents — with agents — Anthropic Engineering — https://www.anthropic.com/engineering/writing-tools-for-agents

  3. Orchestrate subagents at scale with dynamic workflows — Claude Code official documentation — https://code.claude.com/docs/en/workflows 2 3 4 5 6 7 8 9 10

  4. Create custom subagents — Claude Code official documentation — https://code.claude.com/docs/en/sub-agents 2 3

  5. How we built our multi-agent research system — Anthropic Engineering — https://www.anthropic.com/engineering/multi-agent-research-system 2 3 4 5 6 7 8 9

  6. Multiagent orchestration — Claude API documentation (Managed Agents) — https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration

練習

01

コードは不要です。次の5つのタスクそれぞれについて、どの階層に入るかを判断してください:

レベル1: 5つのタスクを3つの階層に振り分ける
  • 単一ループで十分(あるいは1回の呼び出しで足りる。複雑さを足さない)
  • オーケストレーションへ移る(プランをコードへ移す)
  • 自律的なループのまま留める(ステップ数はモデルに決めさせる)

1つ目と3つ目の階層はどちらも1つのループとして走ります。それでも別々に並べているのは、オーケストレーションへ移らない理由が違うからです——片方は仕事が単純すぎて割に合わないから、もう片方は仕事がオープンエンドすぎて分解できないから。階層を判断するとは、理由を判断することです。それぞれの判断には、このレッスンに出てきた具体的な条件を名指しした理由を一文つけてください(同じステップが多数のアイテムにわたって走る/1つのコンテキストより大きい/1つの会話では調整しきれない/ステップ数が予測できず固定経路をハードコードできない/単純なタスクに複雑さは要らない/共有コンテキストと多くの依存を必要とする領域はマルチエージェントに向かない)。「タスクが大きい」「タスクが複雑」で済ませないでください。

  1. リポジトリの40モジュールについて、モジュールごとに移行アセスメントを1本書く。それぞれリスクポイント、規模の見積もり、依存マニフェストを含む。
  2. getUserProfilefetchUserProfileへリネームする。リポジトリ全体で呼び出し箇所は12。
  3. 「メッセージキューをAからBへ替えるべきか」を調査する。情報源のリストは事前に決まっておらず、読みながら進める。
  4. 未処理のカスタマーサポートチケット200件に、それぞれカテゴリのラベルを付ける(カテゴリは全部で8つ)。ラベル付けのルールは1本のドキュメントに書かれている。
  5. 密結合な注文モジュールをリファクタリングする: 3つのクラスを分割し、2つのインターフェースを移し、変更は呼び出し元の連鎖に波及する。
完了基準 · ローカルでチェック
02

コードは不要です。相変わらずあの40モジュールの移行アセスメントで、3つのアプローチがあります:

レベル2: 同じタスク、「誰がプランを持つか」の3バージョン
  • A: 1つの大きなループ — 40モジュールのリストを一度に1つのハーネスループへ渡し、自分で進ませる。
  • B: モデルがオーケストレーターとして1件ずつ送り出す — メインの会話の中で、モデルが毎ターン、どのモジュールにどのサブエージェントを送り出すかを決め、サブエージェントは結果をメインの会話へ返す。
  • C: プランをスクリプトへ書く — スクリプトが40モジュールをforで回し、モジュールごとにきれいなハーネスループを開始する。

この表を埋めてください(クエスチョンマークがあなたの埋める場所です)。3行目が肝心です: モジュール25のところでプロセスがkillされた/セッションが落ちたとき、それぞれのアプローチは何を失いますか?

A: 1つの大きなループB: モデルがオーケストレーターC: プランをスクリプトへ書く
誰がプランを持つか???
中間結果はどこへ着地するか???
モジュール25で落ちたとき何を失うか???
完了基準 · ローカルでチェック