0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【コンテキストエンジニアリングシリーズ】5)マルチエージェント時代のコンテキストオーケストレーション

Last updated at Posted at 2025-10-12

複数のAIエージェントを協調させ、最大のパフォーマンスを引き出すための実践的アプローチ


📚 この記事の位置づけ

本記事は、コンテキストエンジニアリングシリーズの続編です。

前提知識として、以下の記事を先にお読みいただくことをおすすめします:

本記事では、複数のエージェントを同時に活用する際の設計と実装を扱います。


目次

  1. マルチエージェント時代の到来
  2. なぜ複数のエージェントが必要なのか
  3. マルチエージェントアーキテクチャの基本
  4. コンテキストの受け渡しパターン
  5. 役割分担とコンテキスト分割
  6. 並列処理時のコンテキスト競合
  7. 実践: Claude Code × Cursor 併用戦略
  8. エージェント間の依存関係管理
  9. パフォーマンス最適化戦略
  10. ケーススタディ

マルチエージェント時代の到来

「1人でやるには限界がある」——これは人間だけでなく、AIエージェントにも当てはまります。

複雑なプロジェクトでは、単一のAIエージェントでは限界があります。複数のエージェントを適切に組み合わせることで、より大規模で複雑なタスクに対応できます。本セクションでは、マルチエージェントアーキテクチャの必要性と、その基本的な考え方を解説します。

単一のエージェントで全てを処理しようとすると、コンテキストウィンドウの限界、専門性の分散、並列化の機会損失など、さまざまな問題に直面します。マルチエージェントアプローチは、これらの問題を根本から解決します。

単一エージェントの限界

まず、「なぜ1つのエージェントでは足りないのか?」を理解しましょう。

問題点:

  • ✗ コンテキストウィンドウの限界に到達しやすい
  • ✗ 得意・不得意分野の考慮不足
  • ✗ すべてを一度に処理しようとして品質低下
  • ✗ 並列作業ができない
  • ✗ 特定タスクに最適化できない

マルチエージェントのメリット

1つのエージェントの限界を、複数のエージェントで解決します。

専門特化、並列処理、相互チェック——マルチエージェントは、単なる「数の増加」ではなく、「質的な変化」をもたらします。

メリット:

  • ✓ 各エージェントが専門領域に集中
  • ✓ コンテキストが分散され、効率的に
  • ✓ 並列作業で開発速度向上
  • ✓ タスクごとに最適なツール選択
  • ✓ 役割分担による品質向上

現実のユースケース

シナリオ 従来(単一) マルチエージェント
新機能開発 1エージェントで設計〜実装 設計Agent→実装Agent→テストAgent
バグ修正 1エージェントで原因調査〜修正 調査Agent→修正Agent→検証Agent
リファクタリング 1エージェントで全体改善 分析Agent→実装Agent×N(並列)
ドキュメント作成 コード生成と同時にドキュメント コード完成後にDocumentAgent

なぜ複数のエージェントが必要なのか

「便利だから」ではなく、「必要だから」——マルチエージェントは選択肢ではなく、大規模開発の必然です。

マルチエージェントアプローチが必要となる理由は、コンテキストウィンドウの物理的限界、専門性の分離、並列処理の効率化など、複数の観点があります。それぞれの理由を具体例とともに理解することで、適切なアーキテクチャ設計の指針が得られます。

理由1: コンテキストウィンドウの物理的限界

AIにも「一度に覚えられる量」には限界があります。

最先端のAIモデルでも、コンテキストウィンドウには上限があります。大規模プロジェクトでは、この限界を超えることが日常的です。

単一エージェントのコンテキスト:
┌────────────────────────────────┐
│ プロジェクト全体のコンテキスト │ → 200k tokens
│ + 実装すべき機能の詳細         │ → 50k tokens
│ + テストケース設計             │ → 30k tokens
│ + ドキュメント要件             │ → 20k tokens
│ = 合計 300k tokens            │ ❌ 限界超過
└────────────────────────────────┘

マルチエージェント:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Architecture    │ │ Implementation  │ │ Test            │
│ Agent           │ │ Agent           │ │ Agent           │
│ 100k tokens ✅  │ │ 120k tokens ✅  │ │ 80k tokens ✅   │
└─────────────────┘ └─────────────────┘ └─────────────────┘

理由2: 専門性による品質向上

「何でも屋」より「専門家」——エージェントも同じです。

人間の開発チームと同様に、各エージェントが専門領域に特化することで、全体の品質が向上します。ジェネラリストよりスペシャリストの組み合わせが強いのです。

// ❌ 単一エージェント: すべてを「そこそこ」やる
エージェント: "設計も実装もテストも全部やります"
 結果: すべてが70点

// ✅ マルチエージェント: それぞれが専門性を発揮
設計Agent: "アーキテクチャ設計に特化"  95
実装Agent: "TypeScript実装に特化"  95
テストAgent: "テスト設計に特化"  95
 結果: 全体として高品質

理由3: 並列実行による速度向上

時間は有限です。並列化で、開発速度を2倍、3倍、5倍に。

単一エージェントは逐次処理しかできません。しかし、多くのタスクは独立しており、並列実行が可能です。マルチエージェントは、この機会を最大限に活用します。

効果:

  • 単一エージェント: 2時間20分
  • マルチエージェント: 1時間50分
  • 30分短縮(21%高速化)

理由4: 障害分離とリスク管理

「1つの失敗が全体に影響」を防ぐ——リスク分散の重要性。

AIエージェントも完璧ではありません。ハルシネーションや誤った判断をすることがあります。マルチエージェントでは、相互チェックによってこれらのリスクを最小化できます。

単一エージェント:
エージェントがハルシネーション
↓
すべての成果物が信頼できない 😱

マルチエージェント:
実装Agentがハルシネーション
↓
テストAgentが検出
↓
修正Agent/レビューAgentで対処 ✅

マルチエージェントアーキテクチャの基本

アーキテクチャの選択が、プロジェクトの成否を分けます。

マルチエージェントシステムには、主に3つのアーキテクチャパターンがあります。プロジェクトの性質、チームの規模、タスクの依存関係に応じて、最適なパターンを選択することが重要です。

アーキテクチャパターン

パターンの選択は、料理のレシピ選びに似ています——状況に応じた最適解があります。

パターン1: パイプラインアーキテクチャ(直列型)

ウォーターフォールの現代版——順序が重要なタスクに最適です。

各ステージの出力が次のステージの入力となる、古典的だが強力なパターンです。品質ゲートが重要なプロジェクトに向いています。

特徴:

  • 各ステージの出力が次のステージの入力
  • 順序が明確で管理しやすい
  • 前段の失敗が後段に影響

適用シーン:

  • ウォーターフォール的な開発
  • 品質ゲートが必要な場合
  • 各工程が明確に分離できる場合

コンテキスト設計:

# .ai/multi-agent/pipeline.yml

pipeline:
  - name: design
    agent: Claude Sonnet 4.5
    context:
      - .ai/team/context.md
      - .ai/team/architecture.md
      - requirements.md
    output: design-doc.md
    
  - name: implement
    agent: Claude Code
    context:
      - design-doc.md        # 前段の出力
      - .ai/team/conventions.md
      - existing-codebase
    output: src/**/*.ts
    
  - name: test
    agent: Cursor
    context:
      - src/**/*.ts          # 前段の出力
      - .ai/domains/*/testing.md
    output: tests/**/*.test.ts
    
  - name: review
    agent: Claude Opus 4
    context:
      - src/**/*.ts          # すべての成果物
      - tests/**/*.test.ts
      - .ai/team/quality-gate.md
    output: review-report.md

パターン2: 並列アーキテクチャ(並列型)

スピード重視——独立したタスクを同時に処理します。

依存関係のないタスクを並列実行することで、開発速度を劇的に向上させます。大規模リファクタリングやマイクロサービス開発に最適です。

特徴:

  • 独立したタスクを並列実行
  • 高速化が期待できる
  • 統合時の競合リスク

適用シーン:

  • 大規模リファクタリング
  • 複数の独立した機能開発
  • マイクロサービス開発

コンテキスト設計:

# .ai/multi-agent/parallel.yml

coordinator:
  agent: Claude Sonnet 4.5
  role: タスク分割と統合
  context:
    - .ai/team/context.md
    - requirements.md
  
