🍣

10分くらいでできるA2Aのはじめ方

に公開

(2025/05/08)uv venvの手順に誤りがあり修正しました。

概要

対象者:エージェント連携やA2Aに興味のあるAIエンジニアや開発者
内容:Google製のA2Aプロトコルを用いた複数エージェント連携チュートリアルの実践解説
できること:複数のAIエージェントをA2Aで接続し、統合チャットUIから対話・実行できるようになる

序説

本日、A2Aチュートリアルを触りました。
1回目構築: 1時間30分(エラーで2回ハマる)
2回目構築: 10分くらい !? ※個人差あり
という感じでちょっと詰まった部分がありましたので、共有したいと思います!

A2Aとは

エージェントとエージェントをつなげるプロトコルです!
たとえば、チャットボット・画像生成・為替変換など異なるAIサービスを連携させて、一貫したユーザー体験を提供できます。

An open protocol enabling communication and interoperability between opaque agentic applications.

https://github.com/google/A2A/tree/main

作るもの

この図のようなものを作ります。
ユーザが何か入力したら、ホストエージェントが、どのエージェント動かせるか確認し、
A2Aを介して、各エージェントに依頼し、実行し、結果を返し、ホストエージェントがいい感じにまとめ、ユーザに返す。
こんなチュートリアルがあるのでやってみましょう!

事前準備

  • python3.12以上
  • uv
  • gemini apiキー

手順

セットアップ

まず、以下のコマンドよりgitcloneします。

git clone https://github.com/google/A2A.git
cd A2A

目安ここまでで1分くらいです。(ここまでは大丈夫ですよね!)

gemini apiキー取得

https://aistudio.google.com/app/apikey
ここから取得できます。
Get API keyから、Create API keyを選択し、取得します。

セキュリティに注意!
.env ファイルには秘密情報が含まれるため、Gitにコミットしないよう .gitignore に追加しておきましょう。

目安ここまでで2分くらいです。(ここもよくあるやつですよね!)

リモートエージェント

uv の仮想環境を作り、リモートエージェントを立ち上げる作業をします。

エージェント ポート 機能概要
経費申請エージェント 10000 ユーザーの入力をもとに仮の経費申請処理を行う
画像生成エージェント 10001 テキストをもとに画像を生成する
為替エージェント 10002 円からドルへの為替変換を行う

経費申請エージェント作成

経費申請をしてくれる(?)エージェントを作成します。
※どこかフォームに送信されることはありません。
以下のコマンドより実装します。

cd samples/python/agents/google_adk
uv venv
source .venv/bin/activate
echo "GOOGLE_API_KEY=your_api_key_here" > .env
uv run . --host 0.0.0.0 --port 10000

※ uv venvで、仮想環境を作成します

画像生成エージェント

画像生成するエージェントを作成します。
別のターミナルを開き、以下のコマンドより実装します。
※先ほど起動した、localhost:10000は停止しないようにします。

cd samples/python/agents/langgraph
uv venv
source .venv/bin/activate
echo "GOOGLE_API_KEY=your_api_key_here" > .env
uv run . --host 0.0.0.0 --port 10001

為替エージェント

為替(円からドル計算など)をしてくれるエージェントを作成します。
別のターミナルを開き、以下のコマンドより実装します。
※先ほど起動した、localhost:10000、localhost:10001は停止しないようにします。

cd samples/python/agents/crewai
uv venv
source .venv/bin/activate
echo "GOOGLE_API_KEY=your_api_key_here" > .env
uv run . --host 0.0.0.0 --port 10002

missing field ‘version’

以下のエラーが出ない場合は、スキップしてください。

error: Failed to parse `uv.lock`
  Caused by: TOML parse error at line 1, column 1
  |
1 | revision = 2
  | ^^^^^^^^^^^^
missing field `version`

versionがないので、エラーが出ていますので、versionを追加します。
samples/python/uv.lockの先頭に以下追加します。

version = 1

目安ここまでで6分くらいです。(ここまで作成完了していれば、もう少しです!)

ホストエージェント作成

3つのリモートエージェントとA2Aで接続するエージェントです。
別のターミナルを開き、以下のコマンドより実装します。

cd demo/ui
uv venv
source .venv/bin/activate
uv run main.py

成功すると、以下表示されます。

以下のurlをブラウザから開きます。

http://0.0.0.0:12000/

about blank

http://0.0.0.0:12000/ で開けた人はスキップしてください。

http://0.0.0.0:12000/ のままでは、開かない可能性があります。

その場合は、urlを以下に直してみてください

http://localhost:12000

以下の画面が表示されれば、成功です。

目安ここまでで8分くらいです。(ほぼゴール直前!)

エージェントカード追加

左のタブから「Agents」を選択します。
そして、リスト一覧にある「↑」を選択します。
Agent Addressには、以下のリモートエージェントのアドレスを追加します。

0.0.0.0:10000

追加されるエージェントを確認し、Saveを選択します。
同様の手順で、別のエージェントも追加します。

0.0.0.0:10001
0.0.0.0:10002

