エージェント相互交換フォーマット は何をしますか?
あなたはエージェントが通信に使用するデータ構造のエキスパートです。FIPA-ACLからMCP、A2Aに至るワイヤフォーマットを理解し、機械解析可能かつLLMフレンドリーなメッセージエンベロープ、機能カード、タスクペイロード、エラーシグナルを設計できます。
決定ポイント
プロトコル選択ツリー
エージェント通信シナリオ?
├── 単一エージェントがツールを呼び出す?
│ ├── ツールはローカルプロセス → MCP over stdio
│ └── ツールはリモートサービス → MCP over HTTP/SSE または OpenAI function calling
├── エージェント間通信?
│ ├── ディスカバリ + タスクライフサイクル + 非同期が必要 → A2A Protocol
│ ├── シンプルなリクエスト/レスポンス → JSON-RPC 2.0 カスタム
│ └── 既存フレームワークとの統合 → フレームワークのネイティブフォーマット
└── LLMからの構造化出力?
├── 機械可読ペイロード (API、スキーマ) → スキーマファースト (Zod/JSON Schema)
└── クリエイティブ/探索的コンテンツ → 事後検証パース
スキーマ厳格性判断
ペイロードタイプが以下の場合:
├── ツール呼び出しパラメータ → 常にスキーマファースト (構造なしでは破綻)
├── エージェント機能カード → 常にスキーマファースト (ディスカバリに信頼性が必要)
├── タスクハンドオフデータ → 常にスキーマファースト (自動化には構造が必要)
├── エラー/リトライシグナル → 常にスキーマファースト (プログラムによるリトライロジック)
├── クリエイティブなテキスト出力 → 常に事後検証 (スキーマが創造性を殺す)
├── 分析結果 → フォールバック抽出付き事後検証
└── 混合コンテンツ → Parts配列を使用: DataPartはスキーマファースト、TextPartは事後検証
ストリーミング vs バッチ判断
ユーザーエクスペリエンスに以下が必要な場合:
├── プログレッシブ出力 (ユーザー向け) → ストリーミング (SSE/WebSocket)
├── 長時間タスク (>30秒) → ステータス更新付きストリーミング
├── エージェント間パイプライン → バッチ (エラーハンドリングがクリーン)
├── コスト追跡が重要 → バッチ (事前にトークン数が既知)
├── ストリーム途中からの復旧が必要 → バッチ (ストリーミングのエラーハンドリングは複雑)
└── シンプルな統合 → バッチ (HTTP リクエスト/レスポンス)
障害モード
スキーマドリフト
症状: 以前動作していたエージェント間の実行時バリデーションエラー、TypeScriptのコンパイルは成功するが実行時は失敗 診断: スキーマ定義間のバージョン不一致、一方のエージェントが調整なしにスキーマを更新 修正: すべてのスキーマに明示的なバージョンフィールドを追加; 下位互換性チェックを実装; スキーマレジストリを使用して調整
メッセージ損失
症状: 会話が不完全に見える、エージェントが無限にリトライする、重複処理が発生する 診断: 重複排除メカニズムがない、相関IDが欠落、復旧なしのネットワーク問題 修正: UUIDメッセージIDを追加; 既視メッセージ追跡を実装; スレッディングにconversationIdを使用; 指数バックオフ付きリトライロジックを追加
コンテキストウィンドウオーバーフロー
症状: エージェントタスクが「コンテキストが長すぎる」で失敗、切り詰められた会話、不完全なツール結果 診断: ハンドオフでのトークンカウントなし、無制限のコンテキスト蓄積、要約の欠落 修正: Partごとのトークン推定; コンテキスト予算編成を実装; ドロップ可能な優先度システムを追加; 要約で圧縮
パーシングの硬直性
症状: エージェントが不正なJSONを出力、クリエイティブタスクが汎用的な応答を生成、高いリトライ率 診断: 探索的コンテンツにスキーマファーストを適用、過度に厳格なバリデーション、グレースフルデグラデーションの欠如 修正: クリエイティブコンテンツには事後検証を使用; 抽出フォールバックを実装; 探索的タスクでは制約を緩和
プロトコルバベルの塔
症状: エージェントのペアごとにカスタム変換が必要、統合の複雑さが爆発、メンテナンス負荷 診断: 各チームが独自のワイヤフォーマットを発明、標準化なし、NIH症候群 修正: ワイヤ標準としてJSON-RPC 2.0を採用; マルチエージェントにはA2Aを使用; レガシーシステム用のフォーマットアダプタを実装
実例
例1: コンテキストウィンドウ制限付きタスクハンドオフ
シナリオ: リサーチエージェント (32kコンテキスト) が、50kトークンのリサーチデータをコード生成エージェント (128kコンテキスト) にハンドオフ。
判断プロセス:
- 受信エージェントのコンテキスト予算を確認: 128k - 8k (システム) - 8k (出力) = 112k 利用可能
- リサーチデータ (50k) は収まるが、堅牢性のためにコンテキスト予算編成を適用
- 重要でないコンテキストを優先度ベースでドロップする構造でハンドオフ
// リサーチエージェントがハンドオフを準備
const contextHandoff: ContextHandoff = {
context: [
{ kind: 'text', text: summary, mimeType: 'text/markdown' },
{ kind: 'data', data: criticalFindings, schema: FindingsSchema },
{ kind: 'text', text: detailedNotes, mimeType: 'text/plain' }
],
estimatedTokens: 50000,
droppable: [
{ partIndex: 2, priority: 1, tokenEstimate: 30000 }, // 詳細メモを最初にドロップ
{ partIndex: 0, priority: 2, tokenEstimate: 15000 } // やむを得ない場合サマリをドロップ
],
summary: "主な発見: APIレート制限、非同期パターンが必要",
summaryTokens: 500
};
// コード生成エージェントが受信し予算を計算
const budget = calculateContextBudget(128000);
if (contextHandoff.estimatedTokens > budget.available) {
// 優先度の低いコンテキストをドロップ
let remainingBudget = budget.available;
const finalContext = contextHandoff.context.filter((part, index) => {
const droppable = contextHandoff.droppable?.find(d => d.partIndex === index);
if (droppable && droppable.tokenEstimate > remainingBudget) {
return false; // このPartをドロップ
}
remainingBudget -= droppable?.tokenEstimate || 1000;
return true;
});
}
初心者のミス: トークン推定なしで生のリサーチデータを渡し、下流でコンテキストオーバーフローを引き起こす。 エキスパートの対応: 明示的な予算編成とグレースフルデグラデーションでハンドオフを構造化。
例2: A2A vs MCPプロトコル選択
シナリオ: OCRエージェント、分析エージェント、フォーマットエージェントを使用したドキュメント処理システムを構築。
判断プロセス:
- 複数のエージェントが互いをディスカバリする必要がある → OpenAI関数呼び出しは除外
- エージェントは異なるサーバーで動作、非同期タスクライフサイクルが必要 → A2A ProtocolがMCPより優位
- 双方向通信とタスクステータスが必要 → A2Aの選択を確定
// ドキュメントがエージェントパイプラインを流れる
const ocrCard: AgentCard = {
agentId: 'ocr-service-v2',
name: 'OCR Document Reader',
url: 'https://ocr.company.com',
skills: [{
id: 'extract-text',
inputSchema: { /* PDF/画像スキーマ */ },
outputSchema: { /* 構造化テキストスキーマ */ }
}],
capabilities: {
streaming: true, // 長いOCRタスクにはステータス更新が必要
pushNotifications: true, // OCR完了時に通知
stateTransitionHistory: true // パイプラインの進捗を追跡
}
};
// OCRエージェントへのタスク送信
const ocrTask: Task = {
id: generateTaskId(),
state: 'submitted',
messages: [{
id: generateId(),
timestamp: new Date().toISOString(),
sender: { agentId: 'document-processor' },
recipient: { agentId: 'ocr-service-v2' },
conversationId: documentProcessingId,
parts: [
{ kind: 'file', name: 'contract.pdf', content: base64Content, mimeType: 'application/pdf' }
]
}],
artifacts: [],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
};
初心者のミス: 双方向非同期要件を考慮せず、「よりシンプル」という理由でMCPを選択する。 エキスパートの対応: サービスディスカバリ、タスクライフサイクル、マルチエージェントオーケストレーションにはA2Aが必要と認識。
例3: リトライロジックによるエラーリカバリ
シナリオ: 分析エージェントがレート制限により処理中に失敗、インテリジェントなリトライが必要。
判断プロセス:
- 構造化エラーコードからエラータイプを検出
- リトライ可能フラグとバックオフパラメータを確認
- ジッター付き指数バックオフを実装
- 最大リトライ回数超過後は人間にエスカレーション
// エージェントが構造化エラーを返す
const rateLimitError: AgentError = {
code: 'RATE_LIMITED',
message: 'APIクォータを超過しました。60秒後にもう一度お試しください。',
retryable: true,
retryAfterMs: 60000,
maxRetries: 3,
details: {
quotaType: 'requests_per_minute',
resetTime: '2025-01-08T10:15:00Z'
}
};
// 呼び出し側エージェントがリトライロジックを実装
async function callAgentWithRetry(agent: AgentCard, task: Task, attempt = 1): Promise<Task> {
try {
return await callAgent(agent, task);
} catch (error) {
if (error instanceof AgentError && error.retryable && attempt <= error.maxRetries) {
// ジッター付き指数バックオフ
const baseDelay = error.retryAfterMs || 1000;
const jitter = Math.random() * 0.1 * baseDelay;
const delay = baseDelay * Math.pow(2, attempt - 1) + jitter;
await sleep(delay);
return callAgentWithRetry(agent, task, attempt + 1);
} else {
// リトライ不可または最大試行回数超過
return {
...task,
state: 'failed',
artifacts: [{
id: generateId(),
name: 'error-report',
parts: [{ kind: 'error', ...error }],
createdAt: new Date().toISOString(),
index: 0
}]
};
}
}
}
初心者のミス: バックオフなしで即座にリトライ、または最初の失敗で諦める。 エキスパートの対応: 構造化エラーコードを使用し、適切なバックオフとエスカレーションでインテリジェントなリトライを実行。
品質ゲート
- すべてのメッセージエンベロープに一意の
id、conversationId、ISO-8601timestampが含まれている - Partsは型安全性のために
kindフィールドを持つ識別共用体を使用 - エージェントカードはディスカバリ可能な
.well-known/agent.jsonURL で公開されている - エラーオブジェクトには
retryableブール値と型付きcode列挙型が含まれている - コンテキストハンドオフにはトークン推定と優先度ベースのドロップが含まれている
- すべてのスキーマがラウンドトリップを検証: シリアライズ → デシリアライズ → 元と等価
- バイナリコンテンツはbase64埋め込みではなくURI参照を使用
- スキーマバージョン間で下位互換性が維持されている
- ストリーミングイベントには順序付けのための単調増加シーケンス番号が含まれている
- メッセージメタデータに機密データなし (適切な認証ヘッダーを使用)
NOT-FOR境界
このスキルは以下の用途には使用すべきではありません:
- 会話セマンティクス: エージェントが互いに何を言うか → 代わりに
agent-conversation-protocolsを使用 - オーケストレーショントポロジ: エージェントの接続方法 → 代わりに
multi-agent-coordinationを使用 - インフラストラクチャセットアップ: エージェントランタイムのデプロイ → 代わりに
agentic-infrastructure-2026を使用 - 単一エージェントフレームワーク: 個々のエージェントの構築 → 代わりに
ai-engineerを使用 - API設計: REST/GraphQL APIの設計 → 代わりに
api-design-patternsを使用
委任先:
- スキーマバリデーションロジック → Zod/ブランド型には
typescript-advanced-patternsを使用 - ネットワークトランスポート → HTTP/WebSocketセットアップには
systems-architectureを使用 - 認証フロー → OAuth2/JWT実装には
auth-patternsを使用