parallel_agents:
  - name: feature-a
    agent: Claude Code
    context:
      - .ai/domains/auth/context.md
      - coordinator-output/task-a.md
    isolation: high  # 他のAgentと依存なし
    
  - name: feature-b
    agent: Cursor
    context:
      - .ai/domains/payment/context.md
      - coordinator-output/task-b.md
    isolation: high
    
  - name: feature-c
    agent: Claude Code
    context:
      - .ai/domains/notification/context.md
      - coordinator-output/task-c.md
    isolation: high

integrator:
  agent: Claude Opus 4
  role: 統合と競合解決
  context:
    - すべてのAgent出力
    - .ai/team/integration-strategy.md

パターン3: ハイブリッドアーキテクチャ(混合型)

現実のプロジェクトは複雑です——パイプラインと並列の良いとこ取り。

実際のプロジェクト開発では、完全な直列でも完全な並列でもありません。段階によって使い分けるハイブリッドアプローチが最も実用的です。

特徴:

  • パイプラインと並列の組み合わせ
  • 柔軟性が高い
  • 設計が複雑

適用シーン:

  • 実際のプロジェクト開発
  • 最も汎用性が高い

コンテキストの受け渡しパターン

エージェント間でどうやって情報を渡すか?——これがオーケストレーションの核心です。

マルチエージェントシステムでは、エージェント間の情報受け渡しが重要です。適切なパターンを選ぶことで、効率性とトレーサビリティのバランスを取ることができます。

パターン1: ファイルベース受け渡し

最もシンプルで、最も確実な方法です。

ファイルシステムを介してコンテキストを受け渡すこのパターンは、理解しやすく、人間がレビューできるという大きな利点があります。

実装例:

// Step 1: 設計Agentに依頼
// ────────────────────────────────
// プロンプト:
// 「@.ai/team/context.md を読んで、
//  ユーザー認証機能の設計書を.ai/outputs/auth-design.md に出力してください」

// Step 2: 実装Agentに依頼
// ────────────────────────────────
// プロンプト:
// 「@.ai/outputs/auth-design.md に基づいて、
//  src/modules/auth/ に実装してください
//  @.ai/team/conventions.md の規約に従ってください」

// Step 3: テストAgentに依頼
// ────────────────────────────────
// プロンプト:
// 「@src/modules/auth/ の実装に対して、
//  tests/modules/auth/ にテストを書いてください
//  @.ai/outputs/auth-design.md のテストケースを参考に」

メリット:

  • ✓ シンプルで理解しやすい
  • ✓ Gitでバージョン管理できる
  • ✓ 人間が中間成果物をレビュー可能

デメリット:

  • ✗ 手動での受け渡しが必要
  • ✗ ファイル名の命名規則が重要

パターン2: Git Commitベース受け渡し

バージョン管理と受け渡しを同時に——開発者にとって自然な方法です。

Gitのコミットを使ってエージェント間で情報を受け渡すこのパターンは、変更履歴が自動的に記録され、ロールバックも容易です。

実装例:

# Step 1: 設計Agentのコミット
git checkout -b feature/auth-design
# [設計Agentが design.md を生成]
git add .ai/outputs/auth-design.md
git commit -m "design: ユーザー認証機能の設計"
git push origin feature/auth-design

# Step 2: 実装Agentに引き継ぎ
git checkout -b feature/auth-implement
git merge feature/auth-design
# [実装Agentに依頼]
# プロンプト: 「@.ai/outputs/auth-design.md を実装してください」
git add src/modules/auth/
git commit -m "feat: ユーザー認証機能を実装"
git push origin feature/auth-implement

# Step 3: テストAgentに引き継ぎ
git checkout -b feature/auth-test
git merge feature/auth-implement
# [テストAgentに依頼]
git add tests/modules/auth/
git commit -m "test: ユーザー認証のテストを追加"

メリット:

  • ✓ 変更履歴が明確
  • ✓ ロールバックが容易
  • ✓ チームで共有しやすい

デメリット:

  • ✗ Gitの知識が必要
  • ✗ ブランチ管理が複雑化

パターン3: コンテキストメタデータベース受け渡し

高度な管理が必要なプロジェクト向け——依存関係を明示的に管理します。

メタデータを使ってエージェント間の依存関係を管理するこのパターンは、複雑なワークフローでもトレーサビリティを保つことができます。

// .ai/context-registry.json
{
  "sessions": [
    {
      "id": "session-001",
      "agent": "claude-sonnet-4.5",
      "role": "architect",
      "timestamp": "2024-10-12T10:00:00Z",
      "inputs": [
        ".ai/team/context.md",
        "requirements/auth-requirements.md"
      ],
      "outputs": [
        ".ai/outputs/auth-design.md"
      ],
      "summary": "JWT認証の設計を完了。ADR-001を作成",
      "next_agent": "implementation"
    },
    {
      "id": "session-002",
      "agent": "claude-code",
      "role": "implementation",
      "timestamp": "2024-10-12T10:30:00Z",
      "depends_on": ["session-001"],
      "inputs": [
        ".ai/outputs/auth-design.md",
        ".ai/team/conventions.md"
      ],
      "outputs": [
        "src/modules/auth/auth.service.ts",
        "src/modules/auth/auth.controller.ts"
      ],
      "summary": "JWT認証を実装。JWTServiceとAuthControllerを作成"
    }
  ]
}

活用スクリプト:

// .ai/scripts/handoff.ts
import { readFileSync, writeFileSync } from 'fs';

interface Session {
  id: string;
  agent: string;
  role: string;
  depends_on?: string[];
  inputs: string[];
  outputs: string[];
  summary: string;
}

interface ContextRegistry {
  sessions: Session[];
}

// 次のAgentに引き継ぐコンテキストを取得
function getHandoffContext(sessionId: string): string[] {
  const registry: ContextRegistry = JSON.parse(
    readFileSync('.ai/context-registry.json', 'utf-8')
  );
  
  const session = registry.sessions.find(s => s.id === sessionId);
  if (!session) throw new Error(`Session ${sessionId} not found`);
  
  // 依存するセッションの出力も含める
  const contexts = [...session.inputs];
  
  if (session.depends_on) {
    for (const depId of session.depends_on) {
      const depSession = registry.sessions.find(s => s.id === depId);
      if (depSession) {
        contexts.push(...depSession.outputs);
      }
    }
  }
  
  return contexts;
}

// 使用例
const contexts = getHandoffContext('session-002');
console.log('実装Agentに渡すコンテキスト:');
contexts.forEach(c => console.log(`  - ${c}`));

// 出力:
//   - .ai/outputs/auth-design.md
//   - .ai/team/conventions.md

メリット:

  • ✓ 依存関係が明確
  • ✓ 自動化しやすい
  • ✓ トレーサビリティ向上

デメリット:

  • ✗ 初期セットアップが必要
  • ✗ メタデータのメンテナンス

役割分担とコンテキスト分割

「誰が何を担当するか」——明確な役割分担が、混乱を防ぎます。

マルチエージェントシステムでは、各エージェントの役割を明確に定義することが成功の鍵です。責任範囲が曖昧だと、重複や見落としが発生します。人間のチームと同じように、エージェントにも明確な職務記述書が必要です。

Agent役割定義

エージェントの「履歴書」を作りましょう——得意分野、責任範囲、必要なコンテキストを明確化します。

# .ai/multi-agent/roles.yml

agents:
  architect:
    name: "設計Agent"
    model: Claude Sonnet 4.5
    specialty: システム設計、アーキテクチャ決定
    context_size: large
    responsibilities:
      - システム全体のアーキテクチャ設計
      - 技術選定と理由づけ
      - ADR作成
      - インターフェース定義
    context_includes:
      - .ai/team/context.md
      - .ai/team/architecture.md
      - .ai/team/adr/
      - requirements/**
    context_excludes:
      - 実装の詳細
      - 既存コード(概要のみ)
    outputs:
      - .ai/outputs/design-doc.md
      - .ai/team/adr/new-adr.md
    
  implementer:
    name: "実装Agent"
    model: Claude Code
    specialty: コード実装、リファクタリング
    context_size: medium
    responsibilities:
      - 設計に基づいたコード実装
      - 既存コードのリファクタリング
      - エラーハンドリング実装
    context_includes:
      - .ai/outputs/design-doc.md
      - .ai/team/conventions.md
      - src/modules/[relevant]/
      - 関連する既存コード
    context_excludes:
      - 無関係なモジュール
      - テストコード(実装時)
    outputs:
      - src/**/*.ts
    
  tester:
    name: "テストAgent"
    model: Cursor
    specialty: テストケース設計、テストコード実装
    context_size: medium
    responsibilities:
      - テストケース設計
      - 単体テスト実装
      - 統合テスト実装
      - エッジケース検証
    context_includes:
      - .ai/outputs/design-doc.md
      - src/**/*.ts (実装コード)
      - .ai/domains/*/testing.md
    context_excludes:
      - 実装の内部詳細
    outputs:
      - tests/**/*.test.ts
    
  reviewer:
    name: "レビューAgent"
    model: Claude Opus 4
    specialty: コードレビュー、品質検証
    context_size: large
    responsibilities:
      - コード品質チェック
      - セキュリティレビュー
      - パフォーマンスレビュー
      - 設計との整合性確認
    context_includes:
      - .ai/outputs/design-doc.md
      - src/**/*.ts
      - tests/**/*.test.ts
      - .ai/team/quality-gate.md
    context_excludes:
      - なし(全体を見る)
    outputs:
      - .ai/outputs/review-report.md
    
  documenter:
    name: "ドキュメントAgent"
    model: Claude Sonnet 4.5
    specialty: ドキュメント作成、APIドキュメント
    context_size: small
    responsibilities:
      - APIドキュメント作成
      - README更新
      - 技術ドキュメント作成
    context_includes:
      - src/**/*.ts (公開API)
      - .ai/outputs/design-doc.md
      - existing-docs/
    context_excludes:
      - テストコード
      - 実装の内部詳細
    outputs:
      - docs/**/*.md
      - README.md