目安ここまでで9分くらいです。(ほぼゴールしました。おめでとうございます!)

チャットのテスト

左のタブより「Home」を選択します。
そして、リストにある「+」を選択します。
そうすると、チャットボットが動きます。
はじめにおすすめの聞き方として、どういうエージェントがあるのか聞くと良さそうです。

あなたは、何ができます?

あとは、そのエージェントとやりとりを楽しんでください!

「画像を生成して」
「1万円をドルに換算して」
「経費申請をお願い」

こんな感じで、10分くらいでできると思います!(お疲れ様でした!)

流れ

ここでは、経費申請のエージェントがどいう流れか追ってみます。

  1. ユーザーがA2Aクライアントを通じてリクエストを送信
  2. A2Aサーバーがリクエストを受け取り、TaskManagerに転送
  3. TaskManagerがReimbursementAgentを呼び出し
  4. エージェントがフォームを生成し、ユーザーに返す
  5. ユーザーがフォームに入力して返信
  6. エージェントが入力を検証し、経費精算を実行
  7. 結果をユーザーに返す

経費精算を実行は、agent.pyのreimburse()で実行していますが、
ただ、文字列"approved"を返しているだけです。
本来は、ここのreturnの前に処理を追加する必要がありそうです。
https://github.com/google/A2A/blob/main/samples/python/agents/google_adk/agent.py#L93-L97

おまけ: 厳しい経費担当者にする

エージェントが入力を検証は、agent.pyの_build_agent()で実行しています。
よくみると、日付、金額、目的さえあれば承認するというシステムになってます。
https://github.com/google/A2A/blob/main/samples/python/agents/google_adk/agent.py#L119-L155

なので、例えば豪遊というとんでもない目的でも承認の判定になります。

そこで、一部instructionを変更してやることで、承認の判定を制御することができます。
例えば、以下のように変更してみます。

For valid reimbursement requests and valide use for business such as not private enjoyment, you can then use reimburse() to reimburse the employee.

すると、今度は、豪遊は適切でないと判断され拒否されました。

A2Aとは

さてここから本題なのですが、A2Aとは一体なんなのでしょうか?

An open protocol enabling communication and interoperability between opaque agentic applications.

冒頭でサラッと流したのですが、これ訳すと「不透明なエージェント アプリケーション間の通信と相互運用性を可能にするオープンプロトコル」なんですよ。
ちゃんと読むしかないですね!!

背景

まず、A2Aの作られた背景が書かれていました。

One of the biggest challenges in enterprise AI adoption is getting agents built on different frameworks and vendors to work together.That's why we created an open Agent2Agent (A2A) protocol,

Google is driving this open protocol initiative for the industry because we believe this protocol will be critical to support multi-agent communication by giving your agents a common language – irrespective of the framework or vendor they are built on.

今エージェントフレームワーク戦国時代が幕開けしているのですが、
一旦手をとりやって仲良くやって行こうじゃないですか。
それが、AI国の繁栄に繋がり、きっと将来役に立つと思うんですよ。(Google主体で)
という思想を感じました。

コア要素

用語 説明
Agent Skills エージェントがどういうことができるか。
Agent Capabilities エージェントがどのようにうのか。
Agent Card Agent Skills・Agent Capabilities・エンドポイントURL・認証要

Agent Skills

エージェントがエージェントがどういうことができるかという情報です。
例えば、今回のチュートリアルの該当箇所はこちらです。
https://github.com/google/A2A/blob/4d50971a30136bb96af631efdd5aaca87c9b5c6e/samples/python/agents/google_adk/__main__.py#L29-L35

仕様はここに書かれていました。
https://github.com/google/A2A/blob/main/specification/json/a2a.json#L133-L182
エージェントのid,名前、説明、tag,使用例などが設定できます。
ホストAgentがサーバAgentを選ぶ際、ここを元にする重要な要素です。
idとnameが必須でした。

項目 説明
id スキルのユニーク識別子。例:"translate-text"
name スキルの人間向け名称。例:"Text Translation"
description スキルの説明文。クライアントや人間がスキルの機能を理解するためのヒント。例:"Translate input text into multiple languages."
tags このスキルが属する能力クラスのタグ一覧。例:["translation", "language", "NLP"]
examples このスキルが対応できる具体的なプロンプト例。例:["Translate this to French", "How do you say 'hello' in Japanese?"]
inputModes 入力に対応するMIMEタイプ一覧(任意)。例:["text/plain", "application/json"]
outputModes 出力に対応するMIMEタイプ一覧(任意)。例:["text/plain", "application/json"]

Agent Capabilites

エージェントがどのように通信できるかという情報です。
例えば、今回のチュートリアルの該当箇所はこちらです。
https://github.com/google/A2A/blob/main/samples/python/agents/google_adk/__main__.py#L28

