Agent2Agent(A2A)プロトコルの概要
はじめに
先日、Googleにより Agent2Agent(A2A) という AIエージェント同士が相互通信するためのプロトコルが発表されました。
AI関連のプロトコルということで、MCPとの関連性も興味深かったため、少し調査してみました。
公式ドキュメント
開発についての仕様は、以下の公式ドキュメントで公開されています。詳細はこちらをご参照ください。
A2Aプロトコルの概要
Agent2Agent Protocol(A2A)は、AIエージェント間の相互運用性を実現するオープンプロトコルです。
A2Aを使用することで、異なる環境にあるAIエージェントが、相互にコンテキストやデータを交換することができるようになります。
A2Aプロトコルの原則は次のようになっています。
特徴 | 説明 |
---|---|
シンプル | 既存の標準を再利用する |
エンタープライズ対応 | 認証、セキュリティ、プライバシー、追跡、監視に対応 |
非同期ファースト | (非常に)長時間実行されるタスクと人間参加型のプロセスを想定 |
モダリティに依存しません | テキスト、オーディオ/ビデオ、フォーム、iframe など多様な形式に対応 |
不透明な実行エージェント | 考え、計画、ツールを共有する必要はない |
エージェントカード(Agent Card)
A2Aをサポートするリモートエージェントは、エージェントの機能/スキルと認証要件を記述する JSON 形式のAgent Card(エージェントカード)を公開する必要があります。
エージェントカードは、クライアントがタスクを実行できる最適なエージェントを特定し、A2Aを使用してそのリモートエージェントと通信するための重要な情報を提供します。
フォーマット
エージェントカードは次のようなフォーマットで表現されます。
フォーマット(TypeScript)
interface AgentCard {
// エージェントの人間が読める名前(例:"レシピエージェント")
name: string;
// エージェントの説明。ユーザーや他のエージェントが、エージェントの機能を理解するために使われる。
// (例:"レシピや料理を手伝うエージェントです。")
description: string;
// エージェントがホストされているURL。
url: string;
// エージェントの提供元(任意)
provider?: {
organization: string; // 提供組織の名前
url: string; // 組織のウェブサイトURL
};
// エージェントのバージョン。形式はプロバイダーに依存。(例:"1.0.0")
version: string;
// エージェントのドキュメントへのURL(任意)
documentationUrl?: string;
// エージェントがサポートする追加機能(任意)
capabilities: {
streaming?: boolean; // SSE(サーバー送信イベント)をサポートするか
pushNotifications?: boolean; // クライアントへのプッシュ通知が可能か
stateTransitionHistory?: boolean; // タスクの状態遷移履歴を公開するか
};
// エージェントの認証要件(OpenAPIの認証構造に準拠)
authentication: {
schemes: string[]; // 使用可能なスキーム(例:"Basic", "Bearer")
credentials?: string; // 非公開カードに対してクライアントが使用すべき資格情報(任意)
};
// エージェント全体でサポートされている入力モード(MIMEタイプの配列)
defaultInputModes: string[];
// エージェント全体でサポートされている出力モード(MIMEタイプの配列)
defaultOutputModes: string[];
// エージェントが実行可能なスキルの一覧
skills: {
id: string; // スキルの一意な識別子
name: string; // スキルの人間が読める名前
description: string; // スキルの説明。ユーザーや他エージェントの理解を助ける
tags: string[]; // スキルに関連するタグ(例:"料理", "カスタマーサポート")
// スキルで実行可能な例(例:"パンのレシピが欲しい")
examples?: string[];
// スキル固有の入力モード(デフォルトと異なる場合)
inputModes?: string[];
// スキル固有の出力モード(デフォルトと異なる場合)
outputModes?: string[];
}[];
}
以下は、サンプルのJSONです。
{
"name": "Weather Forecast Agent",
"description": "天気予報情報を提供するエージェント",
"version": "1.0.0",
"url": "https://weather-agent.example.com",
"authentication": {
"schemes": ["oauth2"]
},
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/plain", "application/html"],
"capabilities": {
"streaming": true,
"pushNotifications": false
},
"skills": [
{
"id": "get-current-weather",
"name": "現在の天気を取得",
"description": "指定された場所の現在の天気情報を提供します",
"tags": ["weather", "current"],
"examples": ["東京の今日の天気は?", "大阪の現在の気温は?"]
},
{
"id": "get-forecast",
"name": "天気予報を取得",
"description": "指定された場所の数日間の天気予報を提供します",
"tags": ["weather", "forecast"],
"examples": ["東京の週間天気予報", "大阪の明日の天気は?"],
"outputModes": ["application/html"]
}
]
}
エージェントカードの配置
エージェントカードは、次のような標準化された場所に配置することが推奨されています。
https://base url/.well-known/agent.json
このような配置の標準化により、クライアントは、DNSを通じてサーバーのIPを見つけ、HTTP経由でエージェントカードを取得できるようになります。
また、システムがプライベートレジストリ(「エージェントカタログ」やプライベートマーケットプレイスなど)を維持することも想定されています。これにより、組織内でエージェントを効率的に発見し、管理することが可能になります。
コアオブジェクト
ここでは、A2Aプロトコルで使われるコアのオブジェクトについて解説します。これらはA2Aプロトコルのインターフェース内でやり取りされます。
Task(タスク)
タスクは、クライアントとリモートエージェントが特定の結果を達成し、成果物を生成できるようにするステートフルなエンティティです。
クライアントとエージェントは基本的にタスク単位でやり取りを行います。
タスクは、セッション
という単位に複数紐づく可能性があり、オプショナルなsessionId
を持つことができます。
フォーマット
タスクは次のようなフォーマットで表現されます。
フォーマット(TypeScript)
// タスク情報を表すインターフェース
interface Task {
id: string; // タスクの一意な識別子
sessionId: string; // タスクを含むセッションのクライアント生成ID
status: TaskStatus; // タスクの現在の状態
history?: Message[]; // 過去のメッセージ履歴(任意)
artifacts?: Artifact[]; // エージェントが生成した成果物(任意)
metadata?: Record<string, any>; // 拡張用メタデータ(任意)
}
// タスクの状態とステータスメッセージ
interface TaskStatus {
state: TaskState; // 現在のタスク状態
message?: Message; // ステータスに関する追加メッセージ(任意)
timestamp?: string; // タイムスタンプ(ISO形式)(任意)
}
// タスク状態更新イベント(sendSubscribe または subscribe 時にサーバーから送信)
interface TaskStatusUpdateEvent {
id: string; // タスクID
status: TaskStatus; // タスクの新しい状態
final: boolean; // ストリームの終了を示すフラグ
metadata?: Record<string, any>; // 拡張メタデータ(任意)
}
// タスクの成果物更新イベント(sendSubscribe または subscribe 時にサーバーから送信)
interface TaskArtifactUpdateEvent {
id: string; // タスクID
artifact: Artifact; // 新しく追加または更新された成果物
metadata?: Record<string, any>; // 拡張メタデータ(任意)
}
// クライアントがエージェントに送るタスク作成・継続・再開のリクエスト
interface TaskSendParams {
id: string; // タスクID
sessionId?: string; // セッションID(未指定の場合はサーバー側で新規発行)
message: Message; // 実行したい内容のメッセージ
historyLength?: number; // メッセージ履歴の取得数(任意)
pushNotification?: PushNotificationConfig; // プッシュ通知設定(任意)
metadata?: Record<string, any>; // 拡張メタデータ(任意)
}
type TaskState =
| "submitted" // 提出済み
| "working" // 実行中
| "input-required" // 入力待ち
| "completed" // 完了
| "canceled" // キャンセル済み
| "failed" // 失敗
| "unknown"; // 不明
以下は、サンプルのJSONです。
{
"jsonrpc": "2.0",
"id": 1,
"method": "tasks/send",
"params": {
"id": "de38c76d-d54c-436c-8b9f-4c2703648d64",
"message": {
"role": "user",
"data": [
{
"type": "text",
"text": "東京の明日の天気を教えてください"
}
]
},
"metadata": {}
}
}
Artifact(アーティファクト)
アーティファクトは、エージェントがタスクの最終結果として生成するものです。アーティファクトは不変で、名前を付けることができ、複数のPartを持つことができます。
1つのタスクは複数のアーティファクトを生成できます。例えば、「ウェブページを作成する」というタスクは、HTML と画像の別々のアーティファクトを作成する可能性があります。
フォーマット
アーティファクトは次のようなフォーマットで表現されます。
interface Artifact {
name?: string;
description?: string;
parts: Part[];
metadata?: Record<string, any>;
index: number;
append?: boolean;
lastChunk?: boolean;
}
以下は、サンプルのJSONです。
{
"artifacts": [
{
"name": "東京の天気予報",
"parts": [
{
"type": "text",
"text": "東京の明日の天気予報:晴れ、最高気温28℃、最低気温20℃、降水確率10%"
}
]
}
]
}
Message(メッセージ)
メッセージは、ユーザーやエージェントからの指示やメッセージを表現します。クライアントからのすべてのコンテンツはメッセージの形式で送信されます。エージェントは、成果物(アーティファクト)とは別に、ステータスを伝えたり指示を提供したりするためにメッセージを送信します。
フォーマット
メッセージは次のようなフォーマットで表現されます。
interface Message {
role: "user" | "agent";
parts: Part[];
metadata?: Record<string, any>;
}
以下は、サンプルのJSONです。
{
"messages": [
{
"role": "agent",
"data": [
{
"type": "text",
"text": "東京の明日の天気予報を取得しています。少々お待ちください..."
}
]
}
]
}
Part(パーツ)
パーツは、メッセージまたはアーティファクトの一部として使用されるコンテンツを表現するオブジェクトです。各パーツは独自のコンテンツタイプとメタデータを持ちます。
フォーマット
パーツは次のようなフォーマットで表現されます。
interface TextPart {
type: "text";
text: string;
}
interface FilePart {
type: "file";
file: {
name?: string;
mimeType?: string;
// oneof {
bytes?: string; //base64 encoded content
uri?: string;
//}
};
}
interface DataPart {
type: "data";
data: Record<string, any>;
}
type Part = (TextPart | FilePart | DataPart) & {
metadata: Record<string, any>;
};
以下は、サンプルのJSONです。
{
"type": "file",
"file": {
"name": "weather_chart.png",
"mimeType": "image/png",
"bytes": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
},
"metadata": {
"description": "東京の週間天気予報チャート",
"timestamp": "2025-04-10T08:15:00+09:00",
"fileSize": 123456
}
}
MCPと A2Aの関係
Model Context Protocol(MCP)と Agent2Agent Protocol(A2A)の関連について、次のような使い分けを想定されています。
プロトコル | 役割 |
---|---|
MCP | LLM とデータ、リソース、ツールを接続するためのプロトコル。LLM エージェントから異なるツールを呼び出すために使用されます。 |
A2A | エージェント間の対話や協調を実現するための高レベル(アプリケーションレベル)なプロトコル。エージェント同士が効果的に連携し、タスクを遂行するためのフレームワークを提供します。 |
A2Aエージェントを MCP リソースとしてモデル化する例
ドキュメントでは、A2Aのエージェント(AgentCard)を MCPプロトコルによって提供し、接続後は A2Aのプロトコルでやり取りするという協調事例が説明されています。
MCPは、A2Aのエージェントカードの場所のみ提供するイメージでしょうか。
まとめ
Agent2Agent Protocol(A2A)は、異なるエージェントシステム間の相互運用性を実現するためのオープンプロトコルです。
A2Aが未来広がっていくと、様々なケースでAI同士が自由にやり取りできるようになるため、よりAIの拡張性が広がっていきそうです。
AIがインターネットのように繋がりだすと、現時点では想像できないような世界になりそうですね。
Discussion