コンテキスト分割戦略

大きなコンテキストをどう分割するか?——2つのアプローチがあります。

コンテキストの分割方法によって、エージェント間の協調効率が大きく変わります。プロジェクトの構造に合わせて、最適な分割戦略を選びましょう。

水平分割(機能別)

「モジュールごとに担当者を決める」——最も直感的な分割方法です。

認証、決済、通知など、機能モジュールごとにエージェントを割り当てます。依存関係が少ない場合に最適です。

適用例:

// Agent 1: 認証モジュール担当
// コンテキスト:
// - .ai/team/context.md(共通)
// - .ai/domains/auth/context.md(専用)
// - src/modules/auth/(既存コード)

// Agent 2: 決済モジュール担当
// コンテキスト:
// - .ai/team/context.md(共通)
// - .ai/domains/payment/context.md(専用)
// - src/modules/payment/(既存コード)

// Agent 3: 通知モジュール担当
// コンテキスト:
// - .ai/team/context.md(共通)
// - .ai/domains/notification/context.md(専用)
// - src/modules/notification/(既存コード)

垂直分割(レイヤー別)

「レイヤーごとに専門家を配置」——Clean Architectureに最適な分割です。

Controller、Service、Repositoryなど、アーキテクチャのレイヤーごとにエージェントを割り当てます。各レイヤーの専門性を活かせます。

適用例:

// Controller Agent
// コンテキスト:
// - API仕様
// - リクエスト/レスポンス定義
// - バリデーションルール

// Service Agent
// コンテキスト:
// - ビジネスロジック要件
// - ドメインモデル
// - ユースケース

// Repository Agent
// コンテキスト:
// - データアクセスパターン
// - ORM仕様
// - クエリ最適化

// Database Agent
// コンテキスト:
// - スキーマ定義
// - インデックス戦略
// - マイグレーション

並列処理時のコンテキスト競合

並列化の副作用——競合をいかに防ぐかが鍵です。

複数のエージェントが同時に作業すると、必然的に競合が発生します。これは並列処理の宿命ですが、適切な戦略で最小化できます。

競合シナリオ

実際に起こる3つの典型的な競合パターンを理解しましょう。

シナリオ1: ファイル競合

最も頻繁に発生する問題——同じファイルを複数のエージェントが編集してしまいます。

問題:

// Agent 1の変更
export interface User {
  id: string;
  name: string;
  email: string;
}

// Agent 2の変更(同時)
export interface Order {
  id: string;
  userId: string;
  amount: number;
}

// → Gitでマージ競合
解決策1: ファイル分割

競合の根本原因を解決——そもそも競合しない構造にします。

// types/user.ts (Agent 1が担当)
export interface User {
  id: string;
  name: string;
  email: string;
}

// types/order.ts (Agent 2が担当)
export interface Order {
  id: string;
  userId: string;
  amount: number;
}

// types/index.ts(最後に統合)
export * from './user';
export * from './order';
解決策2: オーナーシップ定義

「このファイルは誰の担当?」を明確にします。

ファイルごとにオーナーを決めることで、無秩序な編集を防ぎます。

# .ai/multi-agent/ownership.yml

file_ownership:
  "src/types/user.ts":
    owner: agent-1
    collaborators: []
    
  "src/types/order.ts":
    owner: agent-2
    collaborators: []
    
  "src/types/shared.ts":
    owner: coordinator
    collaborators: [agent-1, agent-2]
    requires_approval: true

シナリオ2: コンテキスト不整合

時間差による認識のズレ——古い情報で作業してしまう問題です。

エージェントA が作業を始めた後にコンテキストが更新されると、エージェントB とで前提が食い違います。

時刻 10:00 - Agent 1が開始
コンテキスト: 認証はセッションベース

時刻 10:30 - 設計変更
決定: 認証をJWTに変更

時刻 11:00 - Agent 2が開始
コンテキスト: 認証はJWTベース

→ Agent 1とAgent 2で前提が異なる!
解決策: コンテキストバージョニング

コンテキストにもバージョン番号——いつの情報を使っているかを明示します。

# .ai/context-versions.yml

version: "2.3.0"
effective_from: "2024-10-12T10:30:00Z"
changes:
  - type: breaking
    description: "認証方式をセッション→JWTに変更"
    affects:
      - auth module
      - api authentication
    migration: |
      既存のセッション関連コードはすべて削除
      JWT実装に置き換え

active_agents:
  - id: agent-1
    started_at: "2024-10-12T10:00:00Z"
    context_version: "2.2.0"  # 古いバージョン
    status: warning
    action_required: "コンテキストを更新してください"
    
  - id: agent-2
    started_at: "2024-10-12T11:00:00Z"
    context_version: "2.3.0"  # 最新バージョン
    status: ok

通知スクリプト:

// .ai/scripts/check-context-version.ts

interface ActiveAgent {
  id: string;
  started_at: string;
  context_version: string;
}

function checkContextVersion() {
  const currentVersion = getCurrentContextVersion();
  const activeAgents = getActiveAgents();
  
  for (const agent of activeAgents) {
    if (agent.context_version !== currentVersion) {
      console.warn(`
⚠️  警告: Agent ${agent.id} が古いコンテキストを使用しています

現在のバージョン: ${currentVersion}
Agent のバージョン: ${agent.context_version}

対処方法:
1. Agent を停止
2. 最新コンテキストを読み込み
3. 作業を再開
      `);
    }
  }
}

シナリオ3: 循環依存

「ニワトリが先か、卵が先か」——実装の順序が決められない問題です。

モジュールAがモジュールBに依存し、モジュールBがモジュールAに依存する——この循環を検出し、解消する必要があります。

問題:

// Agent 1が実装
class UserService {
  // OrderServiceに依存
  async getUserOrders(userId: string) {
    return this.orderService.findByUserId(userId);
  }
}

// Agent 2が実装(同時)
class OrderService {
  // UserServiceに依存
  async createOrder(order: Order) {
    const user = await this.userService.findById(order.userId);
    // ...
  }
}

// → 循環依存発生!
解決策: 依存グラフ管理

依存関係を明示的に管理し、実行順序を決定します。

# .ai/multi-agent/dependencies.yml

modules:
  user-service:
    agent: agent-1
    depends_on: []        # 依存なし(最初に実装)
    provides:
      - UserService
      - User型
    
  order-service:
    agent: agent-2
    depends_on: 
      - user-service      # UserServiceに依存
    provides:
      - OrderService
      - Order型
    wait_for:
      - user-service      # 完了を待つ

execution_order:
  1. user-service (Agent 1)
  2. order-service (Agent 2)

自動検出スクリプト:

// .ai/scripts/detect-circular-deps.ts

function detectCircularDependencies(dependencies: Dependencies): string[] {
  const visited = new Set<string>();
  const recursionStack = new Set<string>();
  const cycles: string[] = [];
  
  function dfs(module: string, path: string[]): void {
    visited.add(module);
    recursionStack.add(module);
    
    const deps = dependencies[module]?.depends_on || [];
    
    for (const dep of deps) {
      if (!visited.has(dep)) {
        dfs(dep, [...path, dep]);
      } else if (recursionStack.has(dep)) {
        // 循環依存を検出
        const cycle = [...path, dep].join('');
        cycles.push(cycle);
      }
    }
    
    recursionStack.delete(module);
  }
  
  Object.keys(dependencies).forEach(module => {
    if (!visited.has(module)) {
      dfs(module, [module]);
    }
  });
  
  return cycles;
}

