「AIに仕事を奪われるか」を眺める側ではなく、
AI同士をどう協働させ、顧客価値に変えるかを設計する側へ。
私たちは、新技術を知っているだけでは十分だと考えていません。
お客様の困りごとを理解し、仲間と知恵を出し合い、実際に動く仕組みへ変える。そこまでやり抜いて、初めて技術は価値になります。
コードを書く力の、その先へ。
「複数のAIエージェントを束ねて、お客様の仕事そのものを良くする」。A2Aは、その挑戦にぴったりのテーマです。
この記事では、A2Aの概要だけでなく、システムエンジニアが設計・実装・運用で押さえるべきポイントまで、具体例を交えて解説します。
A2Aとは何か
A2Aは、異なるAIエージェント同士が、互いの能力を見つけ、仕事を依頼し、途中経過や成果物をやり取りするための共通プロトコルです。
たとえば、次のようなエージェントが別々の言語・フレームワーク・クラウドで動いているとします。
- 問い合わせを受け付け、作業を振り分けるエージェント
- ログを解析するエージェント
- ソースコードの変更影響を調べるエージェント
- テストケースを作るエージェント
- 報告書をまとめるエージェント
A2Aを使えば、内部実装を公開せずに、各エージェントを「専門性を持ったチーム」として連携できます。
A2AはGoogleが最初に開発し、現在はLinux Foundation配下のオープンソースプロジェクトとして運営されています。2026年3月には、最初の安定版であるv1.0が公開されました。公式仕様では、異なるエージェント間の能力発見、通信、タスク管理、安全な情報交換が標準化されています。
なぜ、普通のREST APIだけでは足りないのか
もちろん、エージェント同士を独自のREST APIで接続することは可能です。
しかし、接続先が増えるたびに、次のような“つなぎ込み”を個別設計することになります。
- 相手は何ができるのか
- どの形式で入力すればよいのか
- 処理が数分・数時間かかる場合、どう状態を確認するのか
- 追加情報が必要になった場合、どう聞き返すのか
- 途中経過や複数の成果物をどう受け取るのか
- 認証方式やプロトコルバージョンをどう共有するのか
一般的なAPIが「決められた機能を呼び出すインターフェース」だとすれば、A2Aは判断しながら仕事を進める相手と協働するためのインターフェースです。
A2Aでは、エージェントの内部プロンプト、メモリ、ツール、独自ロジックを相手へ公開する必要がありません。依頼側は「何を実現したいか」を伝え、受け手は自分の責任範囲で計画・処理し、標準化された状態と成果物を返します。
つまりA2Aは、エージェント版の“共通業務契約”と捉えると理解しやすいでしょう。
A2AとMCPの違い
A2Aと一緒に語られることが多いのが、MCP(Model Context Protocol)です。
結論から言えば、競合ではなく補完関係です。
| 観点 | 一般的なREST API | MCP | A2A |
|---|---|---|---|
| 主な接続 | アプリ → 機能・リソース | AI/エージェント → ツール・データ | エージェント → 別のエージェント |
| 相手の役割 | 決められた処理を実行 | 必要な道具や情報を提供 | 目標を受け取り、判断しながら仕事を進める |
| 代表的な単位 | エンドポイント、リソース | Tool、Resource、Prompt | Agent Card、Message、Task、Artifact |
| 長時間処理 | APIごとに個別設計 | 実装・ツール定義による | Task、Streaming、Webhookで標準化 |
| 複数ターン | APIごとに個別設計 | 主目的ではない |
contextId、taskIdで継続可能 |
| 内部実装の公開 | API仕様のみ公開 | ツール仕様などを公開 | 能力と入出力契約だけ公開し、内部は隠せる |
イメージとしては、次の使い分けです。
A2A:誰に仕事を任せるか、エージェント同士をつなぐ
MCP:仕事に必要な道具やデータへ、エージェントをつなぐ
たとえば障害調査エージェントが、別のテスト設計エージェントへ調査結果を引き継ぐ部分はA2A。障害調査エージェントがログ基盤やチケット管理、DBの参照ツールを使う部分はMCP、という構成です。
公式ドキュメントでも、MCPはツール・データへの接続、A2Aはエージェント間の協働を担うものとして整理されています。
参考:A2AとMCPの関係
A2Aを理解する5つの構成要素
1. Agent Card:エージェントの“名刺兼サービス仕様書”
A2A Serverは、自分の名前、説明、接続先、対応プロトコル、能力、スキル、入出力形式、認証方式などをAgent Cardとして公開します。
標準の公開先は、次のURLです。
https://{domain}/.well-known/agent-card.json
クライアント側は、いきなり仕事を依頼するのではなく、まずAgent Cardを取得して、次を判断します。
- 求めるスキルを持っているか
- 入力・出力のMIMEタイプが合うか
- StreamingやPush Notificationを使えるか
- JSON-RPC、gRPC、HTTP+JSONのどれで接続できるか
- どの認証方式が必要か
- 対応するA2Aバージョンは何か
以下は、障害一次調査エージェントを想定した最小構成例です。
{
"name": "Incident Triage Agent",
"description": "ログと事象情報から障害の原因候補と次の確認項目を整理します。",
"supportedInterfaces": [
{
"url": "https://agents.example.com/incident",
"protocolBinding": "HTTP+JSON",
"protocolVersion": "1.0"
}
],
"version": "1.0.0",
"capabilities": {
"streaming": true,
"pushNotifications": false,
"extendedAgentCard": false
},
"securitySchemes": {
"bearerAuth": {
"httpAuthSecurityScheme": {
"scheme": "Bearer",
"bearerFormat": "JWT"
}
}
},
"securityRequirements": [
{
"schemes": {
"bearerAuth": {
"list": []
}
}
}
],
"defaultInputModes": ["text/plain", "application/json"],
"defaultOutputModes": ["application/json", "text/markdown"],
"skills": [
{
"id": "incident-triage",
"name": "障害一次調査",
"description": "ログ、発生時刻、変更内容を基に原因候補と追加確認事項を返します。",
"tags": ["incident", "log-analysis", "troubleshooting"],
"examples": [
"直近のデプロイ後に発生したHTTP 500の原因候補を整理してください"
]
}
]
}
重要
Agent Cardは宣伝文ではなく、ルーティングと契約判定に使う情報です。descriptionやskillsを曖昧にすると、依頼側が誤ったエージェントを選びやすくなります。成功条件、対象外、入力に必要な情報まで具体化しましょう。
2. MessageとPart:依頼と会話の単位
Messageは、クライアントとエージェントの1回分のやり取りです。
内容は1つ以上のPartで構成され、v1.0では次を扱えます。
-
text:自然言語 -
data:構造化JSON -
url:ファイル参照 -
raw:Base64化したバイナリ
Partには上記4種類のうち、必ず1種類だけを設定します。
自然言語だけで依頼することもできますが、業務システムではdataを併用したほうが、入力の欠落や解釈違いを減らせます。
3. Task:状態を持つ仕事の単位
すぐに答えられる処理はMessageを直接返せます。調査や生成など、状態管理が必要な処理はTaskとして扱います。
主な状態は次のとおりです。
| 区分 | 状態 | 意味 |
|---|---|---|
| 実行中 | TASK_STATE_SUBMITTED |
受付済み |
| 実行中 | TASK_STATE_WORKING |
処理中 |
| 中断 | TASK_STATE_INPUT_REQUIRED |
追加情報が必要 |
| 中断 | TASK_STATE_AUTH_REQUIRED |
認証・認可や人の承認が必要 |
| 終了 | TASK_STATE_COMPLETED |
正常完了 |
| 終了 | TASK_STATE_FAILED |
エラー終了 |
| 終了 | TASK_STATE_CANCELED |
キャンセル済み |
| 終了 | TASK_STATE_REJECTED |
エージェントが実行を拒否 |
ここが、単純なAPI呼び出しとの大きな違いです。
「情報が足りないので質問する」「権限が必要なので止める」「長時間処理の途中経過を返す」といった、実務で起こる状態を共通モデルで扱えます。
4. Artifact:成果物の単位
ArtifactはTaskが生成した成果物です。
たとえば、次のようなものを返せます。
- 障害原因候補のJSON
- Markdown形式の調査報告書
- テストケース一覧
- 修正案のパッチファイル
- 画像、PDF、CSV
「チャットの返答」と「正式な成果物」を分けて扱えるため、後続エージェントや業務システムへ受け渡しやすくなります。
5. 更新方法:Polling、Streaming、Webhook
A2Aには、処理状況を受け取る3つの方法があります。
| 方法 | 向いている場面 | 注意点 |
|---|---|---|
| Polling(Get Task) | 小規模な連携、更新頻度が低い処理 | 無駄な問い合わせと遅延が増えやすい |
| Streaming | 対話画面、リアルタイム進捗表示 | 常時接続と再接続設計が必要 |
| Push Notification(Webhook) | サーバー間の長時間処理 | Webhook認証、重複、SSRF対策が必要 |
参考:Task Update Delivery Mechanisms
A2Aの基本フロー
流れはシンプルです。
- Agent Cardで相手の能力と接続条件を確認する
-
SendMessageで依頼する - すぐ終わらない場合はTaskを受け取る
- Polling、Streaming、Webhookのいずれかで進捗を受け取る
- 必要なら同じ
taskIdで追加情報を送る - 完了後にArtifactを後続処理へ渡す
HTTP+JSONで依頼してみる
A2A v1.0は、標準バインディングとしてJSONRPC、GRPC、HTTP+JSONを定義しています。ここでは構造が見やすいHTTP+JSONの例を示します。
1. Agent Cardを取得する
curl --silent --show-error \
https://agents.example.com/.well-known/agent-card.json
2. 非同期で障害調査を依頼する
curl --request POST \
--url https://agents.example.com/incident/message:send \
--header 'Authorization: Bearer <access-token>' \
--header 'A2A-Version: 1.0' \
--header 'Content-Type: application/a2a+json' \
--data '{
"message": {
"messageId": "0f8fad5b-d9cb-469f-a165-70867728950e",
"role": "ROLE_USER",
"parts": [
{
"text": "デプロイ後に増えたHTTP 500の原因候補と、次に確認すべき項目を整理してください。"
},
{
"data": {
"incidentId": "INC-2026-0825-001",
"environment": "staging",
"occurredAt": "2026-08-25T01:30:00+09:00",
"changedComponents": ["OrderApi", "PaymentAdapter"]
},
"mediaType": "application/json"
}
]
},
"configuration": {
"acceptedOutputModes": ["application/json", "text/markdown"],
"returnImmediately": true,
"historyLength": 5
}
}'
returnImmediately: trueを指定すると、サーバーはTaskを作成した後、完了を待たずに応答します。
{
"task": {
"id": "9ef5c0a1-8f64-4b91-a258-9a6d62f56152",
"contextId": "a8d478aa-2d51-4f7f-86e1-820c98bc9d9e",
"status": {
"state": "TASK_STATE_SUBMITTED",
"timestamp": "2026-08-24T16:30:01Z"
}
}
}
その後は、Task取得、TaskへのSubscribe、Webhookのいずれかで完了を待ちます。
v0.3の記事を参考にするときの注意
v1.0では、JSON-RPCの操作名がmessage/sendからSendMessageへ変わり、Task StateやRoleの列挙値もTASK_STATE_*、ROLE_*形式になりました。HTTP+JSONではPOST /message:sendを使います。古いサンプルをそのままコピーしないようにしてください。
参考:What's New in A2A v1.0
システムエンジニアが押さえるべき設計の勘所
1. エージェントは“モデル別”ではなく“責任別”に分ける
「Geminiエージェント」「Claudeエージェント」のようにモデル名で分割すると、業務上の責任が曖昧になりがちです。
分割基準は、次のような業務責任に置きます。
- 問い合わせの分類と振り分け
- ログの分析と原因候補の提示
- 変更影響の確認
- セキュリティ観点のレビュー
- テストケースの生成と不足確認
- 最終報告の統合
各エージェントについて、入力、出力、成功条件、タイムアウト、権限、実行してよい操作を定義します。
1エージェント1責任に近づけるほど、テストしやすく、障害範囲も限定できます。
2. 自然言語だけで連携しない
自然言語は柔軟ですが、業務連携の契約としては曖昧です。
重要項目はdata Partで構造化し、JSON Schemaなどで別途契約を管理しましょう。
{
"hypotheses": [
{
"cause": "PaymentAdapterのタイムアウト増加",
"confidence": 0.78,
"evidenceIds": ["log-1042", "metric-221"],
"nextChecks": ["外部APIのp95応答時間を確認"]
}
],
"requiresHumanDecision": false
}
特に、次の項目を固定すると後続処理が安定します。
- 必須項目と型
- 日時・タイムゾーン
- ID体系
- 信頼度の尺度
- 根拠の参照方法
- エラー形式
- 個人情報・機密情報の扱い
- スキーマバージョン
3. A2Aを“分散システム”として設計する
相手がAIであっても、通信部分で起こる問題は通常の分散システムと同じです。
- タイムアウト
- 応答遅延
- 一時的な接続失敗
- 二重送信
- 順序の入れ替わり
- 部分成功
- 再起動後の状態不整合
最低限、次を設計します。
-
messageIdによる重複検知 - Task状態の永続化
- 再試行対象となるエラーの限定
- 指数バックオフと上限回数
- Task単位のタイムアウトとCancel
- サーキットブレーカー
- 途中まで実行した処理の補償方法
A2A仕様上、SendMessageの冪等性は任意です。サーバー側がmessageIdを使って重複を検知できるようにすること、クライアント側が**「タイムアウトしたから同じ依頼を無条件で再送する」設計にしないこと**が重要です。
また、Streaming接続が切れた場合に、すべてのメッセージを再取得できるとは限りません。重要な完了確認は、Taskの最終状態を取得して確定させましょう。
4. “できること”と“実行してよいこと”を分ける
A2Aで能力を発見できても、その操作を常に実行してよいわけではありません。
たとえば、障害調査エージェントが次の能力を持っていたとします。
- ログを読む
- DBを参照する
- 設定を変更する
- サービスを再起動する
前半2つと後半2つでは、必要な権限と事故時の影響が大きく違います。
本番では、次を徹底します。
- HTTPS/TLSを必須にする
- すべてのリクエストで認証・認可を確認する
- ユーザー、組織、プロジェクト、テナント単位でアクセス範囲を絞る
- エージェントごとに最小権限の資格情報を発行する
- Task履歴やArtifactに秘密情報を残さない
- 破壊的操作は人の承認を必須にする
- Agent Cardの署名を検証し、なりすましを防ぐ
- Webhook URLを検証し、SSRFを防ぐ
A2A v1.0では、JWSによる署名付きAgent Cardや、処理途中で認証・承認を求めるTASK_STATE_AUTH_REQUIREDを利用できます。ただし、A2Aが認可ポリシーそのものを決めてくれるわけではありません。最終的な権限境界は、システム側で設計する必要があります。
参考:A2A Security Considerations
5. エージェント間の“仕事の履歴”を観測可能にする
マルチエージェント化すると、最終回答だけを見ても、どこで誤ったか分かりません。
少なくとも、次を追跡できるようにします。
traceIdcontextIdtaskIdmessageId- 呼び出したエージェントとSkill
- 認証された主体と権限範囲
- 入出力のスキーマバージョン
- 使用モデル、プロンプト、設定のバージョン
- 開始・終了時刻、待ち時間、再試行回数
- トークン数、利用料金、外部API費用
- 最終状態と人による修正内容
ログへ本文を丸ごと保存するのではなく、個人情報や機密情報をマスキングし、必要に応じてハッシュや参照IDで追跡します。
6. “正しく動いたか”を、回答の自然さで判定しない
文章が流暢でも、業務上正しいとは限りません。
エージェントごとに評価データを用意し、次を測ります。
- Task完了率
- 正答率・根拠一致率
- 必須項目の充足率
- 人による修正率
- 誤った自動実行の件数
- p50 / p95処理時間
- 1Task当たりの費用
- 再試行率・重複実行率
- 既存業務と比べた削減時間
「AIを導入したか」ではなく、お客様の判断時間、手戻り、障害復旧時間をどれだけ改善したかで評価することが大切です。
A2Aが“やってくれないこと”
A2Aは強力ですが、万能なAI基盤ではありません。
A2Aが標準化するのは、主にエージェント間の発見・通信・Task管理です。次は別途設計が必要です。
- どのエージェントへ仕事を振るかという業務ルール
- プロンプトや推論の品質
- RAGやデータ更新の仕組み
- 認可ポリシーと秘密情報の管理
- 回答の正しさを測る評価基盤
- コスト上限と利用制御
- 障害時の補償処理
- 人が判断すべき境界
特に危険なのは、A2Aを導入しただけで「自律型AIシステムが完成した」と考えることです。
プロトコルがそろっても、責任分界、データ契約、権限、監視、評価が曖昧なら、連携先が増えた分だけ障害点も増えます。
まとめ:A2Aの本質は、接続ではなく協働にある
A2Aを一言で表すなら、AIエージェント同士が、互いの専門性を尊重しながら仕事を引き継ぐための共通言語です。
- Agent Cardで能力を知る
- Messageで依頼する
- Taskで仕事の状態を共有する
- Artifactで成果を引き継ぐ
- MCPで各エージェントを道具やデータにつなぐ
- 認証・認可、監視、評価、人の承認で安全に運用する
ただし、共通言語があるだけでは、良いチームにはなりません。
どの顧客価値を目指すのか。
誰が何に責任を持つのか。
どこまでAIに任せ、どこで人が判断するのか。
失敗から何を学び、どう仲間へ共有するのか。
それを設計するのは、私たちシステムエンジニアです。
エスプリフォートが目指すのは、「AIを使った会社」ではありません。
技術、理解力、主体性、仲間との協働を掛け合わせ、お客様にも、働く私たちにも、より大きな価値を生み出せる会社です。
「指示された機能を作る」から、「顧客の仕事そのものを良くする仕組みを設計する」へ。
新しい技術を、誰かの研究テーマで終わらせず、仲間と試し、学び、実装までやり抜きたい。
そんなエンジニアにとって、エスプリフォートはきっと、おもしろい挑戦ができる場所です。
