ANTIGRAVITY LABEN
記事一覧/Agents & Manager
Agents & Manager/2026-05-04上級

AIエージェントのオーケストレーション設計 — タスク分解・ハンドオフ・ループ制御の実践

AIエージェントを実際に動かすと直面する設計課題を整理します。タスク分解の粒度、サブエージェントへの引き渡し方、ループ終了条件の設計まで実践的に解説します。

AIエージェント36オーケストレーション7マルチエージェント41設計パターン5自律実行4

AIエージェントを作り始めると、最初にぶつかる壁は「プロンプトの書き方」ではありません。「どこまでを一つのエージェントに任せるか」という設計の問題です。

私が最初に作ったエージェントは、Web調査・要約・レポート生成の三つの責務を一つに詰め込んでいました。動くには動くのですが、途中でコンテキストが詰まり、後半になるほど応答の質が落ちる。リトライしても同じ問題が繰り返される。この体験が、オーケストレーション設計を真剣に考えるきっかけになりました。

タスク分解の粒度をどう決めるか

エージェントを分割するかどうかの判断は、コンテキストウィンドウの消費量と処理の独立性の二軸で考えると整理しやすいです。

コンテキストが重い処理は分ける。大量のドキュメントを読み込んで要約する、コードベース全体を解析してバグを探す — こうした処理を他の作業と同一のエージェントでやらせると、コンテキストが汚染されて後続の判断がずれてきます。「この処理が終わった後、コンテキストはどう見えるか」を想像するのが有効です。

独立して実行できる処理は並列化する。三つのサービスへのAPIコールが結果を互いに参照しないなら、順番に実行する理由はありません。Anthropic の Claude Agent SDK では asyncio.gather() でサブエージェントを並列実行できます。

import asyncio
from anthropic import Anthropic
 
client = Anthropic()
 