// 使用例
const cycles = detectCircularDependencies(dependencies);
if (cycles.length > 0) {
  console.error('❌ 循環依存を検出:');
  cycles.forEach(cycle => console.error(`  ${cycle}`));
  process.exit(1);
}

実践: Claude Code × Cursor 併用戦略

現実の開発現場で最も使われている組み合わせ——具体的な使い分けを学びましょう。

Claude CodeとCursorは、それぞれ異なる強みを持つAIツールです。この2つを適切に組み合わせることで、開発効率を最大化できます。

なぜ併用するのか

「適材適所」——各ツールの強みを活かす戦略です。

特徴 Claude Code Cursor
得意分野 アーキテクチャ設計、複雑なロジック UI実装、リアルタイム編集
コンテキスト理解 深い理解、包括的な提案 高速、インクリメンタル
対話性 チャット形式、詳細な説明 インライン、即座のフィードバック
ファイル操作 複数ファイルの一括操作 単一ファイルの細かい編集

併用パターン

3つの実践的なパターンを紹介します。

パターン1: 設計→実装の分業

Claude Codeで大局を設計し、Cursorで詳細を実装——役割分担の王道です。

実践例:

# Step 1: Claude Codeで設計
# ──────────────────────────
$ claude "ユーザー認証機能を設計してください"

Claude Code:
設計書を.ai/outputs/auth-design.mdに出力しました。
主要なインターフェースも定義しました:
- src/modules/auth/interfaces/auth.interface.ts
- src/modules/auth/dto/

# Step 2: Cursorで実装
# ──────────────────────────
# Cursorを開いて、Composer (Cmd+I) で:
"@.ai/outputs/auth-design.md に基づいて、
 src/modules/auth/auth.service.ts を実装してください"

# Step 3: Claude Codeでレビュー
# ──────────────────────────
$ claude "src/modules/auth/ をレビューしてください"

Claude Code:
以下の改善点があります:
1. エラーハンドリングを追加
2. トランザクション処理が必要
...

パターン2: Claude Code で骨格、Cursor で肉付け

Claude Codeで構造を作り、Cursorで実装を埋める——効率的な二段構えです。

// Step 1: Claude Codeが骨格を作成
// ────────────────────────────────

// src/modules/auth/auth.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class AuthService {
  // TODO: Cursorで実装
  async login(email: string, password: string) {
    // 認証ロジックを実装
  }
  
  // TODO: Cursorで実装
  async register(userData: CreateUserDto) {
    // 登録ロジックを実装
  }
  
  // TODO: Cursorで実装
  async validateToken(token: string) {
    // トークン検証ロジックを実装
  }
}

// Step 2: Cursorで各メソッドを実装
// ────────────────────────────────
// Cursorで各メソッドにカーソルを置いて Cmd+K:
// "このメソッドを実装してください"

パターン3: 並行作業

2つのツールを同時に使って、開発速度を最大化します。

依存関係のないタスクは、Claude CodeとCursorで並列実行できます。テスト作成と実装を同時進行することで、時間を節約できます。

実践例:

# ターミナル1: Claude Code
$ claude "認証機能のテストケースを作成してください
         tests/modules/auth/ に配置"

# VS Code: Cursor(同時進行)
# Cmd+I:
# "src/modules/auth/auth.controller.ts を実装"

# Claude Codeがテスト作成中に、
# Cursorは実装を進められる

.claudefiles と .cursorrules の使い分け

それぞれのツールに、適切なコンテキストを渡します。

Claude Codeには大局的なコンテキストを、Cursorには実装の詳細を——役割に応じた情報を提供することで、最適な出力が得られます。

# .claudefiles (Claude Code用)
# ────────────────────────────
# 大局的なコンテキスト
.ai/team/context.md
.ai/team/architecture.md
.ai/team/adr/
README.md

# 設計関連
.ai/outputs/*.md

# テスト戦略
.ai/domains/*/testing.md
// .cursorrules (Cursor用)
// ────────────────────────────
/*
このプロジェクトの実装ガイド:

1. コーディング規約
   - TypeScript strict mode
   - 関数は camelCase
   - ファイルは kebab-case
   
2. 実装パターン
   - Clean Architecture
   - Controller → Service → Repository
   
3. エラーハンドリング
   - カスタムエラークラス使用
   - 必ずtry-catchで囲む
   
4. インポート順序
   1. 外部ライブラリ
   2. 内部モジュール
   3. 型定義

詳細は .ai/team/conventions.md を参照
*/

トラブルシューティング

併用時によく遭遇する問題と、その解決策です。

問題1: 同じファイルを同時編集してしまった

最も頻繁に起こる問題——マージ競合の対処法を知っておきましょう。

# エラー例
error: Your local changes to the following files would be overwritten by merge:
  src/modules/auth/auth.service.ts

# 解決策
# 1. どちらの変更を優先するか判断

# Claude Codeの変更を優先する場合:
$ git checkout --theirs src/modules/auth/auth.service.ts

# Cursorの変更を優先する場合:
$ git checkout --ours src/modules/auth/auth.service.ts

# 2. 両方の変更をマージする場合:
# 手動でマージまたは、新しいClaude Codeセッションで:
$ claude "以下の2つの変更をマージしてください
         - Claude Codeの変更: [変更内容]
         - Cursorの変更: [変更内容]"

問題2: コンテキストの不整合

2つのツールで異なる実装パターンが使われる——一貫性を保つ方法です。

# 症状
Claude CodeとCursorで異なる実装パターンを使用

# 原因
.claudefilesと.cursorrulesの内容が異なる

# 解決策
# .ai/team/conventions.md を信頼できる情報源(Single Source of Truth)とし、
# 両方からそれを参照する

# .claudefiles
.ai/team/conventions.md

# .cursorrules
/*
詳細なコーディング規約は .ai/team/conventions.md を参照してください
*/

エージェント間の依存関係管理

複雑なワークフローを制御する——依存関係の明示化と自動化が鍵です。

エージェントが増えると、「誰が誰を待っているのか」が不明確になります。依存関係を可視化し、実行順序を自動決定する仕組みが必要です。

依存関係グラフの可視化

複雑な依存関係も、グラフにすれば一目瞭然です。

Mermaidなどのツールでワークフローを可視化することで、実行順序の最適化やボトルネックの発見が容易になります。

依存関係定義ファイル

YAMLで宣言的にワークフローを定義——実行エンジンが自動的に順序を決定します。

# .ai/multi-agent/workflow.yml

workflow_name: "完全な機能開発フロー"
version: "1.0.0"

stages:
  - id: design
    name: "設計フェーズ"
    agents:
      - id: architect
        role: architecture
        parallel: false
        dependencies: []
        timeout: 30min
        outputs:
          - .ai/outputs/architecture.md
          - .ai/team/adr/new-feature.md
    
  - id: database
    name: "データベース設計"
    agents:
      - id: db-designer
        role: database
        parallel: false
        dependencies: [architect]
        timeout: 20min
        outputs:
          - src/database/migrations/
          - src/database/schema.prisma
    
  - id: implementation
    name: "並列実装フェーズ"
    agents:
      - id: impl-auth
        role: implementation
        parallel: true
        dependencies: [db-designer]
        timeout: 60min
        context:
          - .ai/domains/auth/
        outputs:
          - src/modules/auth/
      
      - id: impl-payment
        role: implementation
        parallel: true
        dependencies: [db-designer]
        timeout: 60min
        context:
          - .ai/domains/payment/
        outputs:
          - src/modules/payment/
      
      - id: impl-notification
        role: implementation
        parallel: true
        dependencies: [db-designer]
        timeout: 45min
        context:
          - .ai/domains/notification/
        outputs:
          - src/modules/notification/
    
  - id: integration
    name: "統合フェーズ"
    agents:
      - id: integrator
        role: integration
        parallel: false
        dependencies: [impl-auth, impl-payment, impl-notification]
        timeout: 30min
        outputs:
          - src/app.module.ts
          - .ai/outputs/integration-report.md
    
  - id: testing
    name: "テストフェーズ"
    agents:
      - id: tester
        role: testing
        parallel: false
        dependencies: [integrator]
        timeout: 45min
        outputs:
          - tests/**/*.test.ts
    
  - id: review
    name: "レビューフェーズ"
    agents:
      - id: reviewer
        role: review
        parallel: false
        dependencies: [tester]
        timeout: 20min
        outputs:
          - .ai/outputs/review-report.md

