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

Antigravity マルチエージェント設計の実践パターン — 複雑なワークフローを壊れにくく作る

Antigravity でマルチエージェントワークフローを設計する際の実践パターンを解説。オーケストレーター構成・状態管理・エラー回復・デバッグ手法まで、壊れにくいシステムの作り方を具体的に紹介します。

マルチエージェント41Antigravity338ワークフロー設計3エラーハンドリング3状態管理2アーキテクチャ9

Antigravity でシングルエージェントのワークフローを動かし始めると、ある段階で「これ以上は無理だ」と感じる瞬間があります。タスクが複雑になり、コンテキストが膨らみ、エージェントが出力する内容の一貫性が下がってくる。そのとき、マルチエージェント構成に移行するかどうかを判断しなければなりません。

ただし、何でもマルチエージェントにすればよいわけではありません。エージェントを増やすと調整コストが増え、デバッグが難しくなり、壊れ方が複雑になります。マルチエージェント構成に移行すべきタイミングと、移行した後に壊れにくいシステムを作るための設計パターンを順番にご紹介します。


シングルエージェントの限界を認識する

マルチエージェントに移行する前に、本当にシングルエージェントでは限界かを確認してください。多くの場合、適切なプロンプト設計と段階的な処理で解決できます。

移行を検討すべきサインは3つあります。

コンテキストウィンドウの圧迫: 処理する情報量が多く、エージェントの出力品質が中盤から下がり始める。長い処理を途中でリセットしても同じ問題が起きる場合は、そもそも1つのエージェントが処理すべき量を超えています。

責任の混在: 「データ取得→分析→フォーマット→通知」のような異なる性質のタスクを1つのエージェントが担うと、プロンプトが複雑になりすぎて制御しにくくなります。責任を分離すると、それぞれのエージェントの動作が予測しやすくなります。

並列化の必要性: 独立したサブタスクを順番に処理するより、並列実行したほうが明らかに速い。かつ、待ち時間がユーザー体験に影響している場合。

逆に言えば、これらに当てはまらないなら、まずシングルエージェントを磨くべきです。


オーケストレーター・ワーカーパターン

最も基本的なマルチエージェント構成です。1つの「オーケストレーター」が全体の計画を立て、「ワーカー」エージェントに具体的なタスクを委任します。

// オーケストレーターの擬似コード(Antigravity ワークフロー)
const orchestrator = {
  name: "research_orchestrator",
  prompt: `
    あなたはリサーチプロジェクトのオーケストレーターです。
    ユーザーのリクエストを受け取り、以下のワーカーに適切なタスクを割り当ててください。
    
    利用可能なワーカー:
    - web_researcher: ウェブ検索と情報収集
    - data_analyzer: 収集データの分析と構造化
    - report_writer: 最終レポートの作成
    
    タスクの割り当ては JSON で返してください:
    {
      "tasks": [
        { "worker": "web_researcher", "task": "...", "priority": 1 },
        { "worker": "data_analyzer", "task": "...", "priority": 2 }
      ]
    }
  `
};

このパターンの重要なポイントは、オーケストレーターが具体的な処理を一切行わないことです。オーケストレーターは「何を誰に頼むか」だけを決める。実際の処理はすべてワーカーが担います。

オーケストレーターに実処理を混ぜると、責任が曖昧になり、デバッグが難しくなります。


状態管理: マルチエージェントの最大の落とし穴

マルチエージェントシステムで一番問題になるのは状態管理です。エージェントAが生成した中間結果をエージェントBが使い、その結果をエージェントCが参照する — このチェーンのどこかで状態が壊れると、最終出力が静かに間違います。

Antigravity でワークフローを設計する際に、私が使っているパターンを紹介します。

イミュータブルな中間状態

各エージェントの出力は上書きせず、ステップごとに保存します。

// NG: 状態を上書きする
workflow.state.data = await researcher.run(query);
workflow.state.data = await analyzer.run(workflow.state.data); // 元データが消える
 
// OK: ステップごとに保存
workflow.state.research_results = await researcher.run(query);
workflow.state.analysis_results = await analyzer.run(workflow.state.research_results);

この設計だと、後から「どのエージェントが何を入力として受け取り、何を出力したか」が追跡できます。バグが発生したときの診断が格段に楽になります。

バリデーション層の挿入

エージェント間のデータ受け渡しには、必ずバリデーションを入れます。

const researchOutput = await researcher.run(query);
 
// バリデーション
if (\!researchOutput.sources || researchOutput.sources.length === 0) {
  throw new WorkflowError(
    "researcher_output_invalid",
    "sources が空です。クエリを調整して再試行してください",
    { query, output: researchOutput }
  );
}
 
const analysisInput = {
  sources: researchOutput.sources,
  context: researchOutput.summary,
};

バリデーションなしでデータを流すと、エラーが何ステップも後になって発生し、根本原因の特定が難しくなります。


エラー回復設計

マルチエージェントシステムでは、「どのエージェントがどんな理由で失敗したか」によって回復戦略が変わります。一律に「リトライ」するのではなく、失敗の性質に応じた戦略を持つ点が肝心です。