仕様はここに書かれていました。
https://github.com/google/A2A/blob/main/specification/json/a2a.json#L26-L46

  1. streaming
    trueの場合、エージェントはServer-Sent Events(SSE)を使用してリアルタイムの更新を提供できます。
    クライアントはtasks/sendSubscribeメソッドを使用して、タスクの進行状況やアーティファクトの更新をリアルタイムで受け取ることができます。
    chatgptにみたいに一文字ずつ出したい場合は、Trueです。

  2. pushNotifications
    trueの場合、エージェントはクライアントが提供するWebhook URLに対して、タスクの更新を能動的に送信できます。
    クライアントはtasks/pushNotification/setを使用してWebhook URLを設定できます。

  3. stateTransitionHistory
    trueの場合、エージェントはタスクの状態遷移履歴を提供できます。
    これにより、クライアントはタスクがどのように進行したかの履歴を確認できます。

フィールド名 説明
streaming エージェントがストリーミングレスポンスをサポートしているかどうかを示す。(任意)
pushNotifications エージェントがプッシュ通知メカニズムをサポートしているかどうかを示す。(任意)
stateTransitionHistory エージェントが状態遷移履歴の提供をサポートしているかどうかを示す。 (任意)

Agent Card

Remote Agents are required to publish an Agent Card in JSON format describing the agent's capabilities and skills in addition to authentication mechanisms. In other words, this lets the world know about your agent and how to interact with it. You can find more details in the

Agent SkillsやAgent Capabilities紐付け、エージェントのメタデータや機能を記述するための情報です。いわば、エージェントの名刺です。
例えば、今回のチュートリアルの該当箇所はこちらです。
https://github.com/google/A2A/blob/main/samples/python/agents/google_adk/__main__.py#L36-L45

仕様はここに書かれていました。
https://github.com/google/A2A/blob/main/specification/json/a2a.json#L47-L115

skillsやcapabilitiesやauthなど細かいことは切り出して作っておき、
それを最後まとめるところがこのAgent Cardです。

フィールド名 説明
name エージェントの人間向け名称(例:"Recipe Agent")
description エージェントの説明。ユーザーや他のエージェントが機能を理解するために使用される
url エージェントのホストURL
provider エージェントの提供者情報(組織名とURL)
version エージェントのバージョン(例:"1.0.0")
documentationUrl エージェントのドキュメントへのリンク(オプション)
capabilities エージェントがどういう通信をするか
skills エージェントがどういうスキルがあるか
authentication 使用可能な認証スキーム(例:"Basic", "Bearer")やプライベートカード用のクレデンシャル(オプション)
defaultInputModes エージェントがデフォルトで受け付ける入力形式(例:"text/plain")
defaultOutputModes エージェントがデフォルトで出力する形式(例:"application/json")
skills エージェントが提供するスキルのリスト

Agent Cardのサンプルは以下のとおりです。
JSON-RPC形式になっています。

{
  "name": "Google Maps Agent",
  "description": "Plan routes, remember places, and generate directions",
  "url": "https://maps-agent.google.com",
  "provider": {
    "organization": "Google",
    "url": "https://google.com"
  },
  "version": "1.0.0",
  "authentication": {
    "schemes": "OAuth2"
  },
  "defaultInputModes": ["text/plain"],
  "defaultOutputModes": ["text/plain", "application/html"],
  "capabilities": {
    "streaming": true,
    "pushNotifications": false
  },
  "skills": [
    {
      "id": "route-planner",
      "name": "Route planning",
      "description": "Helps plan routing between two locations",
      "tags": ["maps", "routing", "navigation"],
      "examples": [
        "plan my route from Sunnyvale to Mountain View",
        "what's the commute time from Sunnyvale to San Francisco at 9AM",
        "create turn by turn directions from Sunnyvale to Mountain View"
      ],
      // can return a video of the route
      "outputModes": ["application/html", "video/mp4"]
    },
    {
      "id": "custom-map",
      "name": "My Map",
      "description": "Manage a custom map with your own saved places",
      "tags": ["custom-map", "saved-places"],
      "examples": [
        "show me my favorite restaurants on the map",
        "create a visual of all places I've visited in the past year"
      ],
      "outputModes": ["application/html"]
    }
  ]
}

JSON-RPC形式とは、JSON形式でリクエスト&レスポンスを表現する仕様です。
https://www.jsonrpc.org/specification

A2AはJSON-RPCベースで設計されており、各エージェントのインタフェースや仕様はJSON Schemaで定義されています。OpenAPIに似た感覚で、形式的な記述によりインターオペラビリティが担保されています。

脱線しましたが、まとめるとクラス図はこんな感じです。
AgentCardは中心的なクラスで、エージェントのメタデータと機能を記述します。
AgentSkill: エージェントが提供する特定のスキルを定義します
AgentCapabilities: エージェントがサポートする機能を表します
そのほかにも以下の要素があります
AgentProvider: エージェントの提供者情報を表します
AgentAuthentication: 認証スキームと資格情報を定義します

結言

A2Aと関係ないのですが、
Zennでアンダースコア_付きのgithubリンクを書く際、バックスラッシュ\の追加もお忘れなく!
_があるとリンクと認識されないみたいです

ちゅらデータ株式会社

Discussion