error_handling:
  on_failure:
    - notify_developer: true
    - rollback: previous_stage
    - retry: false

ワークフロー実行エンジン

YAMLの定義を実際に実行するエンジン——並列度の最適化も自動で行います。

このエンジンは、依存関係を解析し、並列実行可能なエージェントを自動的に検出して同時実行します。

// .ai/scripts/workflow-engine.ts

import { readFileSync } from 'fs';
import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);

interface Agent {
  id: string;
  role: string;
  parallel: boolean;
  dependencies: string[];
  timeout: string;
  context?: string[];
  outputs: string[];
}

interface Stage {
  id: string;
  name: string;
  agents: Agent[];
}

interface Workflow {
  workflow_name: string;
  version: string;
  stages: Stage[];
}

class WorkflowEngine {
  private workflow: Workflow;
  private completedAgents: Set<string> = new Set();
  
  constructor(workflowPath: string) {
    const content = readFileSync(workflowPath, 'utf-8');
    this.workflow = require('yaml').parse(content);
  }
  
  async execute(): Promise<void> {
    console.log(`🚀 ワークフロー開始: ${this.workflow.workflow_name}`);
    
    for (const stage of this.workflow.stages) {
      await this.executeStage(stage);
    }
    
    console.log('✅ ワークフロー完了');
  }
  
  private async executeStage(stage: Stage): Promise<void> {
    console.log(`\
📋 ステージ: ${stage.name}`);
    
    // 並列実行可能なAgentと不可能なAgentを分離
    const parallelAgents = stage.agents.filter(a => a.parallel);
    const sequentialAgents = stage.agents.filter(a => !a.parallel);
    
    // 非並列Agentを順次実行
    for (const agent of sequentialAgents) {
      await this.executeAgent(agent);
    }
    
    // 並列Agentを同時実行
    if (parallelAgents.length > 0) {
      await Promise.all(
        parallelAgents.map(agent => this.executeAgent(agent))
      );
    }
  }
  
  private async executeAgent(agent: Agent): Promise<void> {
    // 依存関係チェック
    for (const dep of agent.dependencies) {
      if (!this.completedAgents.has(dep)) {
        throw new Error(
          `Agent ${agent.id} depends on ${dep}, but it's not completed yet`
        );
      }
    }
    
    console.log(`  🤖 Agent: ${agent.id} (${agent.role})`);
    
    // コンテキスト準備
    const contexts = agent.context || [];
    const contextArgs = contexts.map(c => `@${c}`).join(' ');
    
    // Agent実行(実際にはClaude Code CLIなどを呼び出し)
    // ここでは疑似コード
    try {
      // const result = await execAsync(
      //   `claude "${agent.role} を実行してください ${contextArgs}"`
      // );
      
      console.log(`    ✅ 完了: ${agent.outputs.join(', ')}`);
      this.completedAgents.add(agent.id);
    } catch (error) {
      console.error(`    ❌ エラー: ${error}`);
      throw error;
    }
  }
}

// 使用例
const engine = new WorkflowEngine('.ai/multi-agent/workflow.yml');
engine.execute().catch(console.error);

パフォーマンス最適化戦略

速さは正義——最適化で、マルチエージェントの真価を発揮します。

マルチエージェントシステムのボトルネックは、主にコンテキストの処理にあります。以下の4つの最適化戦略で、応答速度とスループットを劇的に向上させることができます。

最適化1: コンテキストの段階的読み込み

「全部読み込む」のではなく「必要な分だけ」——段階的ローディングで高速化します。

一度にすべてのコンテキストを読み込むと、トークン数が爆発します。必要なコンテキストだけを段階的に読み込むことで、処理速度が大幅に向上します。

// ❌ Bad: すべてのコンテキストを一度に読み込む
const contexts = [
  '.ai/team/context.md',
  '.ai/team/architecture.md',
  '.ai/team/conventions.md',
  '.ai/team/adr/*.md',
  '.ai/domains/**/context.md',
  'src/**/*.ts',
  // ... 合計 500k tokens 😱
];

// ✅ Good: 必要なコンテキストのみを段階的に読み込む
// Stage 1: 概要のみ
const stage1 = [
  '.ai/team/context.md',  // 50k tokens
];

// Stage 2: 必要に応じて詳細を追加
if (needsArchitecture) {
  contexts.push('.ai/team/architecture.md');  // +30k tokens
}

if (needsConventions) {
  contexts.push('.ai/team/conventions.md');  // +20k tokens
}

// Stage 3: ドメイン固有のコンテキスト
contexts.push(`.ai/domains/${domain}/context.md`);  // +40k tokens

// 合計: 140k tokens ✅

最適化2: コンテキストキャッシング

同じコンテキストを何度も読まない——キャッシュで高速化します。

ファイルの内容が変わっていなければ、毎回読み直す必要はありません。ハッシュベースのキャッシュで、無駄な読み込みを削減します。

// .ai/scripts/context-cache.ts

import { createHash } from 'crypto';
import { readFileSync, writeFileSync, existsSync } from 'fs';

interface CachedContext {
  hash: string;
  content: string;
  timestamp: number;
  token_count: number;
}

class ContextCache {
  private cacheDir = '.ai/cache/';
  
  getCachedContext(filePath: string): string | null {
    const cacheKey = this.getCacheKey(filePath);
    const cachePath = `${this.cacheDir}${cacheKey}.json`;
    
    if (!existsSync(cachePath)) {
      return null;
    }
    
    const cache: CachedContext = JSON.parse(
      readFileSync(cachePath, 'utf-8')
    );
    
    // ファイルが変更されていないかチェック
    const currentHash = this.getFileHash(filePath);
    if (cache.hash !== currentHash) {
      return null;  // キャッシュが古い
    }
    
    // キャッシュの有効期限チェック(24時間)
    const age = Date.now() - cache.timestamp;
    if (age > 24 * 60 * 60 * 1000) {
      return null;
    }
    
    return cache.content;
  }
  
  setCachedContext(filePath: string, content: string): void {
    const cacheKey = this.getCacheKey(filePath);
    const cachePath = `${this.cacheDir}${cacheKey}.json`;
    
    const cache: CachedContext = {
      hash: this.getFileHash(filePath),
      content,
      timestamp: Date.now(),
      token_count: this.estimateTokens(content),
    };
    
    writeFileSync(cachePath, JSON.stringify(cache, null, 2));
  }
  
  private getCacheKey(filePath: string): string {
    return createHash('md5').update(filePath).digest('hex');
  }
  
  private getFileHash(filePath: string): string {
    const content = readFileSync(filePath, 'utf-8');
    return createHash('sha256').update(content).digest('hex');
  }
  
  private estimateTokens(content: string): number {
    // 簡易的なトークン数推定(1トークン ≈ 4文字)
    return Math.ceil(content.length / 4);
  }
}

最適化3: コンテキスト圧縮

重要な情報だけを残す——インテリジェントな要約で、トークン数を削減します。

長いドキュメントは、重要度に基づいて圧縮します。全体を読ませるのではなく、本質的な情報だけを抽出することで、効率を上げます。

// .ai/scripts/context-compressor.ts

class ContextCompressor {
  /**
   * 長いドキュメントを要約して圧縮
   */
  compressLongDocument(content: string, maxTokens: number): string {
    const tokens = this.estimateTokens(content);
    
    if (tokens <= maxTokens) {
      return content;  // 圧縮不要
    }
    
    // セクションごとに分割
    const sections = this.splitIntoSections(content);
    
    // 重要度を計算
    const scored = sections.map(section => ({
      content: section,
      importance: this.calculateImportance(section),
    }));
    
    // 重要度順にソート
    scored.sort((a, b) => b.importance - a.importance);
    
    // maxTokensに収まるまで追加
    let compressed = '';
    let currentTokens = 0;
    
    for (const section of scored) {
      const sectionTokens = this.estimateTokens(section.content);
      if (currentTokens + sectionTokens <= maxTokens) {
        compressed += section.content + '\
\
';
        currentTokens += sectionTokens;
      }
    }
    
    return compressed;
  }
  
  /**
   * 重要度を計算(ヒューリスティック)
   */
  private calculateImportance(section: string): number {
    let score = 0;
    
    // ヘッダーがあると重要
    if (section.startsWith('#')) score += 10;
    
    // コード例があると重要
    if (section.includes('```')) score += 8;
    
    // 「重要」「必須」などのキーワード
    const keywords = ['重要', '必須', 'IMPORTANT', 'CRITICAL'];
    for (const keyword of keywords) {
      if (section.includes(keyword)) score += 5;
    }
    
    // ADRへのリンクがあると重要
    if (section.includes('ADR-')) score += 7;
    
    return score;
  }
  