async function runWithRecovery(agent, input, options = {}) {
  const {
    maxRetries = 3,
    retryDelay = 1000,
    fallbackAgent = null,
    onFailure = null,
  } = options;
 
  let lastError;
  
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await agent.run(input);
    } catch (error) {
      lastError = error;
      
      // リトライ不要なエラー(入力が間違っている場合など)
      if (error.type === "invalid_input") {
        break;
      }
      
      // レート制限は待機してリトライ
      if (error.type === "rate_limit") {
        await sleep(retryDelay * attempt * 2);
        continue;
      }
      
      // それ以外は通常のリトライ
      if (attempt < maxRetries) {
        await sleep(retryDelay * attempt);
      }
    }
  }
  
  // フォールバックエージェントが設定されていれば試みる
  if (fallbackAgent) {
    try {
      return await fallbackAgent.run(input);
    } catch (fallbackError) {
      // フォールバックも失敗
    }
  }
  
  // カスタム失敗ハンドラー
  if (onFailure) {
    return onFailure(lastError, input);
  }
  
  throw lastError;
}

フォールバックエージェントの設計は特に有効です。例えば、高精度だが遅いエージェントと、精度は低いが速いエージェントのペアを用意しておき、タイムアウト時に後者に切り替えるパターンは実際のプロダクションで効果的でした。


並列実行と同期

独立したサブタスクを並列実行する場合、結果の統合方法を事前に決めておく必要があります。

// 並列実行の基本パターン
async function runParallelResearch(topics) {
  const tasks = topics.map(topic => ({
    id: topic.id,
    promise: runWithRecovery(
      researchAgent,
      { topic: topic.query },
      { maxRetries: 2, fallbackAgent: lightResearchAgent }
    )
  }));
 
  // allSettled で部分的な失敗を許容する
  const results = await Promise.allSettled(
    tasks.map(t => t.promise)
  );
 
  const successful = [];
  const failed = [];
 
  results.forEach((result, index) => {
    if (result.status === "fulfilled") {
      successful.push({ id: tasks[index].id, data: result.value });
    } else {
      failed.push({ id: tasks[index].id, error: result.reason });
    }
  });
 
  // 最低限の成功数を確認
  if (successful.length < Math.ceil(topics.length * 0.7)) {
    throw new WorkflowError(
      "insufficient_results",
      `並列処理で十分な結果が得られませんでした(成功: ${successful.length}/${topics.length})`
    );
  }
 
  return { successful, failed };
}

Promise.all ではなく Promise.allSettled を使う理由は、1つの失敗で全体を止めないためです。実際の並列リサーチワークフローでは、10トピック中1〜2トピックが失敗しても残りを使って続行できる方が、全件成功を要求するより実用的です。


デバッグ: マルチエージェント特有の問題

マルチエージェントシステムのバグには特有のパターンがあります。

「静かな劣化」問題: 出力が完全に壊れているわけではなく、じわじわと品質が下がる。特定のエージェントがコンテキストを誤解していても、後段のエージェントがある程度補正するため気づきにくい。

診断方法: 各エージェントの入出力を個別にログに記録し、期待する出力形式との差異を計測します。品質メトリクスを1〜2個設定して追跡すると、どのエージェントで劣化が始まるかが特定できます。

「非決定的な失敗」問題: 同じ入力でも5回中1回失敗します。並列実行やタイムアウト絡みの問題によく見られます。

診断方法: 同じ入力で10〜20回実行し、失敗率とタイミングを記録します。特定の条件(負荷が高いとき、特定の入力パターンなど)で失敗率が上がるなら、その条件を絞り込みます。

「コンテキスト汚染」問題: 前のワークフロー実行の状態が次の実行に影響します。特にステートフルなエージェントを使っているときに起きます。

診断方法: ワークフロー開始時に状態を完全にリセットしているか確認します。テストでは、意図的に「汚染された状態」から始めて、期待通りにリセットされるかを検証します。


設計のまとめ

Antigravity でマルチエージェントシステムを作るときに、私が戻ってくる原則が3つあります。

  1. 責任の境界を明確に: オーケストレーターは計画のみ、ワーカーは実行のみ。混ぜありません。

  2. 状態は追跡可能に: 中間状態を上書きしありません。バリデーションをエージェント間の境界に入れる。

  3. 失敗を前提に設計する: リトライ・フォールバック・部分的な成功の許容を最初から組み込む。後から追加するのは難しい。

複雑なワークフローを壊れにくく保つことが、マルチエージェント設計の核心です。エージェントの数を増やすより、それぞれのエージェントの責任を明確にする方が、長期的に管理しやすいシステムになります。

さらに踏み込んだ内容 — 動的なエージェント生成、ワークフローの自己修復、プロダクション監視の設計 — は Antigravity Lab のメンバーシップ記事で扱っています。興味があればぜひご覧ください。

シェア

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

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

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

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

関連記事

Agents & Manager2026-07-12
A2A のタスクが working のまま静かに滞留していたとき — 状態遷移を計測して詰まりを名指しする運用メモ
Antigravity の A2A 連携は、エラーで落ちるより「タスクが working のまま進まない」形で静かに詰まります。状態遷移を一本の時系列として記録し、滞留したタスクをどのエージェントのどの辺で止まったかまで名指しする監視の実装を、運用の実感とあわせて整理します。
Agents & Manager2026-07-06
並列エージェントが同じタスクを二度実行して請求が膨らんでいたとき — 重複を計測して止める運用メモ
並列エージェントの請求が想定の約1.9倍に膨らんでいたのは、複数のワーカーが同じタスクを二重に実行していたからでした。重複を計測し、冪等キーで先取り予約し、コストをタスク単位に帰属させるまでの運用記録です。
Agents & Manager2026-06-18
並列エージェントが同じファイルに書き込むときの取り合いを防ぐ
Antigravity 2.0 で複数エージェントを同時に走らせると、同じファイルへの書き込みが衝突して片方の変更が消えることがあります。共有ワークスペースでの書き込み調停を設計します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →