複数のAIエージェントを協調させ、最大のパフォーマンスを引き出すための実践的アプローチ
📚 この記事の位置づけ
本記事は、コンテキストエンジニアリングシリーズの続編です。
前提知識として、以下の記事を先にお読みいただくことをおすすめします:
- コーディングエージェント時代のコンテキストエンジニアリング実践ガイド - 個人利用の基礎
- コンテキストウィンドウの処理フローと動作メカニズム 完全解説 - 技術的詳細
- チーム開発のためのコンテキスト共有戦略 - チーム活用
本記事では、複数のエージェントを同時に活用する際の設計と実装を扱います。
目次
- マルチエージェント時代の到来
- なぜ複数のエージェントが必要なのか
- マルチエージェントアーキテクチャの基本
- コンテキストの受け渡しパターン
- 役割分担とコンテキスト分割
- 並列処理時のコンテキスト競合
- 実践: Claude Code × Cursor 併用戦略
- エージェント間の依存関係管理
- パフォーマンス最適化戦略
- ケーススタディ
マルチエージェント時代の到来
「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%向上したと報告しています。
次のステップ
マルチエージェント開発の旅は、ここから始まります。
さらに学ぶための資料
関連記事(コンテキストエンジニアリングシリーズ)
-
コーディングエージェント時代のコンテキストエンジニアリング実践ガイド
- 個人利用の基礎(前提知識)
-
コンテキストウィンドウの処理フローと動作メカニズム 完全解説
- 技術的詳細(深い理解)
-
プロンプトエンジニアリング2.0 - コンテキストを制する者がAIを制する
- コンテキスト管理 + プロンプト設計の統合
-
コーディングエージェントのメモリ設計 - 長期記憶システムの実装
- 外部化したコンテキストの管理・検索
-
- チーム活用(組織展開)
-
コンテキスト駆動開発(CDD) - AIファーストな開発手法
- 開発手法としての体系化
-
- 複数エージェントの協調動作
-
- トラブルシューティングに特化
複数の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導入
実務メモ
- まず「並列度」を下げて再現性を確保、その後に最適化
- すべての中間成果物を保存(検証/ロールバック容易)