async def run_agent(task: str, context: str) -> str:
    """単一タスクを実行するサブエージェント"""
    response = client.messages.create(
        model="claude-opus-4-6",
        max_tokens=2048,
        system="あなたは与えられたタスクを完結させる専門エージェントです。",
        messages=[{"role": "user", "content": f"コンテキスト: {context}
 
タスク: {task}"}]
    )
    return response.content[0].text
 
async def parallel_research(topics: list[str], shared_context: str) -> list[str]:
    """複数トピックを並列調査"""
    tasks = [run_agent(f"{topic}について調査してまとめて", shared_context) for topic in topics]
    return await asyncio.gather(*tasks)

公式ドキュメントには書かれていませんが、実際に並列実行すると API レートリミットに頻繁にぶつかります。asyncio.Semaphore で同時実行数を 3〜5 に制限するのが現実的な落としどころです。

サブエージェントへのハンドオフ設計

オーケストレーターがサブエージェントに仕事を渡すとき、何を渡して何を渡さないかが重要です。

渡すべき情報: 目的(Why)、現在の状態(What is known)、完了条件(Definition of Done)、失敗時の対応方針。

渡してはいけない情報: オーケストレーター自身の思考過程、他のサブエージェントへの指示内容(干渉の原因になる)、過去の失敗ログの全文(必要なエッセンスだけ渡す)。

def create_handoff_context(
    goal: str,
    current_state: dict,
    success_criteria: str,
    failure_policy: str = "report and stop"
) -> str:
    """サブエージェントへの引き渡しコンテキストを構造化する"""
    return f"""
## あなたのミッション
{goal}
 
## 現在わかっていること
{json.dumps(current_state, ensure_ascii=False, indent=2)}
 
## 完了条件
{success_criteria}
 
## 失敗時の対応
{failure_policy}
"""

この構造を使い始めてから、サブエージェントの応答が「指示の解釈で悩む」ではなく「作業に集中する」ものに変わりました。

ループ制御と終了条件の設計

エージェントループで最も危険なのは「無限ループ」ではなく「終わっていないのに終了したと判断するループ」です。

ループの終了条件は、エージェント自身の判断に完全に委ねない設計にするべきです。次の三層で管理するのが効果的です。

class AgentLoop:
    def __init__(self, max_iterations: int = 10, timeout_seconds: int = 300):
        self.max_iterations = max_iterations
        self.timeout_seconds = timeout_seconds
        self.iteration = 0
        self.start_time = None
 
    def should_continue(self, agent_says_done: bool, result: dict) -> bool:
        """三層の終了判定"""
        # Layer 1: ハードリミット(最優先)
        if self.iteration >= self.max_iterations:
            return False
        import time
        if time.time() - self.start_time > self.timeout_seconds:
            return False
        # Layer 2: エージェントの自己申告
        if agent_says_done:
            # Layer 3: 結果の検証(自己申告を鵜呑みにしない)
            return not self._validate_completion(result)
        return True
 
    def _validate_completion(self, result: dict) -> bool:
        """完了条件を独立して検証する"""
        required_keys = ["summary", "confidence", "next_actions"]
        return all(k in result and result[k] for k in required_keys)

実際の経験から言うと、max_iterations=10 でほとんどのタスクは十分です。それ以上かかるタスクは、タスク分解が不十分なサインであることが多いです。

エラーハンドリングのパターン

エージェントのエラーは大きく三種類に分かれます。

一時的エラー(APIタイムアウト、レートリミット): 指数バックオフでリトライ。最大3回、それ以上は上位エージェントに報告。

ツール実行エラー(ファイルが存在しない、権限不足): ツールの呼び出し方を変えてリトライ。同じエラーが2回続いたら上位に委譲。

論理エラー(タスクが完了条件を満たせない): リトライしても意味がありません。エラーの内容を構造化して上位エージェントが判断できる形で返す。

from enum import Enum
 
class ErrorType(Enum):
    TRANSIENT = "transient"    # リトライ可能
    TOOL = "tool"              # ツール変更でリトライ
    LOGIC = "logic"            # エスカレーション
 
def classify_error(error: Exception) -> ErrorType:
    error_str = str(error).lower()
    if "timeout" in error_str or "rate limit" in error_str:
        return ErrorType.TRANSIENT
    if "not found" in error_str or "permission" in error_str:
        return ErrorType.TOOL
    return ErrorType.LOGIC

実際に動かした構成

私が個人開発で使っている「コンテンツ生成エージェント」の構成を簡略化して紹介します。

オーケストレーター → リサーチエージェント(並列3件)→ 構成提案エージェント → 執筆エージェント → 品質チェックエージェント

この連鎖で重要なのは、各エージェントが「自分のアウトプットを次のエージェントが使いやすい形で返す」意識を持たせることです。そのために、各エージェントのシステムプロンプトに出力フォーマットを JSON スキーマで明示しています。

最初の一歩としては、二段階構成(リサーチャー + ライター)から始めることをお勧めします。シンプルな構成でも、一つのエージェントに全部やらせるより明確に品質が上がります。その体験を積んでから、段階的に複雑さを追加していくのが遠回りに見えて実は一番の近道です。

シェア

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

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Agents & Manager2026-05-03
AIエージェントの品質を「仕組み」で保証する — 自律実行が崩れる瞬間と対処法
AIエージェントの自律実行は時間とともに品質が劣化します。崩れる瞬間を数値で捉え、多段検証ゲートと失敗辞典で自己修復させる設計を、4サイトを複数エージェントで運用してきた実体験から具体的に解説します。
Agents & Manager2026-03-30
AgentKit 2.0 本番プロジェクト設計パターン — 16エージェントを戦略的に活用する実践アーキテクチャ
AgentKit 2.0の16専門エージェント、40以上のスキル、11コマンドを本番環境で活用するための完全設計ガイド。階層委任、パイプライン、ファンアウト等5つのオーケストレーションパターン、AGENTS.md によるチーム統一ルール、1Mトークンコンテキスト戦略を実践的に解説。
Agents & Manager2026-06-27
dynamic sub-agents が枝分かれしすぎる前に — 深さ予算とファンアウト上限の設計
Antigravity 2.0 の dynamic sub-agents は実行中に自分でサブエージェントを生やせます。便利ですが、深さとファンアウトを制御しないとトークン予算を一晩で溶かします。3つのガードの実装を具体コードで示します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →