Antigravity のマルチエージェントアーキテクチャ概要
3つの主要コンポーネント
Antigravityのマルチエージェントシステムは3層で構成されます。
第1層:Manager Surface
Manager Surface は、ユーザーからのリクエストを受け取り、適切なサブエージェントにタスクを割り当てる「指揮官」です。
役割:
タスク分析:ユーザーのリクエストを複数の下位タスクに分解
ルーティング:各タスクを最適なサブエージェントにアサイン
オーケストレーション:サブエージェント間の依存関係を管理
集約:各サブエージェントの出力を統合して最終成果物を生成
第2層:Sub-agents(専門エージェント)
各分野に特化したエージェント。Antigravityでは以下のプリセットが用意されています:
code-gen-agent :プログラミング言語別コード生成(Python、Go、TypeScript等)
design-agent :UIコンポーネント・設計書生成
test-agent :単体テスト・統合テスト自動生成
security-agent :セキュリティ監査・脆弱性チェック
doc-agent :技術ドキュメント・API仕様生成
また、カスタムエージェントも定義可能。
第3層:Orchestrator(オーケストレーター)
各エージェント間の通信とデータフローを管理します。
Manager
↓
[Task 1, Task 2, Task 3]
↓
Sub-agents (並列実行)
↓
[Result 1, Result 2, Result 3]
↓
Orchestrator (結果の検証・マージ)
↓
最終出力
AgentKit 2.0 のコアコンセプト
AgentKit 2.0 は、このマルチエージェント体系を フレームワーク化 しました。
開発者が実装すべきは主に以下2点:
AGENTS.md :各エージェントの指示・ロール・能力を定義
Orchestration Logic :Manager と Sub-agents 間の連携ロジック
残りは AgentKit 2.0 が自動処理します。
AGENTS.md でエージェントを設定する
AGENTS.md の基本構造
プロジェクトルートに以下のような AGENTS.md を配置:
# Antigravity Agents Configuration
## Project Identity
project_name: "e-commerce-platform"
version: "2.0"
language: "en"
## Global Instructions
Keep all outputs modular, testable, and production-ready.
Prefer clear function/method names over comments.
Always consider security implications.
## Agent Definitions
### Manager Agent
name: "orchestrator"
type: "manager"
role: "Coordinates all other agents"
instructions: |
- Analyze incoming requests
- Break down complex tasks into sub-tasks
- Assign tasks to appropriate specialists
- Validate outputs from sub-agents
- Merge results into cohesive deliverables
- Escalate conflicts to human reviewer if needed
### Frontend Agent
name: "frontend-specialist"
type: "sub-agent"
role: "React/TypeScript component development"
expertise:
- React Hooks & State Management
- TypeScript type definitions
- Tailwind CSS styling
- Accessibility (a11y)
instructions: |
- Follow component composition patterns
- Implement error boundaries
- Optimize render performance
- Use semantic HTML
- Test with accessibility tools
dependencies: []
output_format: "TypeScript React components"
### Backend Agent
name: "backend-specialist"
type: "sub-agent"
role: "Node.js/Express API development"
expertise:
- RESTful API design
- Database schema design
- Authentication & Authorization
- Input validation & error handling
instructions: |
- Design APIs that are idempotent
- Implement proper HTTP status codes
- Use dependency injection
- Add comprehensive logging
- Write defensive code
dependencies: [ "database-agent" ]
output_format: "Node.js/Express code with TypeScript"
### Database Agent
name: "database-specialist"
type: "sub-agent"
role: "Database design and optimization"
expertise:
- SQL schema design
- Query optimization
- Index strategy
- Data migration
instructions: |
- Normalize schemas to 3NF minimum
- Add indexes for query performance
- Plan for scalability
- Document migration steps
dependencies: []
output_format: "SQL DDL statements"
### QA Agent
name: "qa-specialist"
type: "sub-agent"
role: "Test automation and quality assurance"
expertise:
- Unit testing (Jest, Vitest)
- Integration testing
- E2E testing (Playwright)
- Coverage analysis
instructions: |
- Write tests before code (TDD mindset)
- Aim for >80% code coverage
- Test error scenarios, not just happy path
- Use descriptive test names
dependencies: ["frontend-specialist", "backend-specialist"]
output_format: "JavaScript/TypeScript test files"
## Execution Strategy
mode: "parallel_with_dependencies"
timeout: 3600
retry_on_failure: true
max_retries: 3
AGENTS.md 作成時の重要なポイント
1. 指示の粒度を適切に
曖昧すぎる指示:
instructions: |
- Write good code
適切な指示:
instructions: |
- Use TypeScript strict mode
- Implement error handling with try-catch
- Add JSDoc comments for public APIs
- Follow naming convention: camelCase for variables, PascalCase for components
2. 依存関係を明示
dependencies : [ "database-agent" ] # ✅ backend-agent は database schema が必要
これにより Orchestrator は自動的に実行順序を決定します。
3. 出力形式を統一
各エージェントの出力形式を明確にすると、統合が容易になります:
output_format : "TypeScript React components (.tsx)"
expected_files :
- "Button.tsx (with props interface)"
- "Form.tsx (with validation logic)"
Manager Surface の実装——タスク分割とサブエージェントへの委譲
Manager Agent のコア責任
Manager Agent が果たすべき3つのフェーズ:
フェーズ1:タスク分析(Task Decomposition)
ユーザーのリクエスト:
「ECサイトのショッピングカート機能を実装して。
データベースはPostgres、フロントはReact、支払いはStripe。」
Manager が分解:
{
"task" : "Build shopping cart feature" ,
"sub_tasks" : [
{
"id" : "db-001" ,
"agent" : "database-specialist" ,
"description" : "Design shopping cart schema (cart, cart_items tables)" ,
"priority" : 1
},
{
"id" : "api-001" ,
"agent" : "backend-specialist" ,
"description" : "Implement POST /api/cart, PUT /api/cart/:id, DELETE /api/cart/:id" ,
"priority" : 2 ,
"depends_on" : [ "db-001" ]
},
{
"id" : "ui-001" ,
"agent" : "frontend-specialist" ,
"description" : "Build CartPage component with add/remove/checkout flows" ,
"priority" : 2 ,
"depends_on" : [ "api-001" ]
},
{
"id" : "payment-001" ,
"agent" : "backend-specialist" ,
"description" : "Integrate Stripe payment API" ,
"priority" : 3 ,
"depends_on" : [ "api-001" ]
},
{
"id" : "test-001" ,
"agent" : "qa-specialist" ,
"description" : "Write tests for cart functionality (unit + integration)" ,
"priority" : 3 ,
"depends_on" : [ "api-001" , "ui-001" ]
}
]
}
フェーズ2:ルーティングと並列実行
ここで一度立ち止まりたいのが、「並列にした」と「速くなった」は別だということです。上の JSON が宣言している depends_on だけを読み、依存を満たす最短の段数を機械的に求めてみます。
# schedule.py — depends_on だけを見て実行段(レベル)を求める
from collections import defaultdict
def levels (tasks):
dep = {t[ "id" ]: set (t.get( "depends_on" , [])) for t in tasks}
lv, placed, n = {}, set (), 0
while len (placed) < len (dep):
ready = [i for i, d in dep.items() if i not in placed and d <= placed]
if not ready:
raise SystemExit ( "循環依存: " + str ( set (dep) - placed))
for i in ready:
lv[i] = n
placed |= set (ready)
n += 1
return lv, n
lv, depth = levels(sub_tasks)
by = defaultdict( list )
for task_id, level in lv.items():
by[level].append(task_id)
print ( "段数:" , depth, "/最大並列幅:" , max ( len (v) for v in by.values()))
for level in sorted (by):
print ( f " L { level } : { ' ' .join( sorted (by[level])) } " )
手元で走らせた出力です。
段数: 4 /最大並列幅: 2
L0: db-001
L1: api-001
L2: payment-001 ui-001
L3: test-001
タスクは 5 つあるのに、同時に走れるのは最大 2 つでした。各タスクの所要を一律 1 と置けば、直列 5 に対して並列 4 ——短縮は 1.25 倍にとどまります。エージェントを 5 体並べても、依存が一本道であれば残りは待っているだけなのです。
しかも、この節にもともと置いていたフェーズ図は、同じ JSON の依存と噛み合っていませんでした。図の割り当てを同じスクリプトで突き合わせると、違反が 2 件出ます。
❌ payment-001(フェーズB)は api-001(フェーズB)に依存しているのに同じ段に置かれています
❌ test-001(フェーズC)は ui-001(フェーズC)に依存しているのに同じ段に置かれています
→ 依存違反 2 件
手で描いた図は、こうして黙って嘘をつきます。実行計画は図で確かめず、depends_on から機械で導く。 サブエージェントを増やす前に、この一手間を挟むようにしております。
では 1.25 倍をどう引き上げるか。効いたのは並列数ではなく、依存の張り方でした。ui-001 が待っているのは api-001 の実装 ではなく、api-001 が返す契約 です。契約(OpenAPI の定義、Zod スキーマ、TypeScript の型)を Manager が先に固定し、フロントとテストはモックに対して進める形へ組み替えます。
同じスクリプトに契約先行の依存を食わせた出力です。
段数: 3 /最大並列幅: 4
L0: contract-001
L1: db-001 payment-001 test-001 ui-001
L2: api-001
タスクは 1 つ増えたのに、段数は 4 から 3 に減りました。契約を先に書く時間は、待ち時間から取り返せるのです。
フェーズ3:結果の集約と検証
各サブエージェントの出力を集約:
Database Output: schema.sql (200行)
Backend Output: cart.controller.ts (350行)
Frontend Output: CartPage.tsx (280行)
Payment Output: stripe.service.ts (150行)
Test Output: cart.test.ts (420行)
↓ Orchestrator による結合
src/
├─ schemas/
│ └─ cart.sql
├─ api/
│ ├─ controllers/
│ │ └─ cart.controller.ts
│ └─ services/
│ └─ stripe.service.ts
├─ components/
│ └─ CartPage.tsx
└─ tests/
└─ cart.test.ts
サブエージェントへの指示の渡し方
Manager が Sub-agent に渡す指示書のテンプレート:
{
"task_id" : "api-001" ,
"target_agent" : "backend-specialist" ,
"context" : {
"project" : "e-commerce-platform" ,
"tech_stack" : [ "Node.js" , "Express" , "TypeScript" , "PostgreSQL" ],
"related_schema" : {
"database_schema" : "cart table with id, user_id, created_at, updated_at" ,
"cart_items" : "cart_id, product_id, quantity, price"
}
},
"requirements" : [
"Create POST /api/cart - initialize user cart" ,
"Create GET /api/cart/:cartId - fetch cart with items" ,
"Create PUT /api/cart/:cartId/items - add/update items" ,
"Create DELETE /api/cart/:cartId/items/:itemId - remove item" ,
"Implement input validation using Zod" ,
"Add error handling (404, 400, 500)" ,
"Include TypeScript types for request/response"
],
"output_requirements" : {
"format" : "TypeScript Express routes" ,
"file_name" : "cart.controller.ts" ,
"includes_tests" : false ,
"doc_required" : true
},
"constraints" : {
"max_file_size" : "500 lines" ,
"performance_target" : "response < 200ms" ,
"security" : "Validate user ownership of cart"
}
}
結果の集約とハンドリング
Sub-agents からの出力を受け取ったら:
形式の検証 :期待どおりの形式で返ってきているか
内容の検証 :未完成のマーカーが残っていないか
依存関係の確認 :次の段に渡す出力がそろっているか
統合 :複数の出力を1つのプロジェクト構造へ
素直に書くと落とし穴があります。私が最初に置いていたのは、こういう形でした。
// orchestrator.js — 素直に書いた版(このあと直します)
async function aggregateResults ( subAgentOutputs ) {
const validatedOutputs = {};
for ( const [ agentName , output ] of Object. entries (subAgentOutputs)) {
if ( ! validateFormat (output)) {
throw new Error ( `${ agentName }: Invalid output format` ); // ここで反復が止まる
}
if (output. includes ( 'ERROR:' ) || output. includes ( 'TODO:' )) {
console. warn ( `${ agentName }: Incomplete output detected` ); // 警告を出すだけ
}
validatedOutputs[agentName] = {
content: output,
timestamp: new Date (),
validated: true // それでも true が付く
};
}
return mergeIntoProjectStructure (validatedOutputs);
}
5 体分の出力を食わせて動かしてみます。不良は 3 件——TODO: が残ったもの、null が返ったもの、ERROR: を返したものです。
backend-specialist: Incomplete output detected
throw: qa-specialist: Invalid output format
不良は 3 件あったのに、手元に残った診断は 2 行でした。TODO: の残る出力には validated: true が付いて通り、ERROR: を返した payment-specialist は一度も検査されないまま反復が終わっています。Object.entries の並び順が変われば、見える失敗も入れ替わります。
並列に投げた意味は、失敗もまとめて受け取れることにあります。途中で throw すると、その利点を自分で捨ててしまうのです。
const INCOMPLETE_MARKERS = [ / ^ \s * ERROR:/ m , / \b TODO:/ , / \b FIXME:/ , /< {7} / ];
function inspect ( agentName , output ) {
if ( typeof output !== 'string' || output. trim () === '' ) {
return { agent: agentName, status: 'invalid' , reason: '出力が文字列ではないか空です' };
}
const hit = INCOMPLETE_MARKERS . find (( re ) => re. test (output));
if (hit) {
return { agent: agentName, status: 'incomplete' , reason: `未完成マーカー ${ hit } を検出しました` };
}
return { agent: agentName, status: 'ok' , content: output };
}
function aggregateResults ( subAgentOutputs ) {
const reports = Object. entries (subAgentOutputs). map (([ name , out ]) => inspect (name, out));
const accepted = reports. filter (( r ) => r.status === 'ok' );
const rejected = reports. filter (( r ) => r.status !== 'ok' );
return {
ok: rejected. length === 0 ,
accepted: Object. fromEntries (accepted. map (( r ) => [r.agent, r.content])),
rejected
};
}
同じ入力での出力です。
ok = false
採用 = [ 'database-specialist', 'frontend-specialist' ]
差し戻し backend-specialist [incomplete] 未完成マーカー /\bTODO:/ を検出しました
差し戻し qa-specialist [invalid] 出力が文字列ではないか空です
差し戻し payment-specialist [incomplete] 未完成マーカー /^\s*ERROR:/m を検出しました
差し戻すべき 3 体が 1 回の実行で出そろい、通った 2 体はそのまま次の段へ渡せます。集約とは、通ったものを進める処理ではなく、通らなかったものを全部数え上げる処理です。 マージ先を組み立てるのは、そのあとで十分なのだと思います。
よくある設計パターン——Map-Reduce・Pipeline・Supervisor
実践では、タスク分割パターンが限定されることに気づきます。代表的な3パターンを紹介します。
パターン1:Map-Reduce(並列処理で速度向上)
複数の独立したタスクを並列処理し、結果をマージ。
ユースケース :
複数APIエンドポイントの同時実装
複数テストスイートの並列実行
複数データベーススキーマの並列設計
例:複数APIエンドポイント実装
Manager: "以下の5つのAPIを全て実装して"
- GET /products
- POST /products
- GET /products/:id
- PUT /products/:id
- DELETE /products/:id
↓ Map フェーズ
[backend-agent#1] [backend-agent#2] [backend-agent#3]
GET /products POST /products GET /products/:id
→ products.get.ts → products.post.ts → products.getById.ts
[backend-agent#4] [backend-agent#5]
PUT /products/:id DELETE /products/:id
→ products.put.ts → products.delete.ts
↓ Reduce フェーズ
Orchestrator がすべてを products.controller.ts に統合
実装のポイント :
並列実行数をコントロール(通常 3〜5 並列が最適)
メモリ・トークン使用量をモニタリング
タイムアウト設定(各エージェント5分以内)
パターン2:Pipeline(逐次処理でデータを変換)
前のステップの出力が次のステップの入力になります。
ユースケース :
ビジネスロジック → テストコード → ドキュメント
スキーマ設計 → マイグレーションスクリプト → インデックス作成
デザイン → コンポーネント実装 → ストーリーブック記述
例:API開発パイプライン
Step 1: API要件定義(Manager)
└─ API仕様ドキュメント生成
Step 2: データベーススキーマ設計(database-agent)
Input: API仕様
└─ schema.sql 生成
Step 3: バックエンド実装(backend-agent)
Input: スキーマ + API仕様
└─ controller.ts 生成
Step 4: テスト生成(qa-agent)
Input: controller.ts
└─ controller.test.ts 生成
Step 5: ドキュメント生成(doc-agent)
Input: controller.ts + テスト
└─ API.md 生成
実装のポイント :
各ステップ間でのデータフォーマットの一貫性確保
前ステップのエラーを検知して止める仕組み(early failure)
部分的なロールバック機構
パターン3:Supervisor(品質保証とエラーハンドリング)
複数のエージェントが独立に作業し、Supervisor が検証・修正。
ユースケース :
セキュリティ監査後の自動修正
コード品質スコア計算と改善
パフォーマンステスト結果に基づく最適化
例:セキュリティ検査パイプライン
Step 1: backend-agent が API コードを生成
└─ controller.ts
Step 2: security-agent が脆弱性をスキャン
Input: controller.ts
Output: "SQL Injection 検出 (line 45)", "XSS 検出 (line 88)"
Step 3: backend-agent が 脆弱性を修正
Input: controller.ts + 脆弱性リスト
Output: controller.ts (修正版)
Step 4: security-agent が再検証
Input: 修正版 controller.ts
Output: "✅ All checks passed"
↓ Merge to main
実装のポイント :
Supervisor の判断基準を明確に(スコア 90点以上 = OK)
修正ループの上限を設定(最大3回まで)
改善不可の場合は人間へエスカレート
実践プロジェクト——コードレビューパイプラインの構築
理論を実装に変えましょう。実際に動くマルチエージェントシステムを構築します。
シナリオ設定
GitHub PR(プルリクエスト)が作成されたら、自動的に以下を実行:
静的解析エージェント :コード品質・ベストプラクティスをチェック
セキュリティエージェント :脆弱性スキャン
パフォーマンスエージェント :パフォーマンス問題を検出
集約エージェント :全レビュー結果をマージして GitHub コメント を生成
AGENTS.md の定義
# GitHub PR Auto-Review System
## Manager Agent
name: "pr-orchestrator"
role: "Coordinates all code review checks"
instructions: |
- Parse GitHub PR diff
- Extract changed files
- Assign files to specialist agents
- Collect all review comments
- Generate consolidated review
## Static Analysis Agent
name: "lint-analyzer"
expertise: ["ESLint", "TypeScript strict mode", "Code complexity"]
instructions: |
- Check TypeScript strict mode compliance
- Run ESLint rules (Airbnb style)
- Detect circular dependencies
- Report cyclomatic complexity > 10
checks:
- type_safety
- naming_conventions
- code_complexity
## Security Agent
name: "security-scanner"
expertise: ["OWASP", "Dependency vulnerabilities", "Secret detection"]
instructions: |
- Scan for hardcoded secrets (API keys, passwords)
- Check dependency versions (npm audit)
- Detect SQL injection patterns
- Check authentication logic
checks:
- secrets
- vulnerabilities
- injection_patterns
- auth_logic
## Performance Agent
name: "perf-analyzer"
expertise: ["Rendering performance", "Bundle size", "Database queries"]
instructions: |
- Check React re-render optimization (useMemo, useCallback)
- Estimate bundle size impact
- Detect N+1 queries
- Check asset loading strategy
checks:
- react_performance
- bundle_size
- database_queries
- asset_loading
## Aggregator Agent
name: "review-aggregator"
role: "Compile all findings into one GitHub comment"
dependencies: ["lint-analyzer", "security-scanner", "perf-analyzer"]
instructions: |
- Consolidate findings from all agents
- Categorize by severity (🔴 critical, 🟡 warning, 🟢 info)
- Format as GitHub markdown comment
- Tag file locations with line numbers
実装ステップ
Step 1:GitHub Webhook リスナーの構築
// webhook.js
const express = require ( 'express' );
const { OrchestratorManager } = require ( './orchestrator' );
const app = express ();
app. post ( '/webhook/github' , express. json (), async ( req , res ) => {
const { action , pull_request } = req.body;
if (action !== 'opened' && action !== 'synchronize' ) {
return res. sendStatus ( 200 );
}
const prNumber = pull_request.number;
const repo = pull_request.base.repo.full_name;
const diff = await fetchPRDiff (repo, prNumber);
// Manager Agent に委託
const orchestrator = new OrchestratorManager (diff, repo, prNumber);
orchestrator. run (). then ( reviews => {
postGitHubComment (repo, prNumber, reviews);
});
res. sendStatus ( 202 ); // Accepted, 非同期処理
});
Step 2:各専門エージェントの実装
// agents/lint-analyzer.js
class LintAnalyzer extends SubAgent {
async analyze ( diff ) {
const files = this . parseFiles (diff);
const issues = [];
for ( const file of files) {
if ( ! file.name. endsWith ( '.ts' ) && ! file.name. endsWith ( '.tsx' )) {
continue ;
}
const fileContent = await getFileContent (file.name);
// ESLint スタイルチェック
const eslintResults = await this . runESLint (fileContent);
issues. push ( ... eslintResults. map ( r => ({
type: 'lint' ,
file: file.name,
line: r.line,
message: r.message,
severity: r.severity
})));
// 型安全性チェック
const typeErrors = await this . checkTypeScript (fileContent);
issues. push ( ... typeErrors);
}
return {
agent: 'lint-analyzer' ,
issues,
summary: `Found ${ issues . length } issues`
};
}
}
// agents/security-scanner.js
class SecurityScanner extends SubAgent {
async analyze ( diff ) {
const findings = [];
// Secret 検出
const secrets = this . detectSecrets (diff);
if (secrets. length > 0 ) {
findings. push ({
type: 'security_critical' ,
message: `Hardcoded secret detected: ${ secrets [ 0 ] }` ,
severity: 'critical'
});
}
// 依存関係チェック
const vulnDeps = await this . auditDependencies ();
findings. push ( ... vulnDeps. map ( v => ({
type: 'vulnerability' ,
message: `${ v . package } has known CVE: ${ v . cve }` ,
severity: 'high'
})));
// SQLインジェクションパターン検出
const sqlInjections = this . detectSQLInjection (diff);
findings. push ( ... sqlInjections);
return {
agent: 'security-scanner' ,
findings,
summary: `${ findings . filter ( f => f . severity === 'critical' ). length } critical issues`
};
}
}
Step 3:集約エージェントが結果をマージ
// agents/review-aggregator.js
class ReviewAggregator extends SubAgent {
async aggregate ( lintResults , securityResults , perfResults ) {
const allFindings = [
... lintResults.issues,
... securityResults.findings,
... perfResults.issues
];
// 重要度でソート
const sorted = allFindings. sort (( a , b ) => {
const severityMap = { critical: 3 , high: 2 , warning: 1 , info: 0 };
return severityMap[b.severity] - severityMap[a.severity];
});
// GitHub マークダウン形式で生成
let comment = '## 🤖 Automated Code Review \n\n ' ;
const critical = sorted. filter ( f => f.severity === 'critical' );
if (critical. length > 0 ) {
comment += `### 🔴 Critical Issues (${ critical . length }) \n ` ;
critical. forEach ( issue => {
comment += `- **${ issue . file }:${ issue . line }** - ${ issue . message } \n ` ;
});
comment += ' \n ' ;
}
// ...他のセクション同様
return comment;
}
}
Step 4:リアルタイムで GitHub に投稿
// post-to-github.js
async function postGitHubComment ( repo , prNumber , reviewComment ) {
const [ owner , repoName ] = repo. split ( '/' );
const response = await github.rest.issues. createComment ({
owner,
repo: repoName,
issue_number: prNumber,
body: reviewComment
});
console. log ( `Comment posted: ${ response . data . html_url }` );
}
この実装により、PR作成時に自動的に以下が実行されます:
3つの専門エージェントが並列にレビュー
結果が集約されて GitHub コメントとして投稿
開発者が即座にフィードバックを受け取れること
デバッグとモニタリング——エージェント間通信の可視化
マルチエージェントシステムは、どこで何が起きたのかが見えにくくなります。調査の入口を先に決めておきます。
ログの確認方法
各エージェントの実行ログを構造化して記録:
{
"timestamp" : "2026-04-07T10:15:30Z" ,
"transaction_id" : "mgr-001-23049" ,
"phase" : "task_decomposition" ,
"manager_input" : "Build shopping cart API" ,
"decomposition_result" : [
{
"task_id" : "db-001" ,
"agent" : "database-specialist" ,
"status" : "queued"
},
{
"task_id" : "api-001" ,
"agent" : "backend-specialist" ,
"status" : "queued" ,
"depends_on" : [ "db-001" ]
}
],
"timestamp_end" : "2026-04-07T10:15:32Z" ,
"duration_ms" : 2000
}
ログビューア:
# 特定のトランザクションを追跡
cat orchestration.log | jq '.[] | select(.transaction_id == "mgr-001-23049")'
# エージェント別実行時間を集計
cat orchestration.log | jq 'group_by(.agent) | map({agent: .[0].agent, avg_time: (map(.duration_ms) | add / length)})'
# エラーが発生したタスクを検索
cat orchestration.log | jq '.[] | select(.status == "failed")'
エラーの特定とトレース
エージェントがタスク失敗した場合:
{
"transaction_id" : "mgr-001-23049" ,
"task_id" : "db-001" ,
"agent" : "database-specialist" ,
"status" : "failed" ,
"error" : {
"type" : "ValidationError" ,
"message" : "Invalid schema: column 'user_id' missing foreign key" ,
"context" : {
"input_requirements" : "Generate cart schema with user_id FK" ,
"output_received" : "CREATE TABLE cart ..." ,
"validation_rule" : "FK constraints must match entities"
}
},
"retry_count" : 1 ,
"next_action" : "retry with additional context"
}
デバッグ手順:
エラーメッセージの読み込み :何が失敗したか
コンテキスト確認 :エージェントが受け取った入力は正しいか
エージェント指示の見直し :AGENTS.md で指示が曖昧でないか
サンプル出力との比較 :期待する出力形式が明確か
パフォーマンスボトルネックの発見
全タスクの実行時間を可視化:
Task db-001 (database-specialist) ████████░░ 8s
Task api-001 (backend-specialist) ██████████ 10s ← 最長
Task test-001 (qa-specialist) ███████░░░ 7s
─────────────────────────────────────
Total (sequential) = 25s
Total (optimal parallel) = 10s
Efficiency = 25/10 = 2.5倍
ボトルネック: backend-specialist が遅い理由を調査
→ API数が多すぎる、指示が不明確、トークン上限に達している等
ボトルネック解決策:
タスク分割細分化 :1つの大きなタスクを複数に分割
キャッシング :以前のタスク結果を再利用
エージェント指示の最適化 :不要な出力を削除
リソース割当て :高性能なモデルを使用
本番環境への移行チェックリスト
マルチエージェントシステムを本番運用するには、多くの準備が必要です。以下のチェックリストを確認してください。
セキュリティ(Security)
コスト管理(Cost Management)
[ ] LLM トークン消費の最適化
[ ] 平均トークン消費量を測定(タスク種別ごと)
[ ] キャッシングで重複呼び出しを削減
[ ] プロンプト長を最小化(不要な情報削除)
[ ] 予算と上限設定
[ ] 月間トークン予算を設定
[ ] 上限到達時のアラート機構
[ ] コスト超過時の自動停止機構
実装例 :
// cost-manager.js
class CostManager {
constructor ( monthlyBudget = 1000 ) {
this .budget = monthlyBudget;
this .currentSpend = 0 ;
}
async executeWithCostControl ( agent , task ) {
const estimatedTokens = this . estimateTokens (task);
const estimatedCost = estimatedTokens * COST_PER_TOKEN ;
if ( this .currentSpend + estimatedCost > this .budget) {
await sendAlert ( `Budget exceeded: $${ estimatedCost } would exceed limit` );
return null ;
}
const result = await agent. execute (task);
this .currentSpend += estimatedCost;
return result;
}
}
スケーリングと可用性(Scalability & Availability)
[ ] 並列処理のスケール
[ ] 同時実行エージェント数の上限を決定
[ ] キューイング機構で過負荷時のリクエスト管理
[ ] 長時間タスクはバックグラウンド化
[ ] エラーリカバリー
[ ] タスク失敗時のリトライロジック(最大3回推奨)
[ ] リトライ時の指数バックオフ
[ ] リトライ失敗時の人間へのエスカレーション
[ ] モニタリングとアラート
[ ] エージェント稼働率を監視
[ ] 応答時間 SLA を設定(通常 <5秒)
[ ] エラー率が閾値を超えたらアラート
実装例 :
// availability-manager.js
const retryConfig = {
maxRetries: 3 ,
baseDelay: 1000 , // 1 second
maxDelay: 30000 // 30 seconds
};
async function executeWithRetry ( agent , task ) {
let delay = retryConfig.baseDelay;
for ( let attempt = 0 ; attempt <= retryConfig.maxRetries; attempt ++ ) {
try {
return await agent. execute (task);
} catch (error) {
if (attempt === retryConfig.maxRetries) {
// エスカレーション
await escalateToHuman (agent, task, error);
throw error;
}
await sleep (Math. min (delay, retryConfig.maxDelay));
delay *= 2 ; // 指数バックオフ
}
}
}
品質保証(Quality Assurance)
[ ] 出力品質の検証
[ ] 各エージェント出力のスキーマ検証
[ ] 生成コードの構文チェック
[ ] 統合テストで全機能確認
[ ] パフォーマンステスト
[ ] 標準的なタスク実行時間を計測
[ ] ストレステスト(100並列エージェント等)
[ ] メモリ・CPU 使用率の監視
デプロイメント(Deployment)
[ ] 段階的ロールアウト
[ ] 本番前にステージング環境でテスト
[ ] 初期ユーザー数を制限(全体の10%)
[ ] 段階的に対象を拡大
[ ] ロールバック計画
[ ] 問題発生時の即時停止手順
[ ] 前バージョンへの復帰手順
[ ] 互換性を保つ API バージョニング
一人で複数の専門エージェントを束ねて分かったこと
ここからは設計論ではなく、私自身が実際に複数のエージェントを並行で動かしてきて得た手触りを共有させてください。私はいくつかのサイトと複数のモバイルアプリを一人で運用しており、整合性チェック・デプロイ監視といった役割を、性質ごとに分けたエージェントへ委ねています。
役割を分けた瞬間に楽になった、その理由
最初は欲張って、1つのエージェントに「記事を書いて、リンクを検証して、デプロイまで見届けて」と詰め込んでいました。結果として、どの工程で失敗したのかが追いにくく、修正のたびに全体を読み直すことになりました。
役割を Manager と専門サブエージェントに分けてからは、失敗が「どの専門家の担当範囲で起きたか」に局所化され、原因の切り分けが目に見えて速くなりました。オーケストレーションの価値は処理速度よりも、この 責任範囲の明確さ にあると感じています。
作業の種類によって、AIに任せられる度合いは大きく違う
並行運用のなかで、作業の性質ごとに委譲の向き不向きがはっきりしてきました。私の体感を表にまとめます。
数字で言えば、定型チェック系の作業は体感で8割以上をエージェントに任せられる一方、課金や権限が絡む工程は、どれだけプロンプトを工夫しても最後の確認を人間が握るべきだと考えています。ここを曖昧にすると、便利さと引き換えに取り返しのつかない事故を呼び込みます。
任せて事故りかけた場面
一度、デプロイ監視のエージェントに「異常があれば自動で前のバージョンへ戻す」役割まで持たせたことがありました。一見スマートでしたが、検知のしきい値が甘く、正常なデプロイまで巻き戻しかけたのです。
そこで学んだのは、自律の範囲は「可逆かどうか」で線を引く ということでした。やり直しがきく操作は委ねてよいのです。けれども本番への不可逆な反映だけは、エージェントが提案し人間が承認する形に戻しました。Manager Surface を設計するときは、各サブエージェントに与える権限がこの基準を超えていないか、必ず一度立ち止まって見直すようにしています。
全体を振り返って
マルチエージェント・オーケストレーションの本質は、たくさんのエージェントを動かすことではなく、責任の範囲を丁寧に切り分けること だと考えています。Manager Surface に調整を集約し、各サブエージェントには可逆な仕事を任せ、不可逆な判断は人間が握ります。この一線さえ守れれば、システムは無理なく育っていきます。
もし今あなたが一つのエージェントに多くを抱えさせて苦しんでいるなら、まずは最も定型的な工程を1つだけ切り出し、専門サブエージェントとして独立させてみてください。そこから得られる「原因の切り分けやすさ」が、次の一歩の設計を自然と教えてくれるはずです。
私自身まだ運用のなかで学び続けていますが、同じように一人で複数の関心事を抱える方の支えになれば嬉しいです。最後までお読みいただき、ありがとうございました。