  private splitIntoSections(content: string): string[] {
    // Markdownのセクション(##)で分割
    return content.split(/\
(?=##)/);
  }
  
  private estimateTokens(content: string): number {
    return Math.ceil(content.length / 4);
  }
}

最適化4: 並列Agent数の動的調整

システムの負荷に応じて、並列数を自動調整——賢いスケジューリングで、リソースを最大活用します。

CPUやメモリの使用率に応じて、並列実行するエージェント数を動的に調整します。負荷が高いときは並列度を下げ、余裕があるときは上げる——この適応的なアプローチで、システムの安定性とスループットを両立します。

// .ai/scripts/adaptive-parallelism.ts

interface SystemResources {
  cpuUsage: number;
  memoryUsage: number;
  activeAgents: number;
}

class AdaptiveParallelism {
  private maxParallelAgents = 5;
  
  /**
   * 現在のシステム負荷に基づいて、
   * 並列実行するAgent数を決定
   */
  determineParallelism(tasks: Agent[]): Agent[][] {
    const resources = this.getSystemResources();
    
    // CPU使用率が高い場合は並列数を減らす
    let parallelCount = this.maxParallelAgents;
    if (resources.cpuUsage > 80) {
      parallelCount = 2;
    } else if (resources.cpuUsage > 60) {
      parallelCount = 3;
    }
    
    // メモリ使用率が高い場合も並列数を減らす
    if (resources.memoryUsage > 80) {
      parallelCount = Math.min(parallelCount, 2);
    }
    
    // タスクをバッチに分割
    const batches: Agent[][] = [];
    for (let i = 0; i < tasks.length; i += parallelCount) {
      batches.push(tasks.slice(i, i + parallelCount));
    }
    
    return batches;
  }
  
  private getSystemResources(): SystemResources {
    // 実際にはOSのメトリクスを取得
    // ここでは疑似コード
    return {
      cpuUsage: 45,
      memoryUsage: 60,
      activeAgents: 2,
    };
  }
}

ケーススタディ

理論は理解した。では、実際のプロジェクトでどう使われているのか?——3つのリアルな事例を見ていきましょう。

これらのケーススタディは、実際のプロジェクトで実践され、成果を上げた事例です。数字とプロセスを通じて、マルチエージェントの威力を実感してください。

ケース1: 大規模リファクタリング

1000ファイルのレガシーコードベース——単一エージェントでは不可能な規模です。

背景:

  • 1000ファイルのレガシーコードベース
  • 1人のエージェントでは数日かかる(現実的ではない)
  • マルチエージェントで高速化を実現

課題: コンテキストウィンドウの限界を超える規模のリファクタリング

アプローチ:

ステップ1: 分析 - 依存関係を解析し、独立して処理できるグループに分割
ステップ2: 並列実行 - 各グループを別々のエージェントで同時処理
ステップ3: 統合 - 結果をマージし、整合性を検証

実装:

// Step 1: 分析Agentでファイルを分類
// ────────────────────────────────
claude "以下のディレクトリを分析して、
       依存関係が少ないファイル群に分類してください
       
       対象: src/
       出力: .ai/outputs/refactor-groups.json"

// 出力例:
{
  "groups": [
    {
      "id": "group-1",
      "files": ["src/utils/string.ts", "src/utils/array.ts", ...],
      "dependencies": [],
      "estimated_time": "30min"
    },
    {
      "id": "group-2",
      "files": ["src/services/user.ts", ...],
      "dependencies": ["group-1"],
      "estimated_time": "45min"
    },
    // ... 全20グループ
  ]
}

// Step 2: 並列実行スクリプト
// ────────────────────────────────
// .ai/scripts/parallel-refactor.ts

async function parallelRefactor() {
  const groups = JSON.parse(
    readFileSync('.ai/outputs/refactor-groups.json', 'utf-8')
  );
  
  // 依存関係順にソート
  const sorted = topologicalSort(groups.groups);
  
  // 並列実行可能なグループをバッチ化
  const batches = createBatches(sorted, 5);  // 5並列
  
  for (const batch of batches) {
    console.log(`並列実行: ${batch.map(g => g.id).join(', ')}`);
    
    await Promise.all(
      batch.map(group => refactorGroup(group))
    );
  }
}

async function refactorGroup(group: Group): Promise<void> {
  // 各グループを個別のAgentで処理
  const contextFiles = [
    '.ai/team/conventions.md',
    '.ai/outputs/refactor-strategy.md',
    ...group.files,
  ];
  
  // Claude Codeで実行
  await execAsync(
    `claude "以下のファイルをリファクタリングしてください ${contextArgs}"`
  );
}

結果:

  • 所要時間: 単一Agent 3日 → マルチAgent 6時間(75%短縮
  • 品質: テストAgentによる検証で品質担保(バグ発生率: 通常の1/3)
  • 並列度: 最大5Agent同時実行
  • 開発者の感想: 「これなしでは、このプロジェクトは不可能だった」

学び: 大規模なタスクは、適切に分割することで、驚くほど高速化できる。


ケース2: マイクロサービス開発

3つのサービスを同時開発——従来は逐次開発だったものを、並列化で3倍速に。

背景:

  • 3つのマイクロサービスを同時開発(Auth、Order、Notification)
  • サービス間の依存関係あり(API契約の共有が必要)
  • チーム3人で分担(各サービスに1人ずつ)

課題: サービス間のインターフェース整合性を保ちながら、並列開発を実現

アーキテクチャ:

実装戦略:

# .ai/multi-agent/microservices.yml

services:
  api-gateway:
    agent: architect-agent
    dependencies: []
    outputs:
      - services/gateway/
      - .ai/outputs/api-contracts.md
    
  auth-service:
    agent: auth-team-agent
    dependencies: [api-gateway]
    context:
      - .ai/outputs/api-contracts.md
      - .ai/domains/auth/
    outputs:
      - services/auth/
    parallel: true
    
  order-service:
    agent: order-team-agent
    dependencies: [api-gateway, auth-service]
    context:
      - .ai/outputs/api-contracts.md
      - .ai/domains/order/
      - services/auth/interfaces/  # 認証インターフェース
    outputs:
      - services/order/
    parallel: true
    
  notification-service:
    agent: notification-team-agent
    dependencies: [api-gateway]
    context:
      - .ai/outputs/api-contracts.md
      - .ai/domains/notification/
    outputs:
      - services/notification/
    parallel: true

成果:

  • Auth ServiceとNotification Serviceは完全並列開発(依存なし)
  • Order Serviceはauth完了後に開始(依存関係を明示的に管理)
  • 3週間で3サービス完成(従来の逐次開発なら9週間)
  • 開発効率: 3倍向上
  • 品質: 統合テストAgentにより、サービス間の整合性を自動検証

学び: API契約を最初に定義することで、サービス間の依存を最小化し、並列開発が可能になる。


ケース3: レガシーシステムのモダナイゼーション

10万行のPHPコードをTypeScriptに——段階的かつ並列的なアプローチで、9週間で完了。

背景:

  • PHP 5.6 → Node.js + TypeScript への全面移行
  • 300ファイル、10万行のコード
  • ビジネスロジックを保ちながら書き換え(仕様変更なし)

課題: 動作を変えずに、技術スタックを完全に入れ替える

戦略:

Phase 1: 分析(2週間) - レガシーコードの構造とビジネスロジックを抽出
Phase 2: 設計(1週間) - モダンなアーキテクチャに再設計
Phase 3: 実装(4週間、並列) - レイヤーごとに異なるエージェントで並列実装
Phase 4: 検証(2週間) - 比較Agentでレガシーと新実装の動作を照合

段階的アプローチ:

// Phase 1: 分析(2週間)
// ────────────────────────
// 分析Agentがレガシーコードを解析
const analysis = {
  businessLogic: [
    {
      file: 'legacy/user_management.php',
      functions: ['createUser', 'updateUser', 'deleteUser'],
      dependencies: ['database.php', 'validation.php'],
      complexity: 'medium'
    },
    // ...
  ],
  dataModels: [...],
  apis: [...]
};

// Phase 2: 設計(1週間)
// ────────────────────────
// 設計AgentがTypeScript設計を作成
const design = {
  architecture: 'Clean Architecture',
  modules: [
    {
      name: 'users',
      layers: ['controller', 'service', 'repository'],
      interfaces: [...]
    }
  ]
};

// Phase 3: 実装(4週間、並列)
// ────────────────────────────
// 3つのAgentが並列実装

// Agent 1: Controllers
await implementControllers(design.modules);

// Agent 2: Services
await implementServices(design.modules);

// Agent 3: Repositories
await implementRepositories(design.modules);

// Phase 4: 検証(2週間)
// ────────────────────────
// テストAgentが動作を比較
const comparison = await compareWithLegacy({
  legacy: 'legacy/',
  modern: 'src/',
  testCases: [...]
});

成果:

  • 期間: 9週間で完了(単一Agentなら6ヶ月予想 → 75%短縮
  • 品質: 比較Agentにより動作の一致を保証(回帰バグゼロ)
  • 学習: 過程でチーム全体がTypeScriptに習熟(副次的効果)
  • ROI: 6ヶ月分の開発コストを節約、リリースも大幅に前倒し

学び: レガシーモダナイゼーションは、分析と設計に時間をかけることで、実装フェーズを大幅に短縮できる。


実践的なワークフロー例

日常的な開発タスクでの活用方法——コピペして使えるテンプレートです。

理論とケーススタディを学んだら、次は実践です。以下のワークフロー例は、そのまま使えるテンプレートとして設計されています。

ワークフロー1: 新機能開発(2日間)

最も一般的なシナリオ——設計からリリースまでの完全なフローです。

# Day 1: 設計と実装
morning:
  - agent: architect
    task: "新機能の設計"
    duration: 2h
    output: design-doc.md
    
  - agent: db-designer
    task: "データベース設計"
    duration: 1h
    depends_on: [architect]
    output: migration.sql

afternoon:
  - agents: [implementer-1, implementer-2, implementer-3]
    task: "並列実装"
    duration: 4h
    parallel: true
    depends_on: [db-designer]
    output: src/modules/new-feature/

# Day 2: テストとレビュー
morning:
  - agent: tester
    task: "テストケース作成・実行"
    duration: 3h
    depends_on: [implementer-1, implementer-2, implementer-3]
    output: tests/new-feature/
    
afternoon:
  - agent: reviewer
    task: "コードレビュー"
    duration: 2h
    depends_on: [tester]
    output: review-report.md
    
  - agent: documenter
    task: "ドキュメント作成"
    duration: 1h
    parallel: true
    depends_on: [implementer-1, implementer-2, implementer-3]
    output: docs/new-feature.md

ワークフロー2: バグ修正(半日)

緊急対応も、体系的なアプローチで素早く解決します。

バグ修正は時間との戦いです。調査、修正、検証を並列化することで、半日で完了できます。

# 午前
morning:
  - agent: investigator
    task: "バグ原因調査"
    duration: 1h
    context:
      - bug-report.md
      - src/**/*.ts
      - logs/
    output: investigation-report.md
    
  - agent: fixer
    task: "修正実装"
    duration: 1.5h
    depends_on: [investigator]
    context:
      - investigation-report.md
      - src/relevant-files/
    output: fixed-code

# 午後
afternoon:
  - agent: tester
    task: "修正の検証"
    duration: 0.5h
    depends_on: [fixer]
    output: test-results
    
  - agent: reviewer
    task: "修正レビュー"
    duration: 0.5h
    depends_on: [tester]
    output: review-approval

ベストプラクティス集

成功するチームと失敗するチームの違いは、細部にあります。

マルチエージェント開発の経験から抽出された、実践的なベストプラクティスです。これらを守ることで、多くの落とし穴を回避できます。

✅ DO: やるべきこと

これらの習慣が、マルチエージェントの成功を決定します。

1. Agent役割を明確に定義

曖昧な役割は、混乱の元——明確な職務記述書を作りましょう。

# ❌ Bad: 曖昧な役割
agent:
  name: "開発Agent"
  role: "なんでもやる"

# ✅ Good: 明確な役割
agent:
  name: "実装Agent"
  role: "TypeScript実装専門"
  responsibilities:
    - 設計書に基づくコード実装
    - エラーハンドリング
    - ユニットテスト実装
  context_size: medium
  context_focus:
    - 実装詳細
    - コーディング規約
  excludes:
    - アーキテクチャ設計
    - インフラ設定

2. コンテキストは最小限に

「全部渡す」のではなく「必要なものだけ」——コンテキストのミニマリズムです。

// ❌ Bad: すべてのコンテキストを渡す
const contexts = [
  '.ai/team/**',
  '.ai/domains/**',
  'src/**',
  'tests/**',
  'docs/**'
];

// ✅ Good: 必要なコンテキストのみ
const contexts = [
  '.ai/team/context.md',         // 最小限の共通知識
  '.ai/domains/auth/context.md', // 担当ドメイン
  'src/modules/auth/**'          // 関連コードのみ
];

3. 依存関係を明示

「暗黙の了解」は通用しません——すべてを明示的に記述します。

# ✅ Good: 依存関係が明確
workflow:
  - id: step-1
    dependencies: []
    
  - id: step-2
    dependencies: [step-1]
    wait_for: step-1  # 完了を待つ
    
  - id: step-3
    dependencies: [step-1]
    parallel_with: [step-2]  # step-2と並列可能

4. 中間成果物を保存

すべての成果物を記録——トレーサビリティが品質を保証します。

// ✅ Good: 各Agentの出力を保存
const outputs = {
  'design-agent': '.ai/outputs/design-{timestamp}.md',
  'impl-agent': 'src/modules/feature/',
  'test-agent': 'tests/modules/feature/',
  'review-agent': '.ai/outputs/review-{timestamp}.md'
};

// すべてGit管理下に置く
// → トレーサビリティ向上
// → ロールバック可能

❌ DON'T: やってはいけないこと

これらのアンチパターンは、プロジェクトを破綻させます。

1. Agent間で状態を共有

グローバル状態は悪——ファイルで明示的に受け渡しましょう。

// ❌ Bad: グローバル状態で共有
global.sharedState = {
  currentUser: {...},
  processedFiles: [...]
};

// ✅ Good: ファイルで受け渡し
// Agent 1
await writeFile('.ai/outputs/processed-files.json', JSON.stringify(files));

// Agent 2
const files = JSON.parse(await readFile('.ai/outputs/processed-files.json'));

2. 無制限な並列実行

「多ければ良い」は間違い——適切な並列度を保ちましょう。

// ❌ Bad: すべてを並列実行
await Promise.all(
  tasks.map(task => executeAgent(task))
);  // 100個のタスク = 100個のAgent 😱

// ✅ Good: 適切な並列数
const batches = chunk(tasks, 5);  // 5並列まで
for (const batch of batches) {
  await Promise.all(
    batch.map(task => executeAgent(task))
  );
}

3. エラーハンドリングなし

エラーは必ず起きます——適切なハンドリングとリトライ戦略が必須です。

// ❌ Bad: エラーを無視
await executeAgent(agent);  // 失敗しても続行

// ✅ Good: 適切なエラーハンドリング
try {
  await executeAgent(agent);
} catch (error) {
  console.error(`Agent ${agent.id} failed:`, error);
  
  // リトライ戦略
  if (error.isRetryable) {
    await retryAgent(agent, { maxRetries: 3 });
  } else {
    // 依存するAgentも停止
    await cancelDependentAgents(agent.id);
    throw error;
  }
}

トラブルシューティング

問題は必ず起きます。重要なのは、素早く解決する方法を知っていることです。

マルチエージェント開発でよく遭遇する3つの典型的な問題と、その解決策を紹介します。これらを知っておくことで、トラブル発生時の対応時間を大幅に短縮できます。

問題1: Agent間でコンテキストが食い違う

最も深刻な問題——認識のズレは、矛盾した実装を生みます。

症状:

Agent A: "認証はJWTです"
Agent B: "認証はセッションです"
→ 実装が矛盾 😱

原因:

  • コンテキストファイルの更新タイミングのズレ
  • 古いコンテキストキャッシュ

解決策:

// .ai/scripts/sync-context.ts

async function syncContextForAllAgents() {
  const currentVersion = await getCurrentContextVersion();
  const activeAgents = await getActiveAgents();
  
  for (const agent of activeAgents) {
    if (agent.contextVersion !== currentVersion) {
      console.warn(`⚠️  Agent ${agent.id}のコンテキストを更新中...`);
      
      // Agentを一時停止
      await pauseAgent(agent.id);
      
      // 最新コンテキストを読み込み
      await updateAgentContext(agent.id, currentVersion);
      
      // 再開
      await resumeAgent(agent.id);
      
      console.log(`✅ Agent ${agent.id}のコンテキスト更新完了`);
    }
  }
}

問題2: 並列Agentで競合が頻発

並列化の代償——しかし、適切な管理で最小化できます。

症状:

error: CONFLICT (content): Merge conflict in src/shared/types.ts
error: CONFLICT (content): Merge conflict in src/shared/constants.ts
# 複数のAgentが同じファイルを編集

解決策:

# .ai/multi-agent/file-allocation.yml

# ファイルの所有権を事前定義
file_ownership:
  src/modules/auth/**:
    owner: auth-agent
    readonly_for: [payment-agent, notification-agent]
    
  src/modules/payment/**:
    owner: payment-agent
    readonly_for: [auth-agent, notification-agent]
    
  src/shared/**:
    owner: coordinator-agent
    requires_lock: true  # 編集時はロック必要
    readonly_for: [auth-agent, payment-agent, notification-agent]
// ファイルロック機構
class FileLockManager {
  private locks = new Map<string, string>();  // file → agentId
  
  async acquireLock(file: string, agentId: string): Promise<boolean> {
    if (this.locks.has(file)) {
      const owner = this.locks.get(file);
      if (owner !== agentId) {
        console.warn(`ファイル ${file} は Agent ${owner} がロック中`);
        return false;
      }
    }
    
    this.locks.set(file, agentId);
    return true;
  }
  
  releaseLock(file: string, agentId: string): void {
    if (this.locks.get(file) === agentId) {
      this.locks.delete(file);
    }
  }
}

問題3: Agent実行の順序がわからない

依存関係が複雑になると、人間では追いきれません——自動化と可視化が解決策です。

症状:

どのAgentから実行すべき?
依存関係が複雑すぎて追えない...
全体像が見えず、どこから手をつければいいかわからない

原因:

  • 依存関係が暗黙的
  • ドキュメント化されていない
  • グラフとして可視化されていない

解決策:

// .ai/scripts/visualize-workflow.ts

import * as graphviz from 'graphviz';

function visualizeWorkflow(workflow: Workflow): void {
  const g = graphviz.digraph('workflow');
  
  // Agentをノードとして追加
  for (const stage of workflow.stages) {
    for (const agent of stage.agents) {
      g.addNode(agent.id, {
        label: `${agent.id}\n${agent.role}`,
        shape: 'box'
      });
    }
  }
  
  // 依存関係をエッジとして追加
  for (const stage of workflow.stages) {
    for (const agent of stage.agents) {
      for (const dep of agent.dependencies) {
        g.addEdge(dep, agent.id);
      }
    }
  }
  
  // 画像出力
  g.output('png', '.ai/outputs/workflow-graph.png');
  console.log('ワークフローグラフを生成: .ai/outputs/workflow-graph.png');
}

まとめ

長い記事でしたが、ここまで読んでいただき、ありがとうございます。最後に、マルチエージェントの本質を振り返りましょう。

マルチエージェントの価値

「1+1=2」ではなく「1+1=5」——適切な協調が、指数関数的な価値を生みます。

成功のための5つの原則

これら5つの原則を守ることが、マルチエージェントの成功を約束します。

1. 明確な役割分担

曖昧さは混乱の元。 各Agentの責任範囲を明確に定義し、重複や空白を避けます。

2. 効率的なコンテキスト管理

少ないコンテキストで、最大の成果を。 必要最小限のコンテキストで最大の成果を出します。

3. 依存関係の可視化

誰が誰を待っているのか、一目でわかるように。 Agent間の依存関係を明示し、実行順序を最適化します。

4. 適切な並列度

多ければ良いわけではない。 システムリソースとタスクの性質に応じた並列実行が重要です。

5. 継続的な改善

測定し、分析し、改善する。 ワークフローを計測し、ボトルネックを特定して改善します。

今日から始められること

完璧を目指さず、まず始めましょう。小さな一歩が、大きな変化につながります。

# 30分でできるクイックスタート

## ステップ1: Agent役割を定義(10分)

`.ai/multi-agent/roles.yml` を作成
最低限 architect, implementer, tester の3役割から始める

**ポイント**: 完璧でなくていい。まず動かすことが重要。

## ステップ2: シンプルなワークフローを作成(10分)

`.ai/multi-agent/workflow.yml` を作成
パイプライン型(直列)から始める——並列は慣れてから

**ポイント**: 最初は2-3個のAgentで十分。複雑さは後から追加。

## ステップ3: 実際に試す(10分)

小さな機能追加で試してみる
実践を通じて学ぶのが最速

**ポイント**: 失敗から学ぶ。最初の試みは実験と割り切る。

---

**これだけでも効果を実感できます!**

多くのチームが、この30分の投資で、開発効率が20-30%向上したと報告しています。

次のステップ

マルチエージェント開発の旅は、ここから始まります。

さらに学ぶための資料

関連記事(コンテキストエンジニアリングシリーズ)

📚 シリーズトップページ

  1. コーディングエージェント時代のコンテキストエンジニアリング実践ガイド

    • 個人利用の基礎(前提知識)
  2. コンテキストウィンドウの処理フローと動作メカニズム 完全解説

    • 技術的詳細(深い理解)
  3. プロンプトエンジニアリング2.0 - コンテキストを制する者がAIを制する

    • コンテキスト管理 + プロンプト設計の統合
  4. コーディングエージェントのメモリ設計 - 長期記憶システムの実装

    • 外部化したコンテキストの管理・検索
  5. チーム開発のためのコンテキスト共有戦略

    • チーム活用(組織展開)
  6. コンテキスト駆動開発(CDD) - AIファーストな開発手法

    • 開発手法としての体系化
  7. マルチエージェント時代のコンテキストオーケストレーション

    • 複数エージェントの協調動作
  8. デバッグ駆動コンテキストエンジニアリング

    • トラブルシューティングに特化

複数のAIエージェントを協調させ、開発生産性を最大化しましょう!

マルチエージェント開発は、もはや「先進的な手法」ではなく、「現代の標準」になりつつあります。この記事があなたの開発を加速させ、チームを成功に導く助けとなれば幸いです。


付録:依存定義テンプレート(YAML)

ここまでお読みいただき、ありがとうございました。

この記事では、マルチエージェントの協調動作について、アーキテクチャパターンから実践的な実装まで詳しく解説してきました。「理論はわかったけど、実際のファイルはどう書けばいいの?」という疑問をお持ちの方のために、すぐに使えるテンプレート集を用意しました。

このセクションの使い方

  • 初めての方: テンプレートをコピーして、自分のプロジェクトに合わせてカスタマイズ
  • 実装中の方: 依存関係の定義方法や競合対処のパターンを素早く参照
  • トラブル時: 競合クイックリファレンスで症状から対処法を即座に見つける

ヒント: まずは依存定義テンプレートをコピーして、2-3個のエージェントから始めることをおすすめします。


依存定義テンプレート(YAML)

マルチエージェントの実行順序・依存関係を明確化する最小テンプレートです。

# .ai/workflows/order-processing.yaml
version: 1
agents:
  - id: spec
    role: "仕様設計"
    context: [".ai/team/context.md", "docs/domain/order.md"]
  - id: impl_order
    role: "注文サービス実装"
    needs: [spec]
    context: ["services/order/README.md"]
  - id: impl_payment
    role: "決済サービス実装"
    needs: [spec]
    context: ["services/payment/README.md"]
  - id: e2e_test
    role: "統合テスト"
    needs: [impl_order, impl_payment]
    context: ["tests/e2e/README.md"]
options:
  parallelism: 2
  on_conflict: "skip-later"  # later/earlier/prefer-owner

実行イメージ:

npm run ai:run -- .ai/workflows/order-processing.yaml

競合クイックリファレンス(症状→対処)

マルチエージェント開発で遭遇する主な競合パターンと、その対処法を一覧にまとめました。症状から素早く解決策を見つけられます。

ファイル競合

  • 症状: 同一ファイルを複数Agentが更新
  • 対処: ファイル分割 / ファイルオーナー明示 / on_conflict=prefer-owner

コンテキスト不整合

  • 症状: 古い仕様で実装が進む
  • 対処: context version pin(例: context@1.3)/ 仕様Agent完了をneedsで強制

循環依存

  • 症状: 実行順序が確定せず待ち状態
  • 対処: 境界定義(契約の先行合意)/ 依存グラフの分割 / ハブAgent導入

実務メモ

  • まず「並列度」を下げて再現性を確保、その後に最適化
  • すべての中間成果物を保存(検証/ロールバック容易)
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?