4サイトを並行で運用していると、ひとつのエージェントに「全部お願いします」と投げた仕事ほど、あとで手直しが増えることに気づきます。フロントの都合とインフラの都合を一人に同時に最適化させると、どちらも七割の出来で止まりがちなのです。
個人開発を続けるなかで私が頼るようになったのが、役割を分けた複数のエージェントを同時に走らせる構成でした。ここでは Antigravity で最大5つのエージェントを並列に動かすときの分解の仕方、競合の収め方、そして生成物を安全に統合する手順を、実際に使っている実装コードとともに整理します。
最後に、並列化しても速くならない場面についても正直に触れます。台数を増やすこと自体が目的になってしまうと、運用はかえって重くなるからです。
並列エージェント実行の基本概念
単一 vs 複数エージェント: どう選ぶ?
単一エージェント の限界
入力: "Reactアプリを作ってください"
↓
[Claude Code Agent]
- フロントエンド実装
- バックエンド実装
- テスト実装
- デプロイメント設定
↓
出力: 完全なアプリケーション(ただし汎用的)
課題:
✗ エージェントの「脳」は一つ
✗ 複数の専門分野を同時に最適化できない
✗ フロントエンド設計とバックエンド実装のバランスが常に最適とは限らない
✗ 大規模プロジェクト(>10000行)では品質劣化の傾向
複数エージェント並列実行の優位性
入力: "フルスタックアプリを構築"
│
├─ [Frontend Specialist] → React コンポーネント + スタイリング
├─ [Backend Architect] → API + データベース設計(並列)
├─ [DevOps Engineer] → CI/CD + Kubernetes 設定(並列)
└─ [Test Specialist] → テスト戦略(並列)
↓
✓ 各専門分野が「最適化」される
✓ 大規模プロジェクト(>50000行)でも高品質
✓ 実装時間が大幅に短縮
✓ 並列性により全体実行時間は「最長タスク」に左右される
タスク分解戦略(Task Decomposition Strategy)
5つのエージェント配置パターン
Antigravity で推奨される並列エージェント構成:
パターンA: フロントエンド × バックエンド × DevOps(3エージェント)
// 最小構成(中規模プロジェクト向け)
const parallel_config = {
tier_1: {
// 並列実行
"agent_1": {
type: "Frontend Specialist",
task: "UI/UX設計 + React実装",
input: "project_spec.json",
output: ["components/", "styles/", "pages/"]
},
"agent_2": {
type: "Backend Architect",
task: "API設計 + データベース実装",
input: "project_spec.json",
output: ["api/", "models/", "migrations/"]
},
"agent_3": {
type: "DevOps Specialist",
task: "CI/CD + Kubernetes 構成",
input: ["frontend_output", "backend_output"],
dependencies: ["agent_1", "agent_2"],
output: ["docker/", ".github/workflows/", "k8s/"]
}
}
};
// 実行例
await parallel_execute(parallel_config);
// Tier 1: agent_1, agent_2 は同時開始(約45分)
// Tier 2: agent_3 は Tier 1 完了後に開始(約30分)
// 全体: 75分で完了
パターンB: 専門化した4エージェント構成(大規模向け)
// 企業規模プロジェクト向け
const large_project_config = {
tier_1: {
// Stage 1: 並列設計フェーズ(30分)
"design_frontend": {
type: "UI/UX Design Master",
task: "Figmaからコンポーネント設計",
input: "figma_design_link",
output: "design_spec.json"
},
"design_backend": {
type: "API Design Engineer",
task: "OpenAPI仕様書生成",
input: "requirements.md",
output: "openapi.yaml"
},
"design_infra": {
type: "Infrastructure Architect",
task: "クラウドアーキテクチャ設計",
input: "project_spec.json",
output: "architecture.json"
}
},
tier_2: {
// Stage 2: 実装フェーズ(2時間、tier_1依存)
"implement_frontend": {
type: "Frontend Implementation Specialist",
depends_on: ["design_frontend"],
task: "React実装",
input: "design_spec.json",
output: "src/components/"
},
"implement_backend": {
type: "Backend Implementation Specialist",
depends_on: ["design_backend"],
task: "Node.js/FastAPI実装",
input: "openapi.yaml",
output: "api/"
},
"setup_infra": {
type: "Infrastructure Setup Specialist",
depends_on: ["design_infra"],
task: "Terraform によるクラウド構築",
input: "architecture.json",
output: "terraform/"
}
},
tier_3: {
// Stage 3: 統合テストフェーズ(1時間、tier_2依存)
"test_integration": {
type: "Integration Test Master",
depends_on: ["implement_frontend", "implement_backend"],
task: "E2Eテスト",
input: ["src/", "api/"],
output: "test/e2e/"
}
}
};
// 結果: 計3.5時間で完成(従来: 単一エージェント12時間)
DAG(有向非環グラフ)による依存関係管理
// taskDAG.js - エージェント間の依存関係を定義
class TaskDAG {
constructor() {
this.tasks = {};
this.edges = {}; // 依存関係
}
addTask(taskId, agentType, input, dependencies = []) {
this.tasks[taskId] = {
agent: agentType,
input: input,
dependencies: dependencies,
status: "pending",
result: null,
start_time: null,
end_time: null
};
dependencies.forEach(dep => {
if (!this.edges[dep]) this.edges[dep] = [];
this.edges[dep].push(taskId);
});
}
getExecutionTiers() {
// トポロジカルソート
const visited = new Set();
const tiers = [];
let currentTier = 0;
const visit = (taskId, tier) => {
if (visited.has(taskId)) return;
visited.add(taskId);
const task = this.tasks[taskId];
const depMaxTier = task.dependencies.length === 0
? -1
: Math.max(...task.dependencies.map(dep => this.tasks[dep].tier || -1));
task.tier = depMaxTier + 1;
tiers[task.tier] = tiers[task.tier] || [];
tiers[task.tier].push(taskId);
};
Object.keys(this.tasks).forEach(taskId => visit(taskId));
return tiers;
}
async executeParallel() {
const tiers = this.getExecutionTiers();
for (const tier of tiers) {
if (!tier) continue;
// 同じティア内はすべて並列実行
const tierPromises = tier.map(async (taskId) => {
const task = this.tasks[taskId];
task.start_time = Date.now();
console.log(`▶ [${taskId}] 開始: ${task.agent}`);
const agent = getAgent(task.agent);
task.result = await agent.execute(task.input);
task.end_time = Date.now();
task.status = "completed";
console.log(`✓ [${taskId}] 完了: ${(task.end_time - task.start_time) / 1000}秒`);
});
await Promise.all(tierPromises);
}
return this.getResults();
}
getResults() {
return Object.fromEntries(
Object.entries(this.tasks).map(([id, task]) => [id, task.result])
);
}
}
// 使用例
const dag = new TaskDAG();
dag.addTask("api_design", "APIDesignEngineer", "spec.json");
dag.addTask("db_schema", "DatabaseArchitect", "spec.json");
dag.addTask("frontend", "UIComponentSpecialist", "spec.json");
dag.addTask("api_impl", "BackendImplementation", "api_design結果", ["api_design"]);
dag.addTask("db_impl", "DatabaseImplementation", "db_schema結果", ["db_schema"]);
dag.addTask("frontend_impl", "FrontendImplementation", "frontend結果", ["frontend"]);
dag.addTask("integration_test", "IntegrationTestMaster",
{ api: "api_impl結果", frontend: "frontend_impl結果" },
["api_impl", "frontend_impl", "db_impl"]);
await dag.executeParallel();
競合解決戦略(Conflict Resolution)
複数エージェントが並列で動作する際、「矛盾した提案」が発生することは避けられません。
競合シナリオと対処パターン
シナリオ1: パフォーマンス vs セキュリティ
// Backend Architect が提案:
const backendProposal = {
database: "MongoDB(NoSQL、高速)",
caching: "Redis(メモリ最適化)",
encryption: "Optional(パフォーマンス優先)"
};
// Security Testing Analyst が提案:
const securityProposal = {
database: "PostgreSQL(強力なACL機構)",
caching: "Memcached with TLS(暗号化)",
encryption: "Mandatory at-rest + in-transit"
};
// 競合解決ポリシー
const conflictResolutionPolicy = {
"performance_vs_security": {
rule: "SECURITY_FIRST",
reasoning: "データ漏洩のリスクはパフォーマンス劣化より深刻",
decision: securityProposal,
optimization: "PostgreSQL + Redis(TLS対応版)で両立"
}
};
シナリオ2: フレームワーク選択の競合
// Frontend Specialist が提案:
const frontendProposal = {
framework: "Next.js 15 (最新、フル機能)",
state_management: "Zustand(軽量)",
testing: "Vitest(最速)"
};
// DevOps Specialist が提案:
const devopsProposal = {
framework: "Create React App (枯れた技術)",
state_management: "Redux(エンタープライズ対応)",
testing: "Jest(業界標準)"
};
// 競合解決ロジック
const resolutionLogic = {
rule: "PROJECT_CONTEXT_AWARE",
evaluation: {
project_maturity: "startup → 新技術OK",
team_expertise: "React > Next.js → Next.js採用",
deployment_target: "Vercel available → Next.js最適",
legacy_constraints: "none → 新技術選択"
},
decision: "Next.js + Zustand + Vitest(条件A,B,D満たす)"
};
競合解決エンジンの実装
// conflict-resolver.js
class ConflictResolver {
constructor(policy = {}) {
this.policy = policy;
this.resolutionLog = [];
}
async resolveConflict(agentA, propA, agentB, propB, context) {
const conflictKey = this.identifyConflictType(propA, propB);
console.log(`⚠️ 競合検出: ${agentA.name} vs ${agentB.name}`);
console.log(`📋 タイプ: ${conflictKey}`);
// Step 1: ポリシーベースの判定
let resolution = this.applyPolicy(conflictKey, propA, propB, context);
// Step 2: ポリシーにない場合は重要度スコアリング
if (!resolution) {
resolution = await this.scoreAndCompare(propA, propB, context);
}
// Step 3: 結果をログに記録
this.resolutionLog.push({
conflict_key: conflictKey,
agent_a: agentA.name,
agent_b: agentB.name,
resolution: resolution,
timestamp: new Date()
});
return resolution;
}
applyPolicy(conflictKey, propA, propB, context) {
const policyRule = this.policy[conflictKey];
if (!policyRule) return null;
// ポリシーに基づいて決定
if (policyRule.rule === "ALWAYS_A") return propA;
if (policyRule.rule === "ALWAYS_B") return propB;
if (policyRule.rule === "SECURITY_FIRST") {
return propA.security_score > propB.security_score ? propA : propB;
}
if (policyRule.rule === "CONTEXT_AWARE") {
return this.evaluateInContext(propA, propB, context, policyRule.criteria);
}
}
scoreAndCompare(propA, propB, context) {
// スコアリング基準
const scoringCriteria = {
"ecosystem_maturity": 0.2,
"team_skills": 0.2,
"long_term_maintainability": 0.15,
"performance_impact": 0.15,
"cost": 0.1,
"security": 0.2
};
const scoreA = Object.entries(scoringCriteria).reduce((sum, [criterion, weight]) => {
return sum + (propA[criterion] || 0) * weight;
}, 0);
const scoreB = Object.entries(scoringCriteria).reduce((sum, [criterion, weight]) => {
return sum + (propB[criterion] || 0) * weight;
}, 0);
return scoreA > scoreB ? propA : propB;
}
identifyConflictType(propA, propB) {
// 競合のタイプ(キー)を判定
if (propA.performance && propB.security) return "performance_vs_security";
if (propA.new_technology && propB.proven_technology) return "innovation_vs_stability";
if (propA.cost && propB.scalability) return "cost_vs_scalability";
return "unknown_conflict";
}
}
// 使用例
const resolver = new ConflictResolver(conflictResolutionPolicy);
const resolved = await resolver.resolveConflict(
backendAgent,
{ database: "MongoDB", security_score: 7 },
securityAgent,
{ database: "PostgreSQL", security_score: 9 },
{ project_type: "fintech", security_criticality: "high" }
);
console.log("🔧 決定:", resolved);
// 出力: 🔧 決定: { database: "PostgreSQL", ... }
アーティファクト検証とマージ戦略
複数エージェントが生成した成果物(コード、設定ファイル)を、安全に統合する必要があります。
アーティファクト品質チェック
// artifact-validator.js
class ArtifactValidator {
async validateAll(artifacts) {
const results = {};
for (const [agentName, artifact] of Object.entries(artifacts)) {
results[agentName] = await this.validate(artifact, agentName);
}
return results;
}
async validate(artifact, agentName) {
const checks = {
syntax_validity: await this.checkSyntax(artifact),
dependency_completeness: await this.checkDependencies(artifact),
type_safety: await this.checkTypes(artifact),
security_audit: await this.auditSecurity(artifact),
performance_baseline: await this.checkPerformance(artifact)
};
const allPassed = Object.values(checks).every(c => c.passed);
return {
agent: agentName,
passed: allPassed,
checks: checks,
warnings: this.extractWarnings(checks),
severity: allPassed ? "info" : "error"
};
}
async checkSyntax(artifact) {
try {
if (artifact.type === "javascript") {
// JSの構文検証
new Function(artifact.code);
return { passed: true };
}
if (artifact.type === "json") {
JSON.parse(artifact.content);
return { passed: true };
}
if (artifact.type === "yaml") {
// YAML検証
return { passed: true };
}
} catch (e) {
return { passed: false, error: e.message };
}
}
async checkDependencies(artifact) {
// 依存ライブラリが package.json に記録されているか
const imports = this.extractImports(artifact.code);
const packageJson = require('./package.json');
const missing = imports.filter(imp => !packageJson.dependencies[imp]);
return {
passed: missing.length === 0,
missing_deps: missing
};
}
async auditSecurity(artifact) {
const issues = [];
// セキュリティパターン検出
if (artifact.code.includes("eval(")) issues.push("eval() usage detected");
if (artifact.code.includes("dangerouslySetInnerHTML")) issues.push("XSS risk");
if (artifact.code.match(/password\s*=\s*['"][^'"]+['"]/)) issues.push("Hardcoded password");
return {
passed: issues.length === 0,
issues: issues
};
}
extractWarnings(checks) {
return Object.entries(checks)
.filter(([_, check]) => !check.passed)
.map(([name, check]) => `${name}: ${check.error || check.issues?.join(", ")}`);
}
}
マージ戦略
// merger.js
class ArtifactMerger {
async mergeAll(artifacts, strategy = "smart") {
if (strategy === "sequential") {
return this.mergeSequential(artifacts);
}
if (strategy === "smart") {
return this.mergeSmart(artifacts);
}
if (strategy === "conflict_aware") {
return this.mergeConflictAware(artifacts);
}
}
async mergeSmart(artifacts) {
const result = {
frontend: {},
backend: {},
devops: {},
shared: {}
};
// 1. カテゴリ分類
for (const [source, artifact] of Object.entries(artifacts)) {
const category = this.classifyArtifact(artifact, source);
result[category][source] = artifact;
}
// 2. カテゴリ内でマージ
result.frontend = await this.mergeFrontendArtifacts(result.frontend);
result.backend = await this.mergeBackendArtifacts(result.backend);
result.devops = await this.mergeDevopsArtifacts(result.devops);
// 3. 検証
await this.validateMerged(result);
return result;
}
async mergeFrontendArtifacts(artifacts) {
// React components, styles, assets の統合
const merged = {
components: {},
styles: {},
pages: {},
public: {}
};
for (const [source, artifact] of Object.entries(artifacts)) {
if (artifact.type === "component") {
merged.components = this.deepMerge(merged.components, artifact.content);
}
if (artifact.type === "styles") {
merged.styles = this.deepMerge(merged.styles, artifact.content);
}
}
return merged;
}
deepMerge(target, source) {
for (const [key, value] of Object.entries(source)) {
if (target[key] && typeof target[key] === "object" && typeof value === "object") {
target[key] = this.deepMerge(target[key], value);
} else if (target[key] && target[key] !== value) {
console.warn(`⚠️ マージ競合: ${key}`);
// 競合時は新しい値で上書き(またはカスタムロジック)
target[key] = value;
} else {
target[key] = value;
}
}
return target;
}
}
本番環境ワークフロー実装例
ケーススタディ: フルスタックSaaS アプリケーション構築
5個のエージェント並列実行で、完全なアプリケーションを構築するシナリオ:
// production-workflow.js
const productionWorkflow = async () => {
console.log("🚀 フルスタックSaaS構築開始");
console.log("📋 プロジェクト: Notion風のノート管理アプリ");
console.log("⏱️ 目標完了時間: 4時間(従来: 10営業日)\n");
// Step 1: 5個エージェント並列起動
const agents = {
frontend: getAgent("UIComponentSpecialist"),
backend: getAgent("BackendArchitect"),
database: getAgent("DatabaseArchitect"),
devops: getAgent("DevOpsEngineer"),
testing: getAgent("TestingAutomationMaster")
};
const startTime = Date.now();
// Step 2: 並列実行(依存関係なし)
const [frontendCode, backendAPI, dbSchema, cicdConfig, testSuite] = await Promise.all([
agents.frontend.generate({
spec: projectSpec,
design: figmaLink,
constraints: { framework: "Next.js 15", styling: "Tailwind CSS" }
}),
agents.backend.design({
spec: projectSpec,
performance_target: "< 100ms p99"
}),
agents.database.design({
entities: ["users", "workspaces", "documents"],
scale: "1M+ documents",
compliance: "GDPR"
}),
agents.devops.build({
hosting: "AWS ECS + RDS",
regions: ["Tokyo", "us-east-1"],
autoscaling: true
}),
agents.testing.plan({
coverage_target: 80,
e2e_scenarios: ["sign_up", "create_doc", "share", "export"]
})
]);
const parallelTime = (Date.now() - startTime) / 1000;
console.log(`✓ 並列フェーズ完了: ${parallelTime.toFixed(0)}秒\n`);
// Step 3: アーティファクト検証
console.log("🔍 品質チェック中...");
const validator = new ArtifactValidator();
const validation = await validator.validateAll({
frontend: frontendCode,
backend: backendAPI,
database: dbSchema,
devops: cicdConfig,
tests: testSuite
});
let validationPassed = true;
for (const [agent, result] of Object.entries(validation)) {
console.log(`${result.passed ? "✓" : "✗"} ${agent}: ${result.checks.syntax_validity.passed ? "OK" : "ERROR"}`);
if (!result.passed) validationPassed = false;
}
if (!validationPassed) {
console.error("❌ 検証失敗。修正中...");
// 自動修正ロジック
}
// Step 4: マージと統合
console.log("🔗 成果物を統合中...");
const merger = new ArtifactMerger();
const merged = await merger.mergeAll({
frontend: frontendCode,
backend: backendAPI,
database: dbSchema,
devops: cicdConfig,
tests: testSuite
});
// Step 5: リポジトリにコミット
console.log("📦 リポジトリにコミット...");
await commitToGit({
message: "feat: Full-stack Notion clone v1.0 (AgentKit 5-agent parallel)",
files: merged
});
// Step 6: CI/CDパイプライン実行
console.log("⚙️ CI/CDパイプライン起動...");
const deploymentResult = await triggerDeployment(cicdConfig);
const totalTime = (Date.now() - startTime) / 1000 / 60;
console.log(`\n✅ 完成!総時間: ${totalTime.toFixed(1)}分`);
console.log(`🎯 成果物:`);
console.log(` - Frontend: ${Object.keys(merged.frontend.components).length} components`);
console.log(` - Backend: ${Object.keys(merged.backend.routes).length} API endpoints`);
console.log(` - Database: ${Object.keys(merged.database.tables).length} tables`);
console.log(` - Tests: ${Object.keys(merged.tests.scenarios).length} test scenarios`);
console.log(` - 📍 URL: ${deploymentResult.url}`);
};
// 実行
await productionWorkflow();
並列化が効かない3つの場面
台数を増やせば増やすほど速くなる、という直感はだいたい外れます。Dolice Labs の4サイトを並行運用するなかで何度も足をすくわれたのは、次の3つでした。
1. 依存が一本道のとき
設計→実装→テストのように、後段が前段の出力を必ず待つ仕事は、何エージェント並べても所要時間は変わりません。DAG を引いてティアが縦にだけ伸びる構成になっていたら、それは並列化の対象ではなく、単に分割しただけです。並列で意味が出るのは、同じティアに2つ以上のタスクが並ぶときだけです。
2. マージが人間の目を必要とするとき
5体が同時に生成したコードを、機械的なバリデーションだけで本番に流すのは現実的ではありません。私のワークフローでも、記事の自動生成は並列で回せても、最後の品質ゲートと取り込みの判断は一本のキューに直列で並びます。生成を5倍速にしても、レビューが1人分のままなら、全体のスループットはレビューに律速されます。これはエージェント開発に限らず、人手のレビューが残るあらゆる自動化に共通する壁です。
3. 競合解決のコストが分割の利益を上回るとき
タスクを細かく割るほど、エージェント間の前提のずれが増えます。フロント担当が選んだ状態管理と、テスト担当が想定していたそれが食い違えば、その調整に人間の時間が溶けていきます。3体で回したほうが、5体で回して毎回すり合わせるより速い、という逆転は珍しくありません。
私が並列構成を選ぶときの基準は、ひとつだけです。「分割して並べたあとに残るすり合わせのコストが、短縮できる時間より小さいか」。この問いに自信を持って頷けないときは、素直に台数を減らすようにしています。
おわりに
複数エージェントの並列実行は、使いどころを選べば確かに強力です。本記事のワークフロー例では3.5時間という数字を挙げましたが、これは依存の少ない理想的なケースでの目安であり、実務では競合解決とマージの分だけ必ず上振れします。大切なのは「速くなった」ことよりも、専門特化とマルチビュー検証によって手直しの総量が減ることだと、私は考えています。
次に手を動かすなら、まずは3体構成で一度パイプラインを通し、同じティアに並ぶタスクが本当に独立しているかを観察してみてください。そのうえで台数を増やすかどうかを決めると、無理のない設計に落ち着きます。より複雑な委譲パターンは、Antigravity マルチエージェント オーケストレーション実践ガイド で扱っています。
お読みいただきありがとうございました。
記事執筆日: 2026年3月25日
対象: Antigravity 2025.Q4以降