ANTIGRAVITY LABEN
記事一覧/Agents & Manager
Agents & Manager/2026-04-24中級

Antigravity A2A プロトコル実装ガイド — エージェント同士が対話する現実的なパターン

Antigravity の A2A(Agent-to-Agent)プロトコルを実装ベースで解説します。2 つのエージェントの間でタスクを委譲・結果を受け取る最小構成から、複数エージェントの長期対話パターンまで、実際に動くサンプル付きで紹介します。

Antigravity338A2A4マルチエージェント41プロトコル2エージェント設計13

マルチエージェント設計の議論で必ず出てくるのが「エージェント同士はどうやって会話するのか」という問いです。Antigravity には A2A(Agent-to-Agent)プロトコルという仕組みが用意されていて、これを使うと、あるエージェントが別のエージェントに作業を依頼し、結果を受け取る流れを型として書けます。

ただ、公式ドキュメントだけを読むと「どういうときに使うのか」がつかみにくいので、ここでは実務で有効なパターンを 3 つ、動くサンプルを添えて紹介します。

A2A プロトコルの 1 分サマリー

A2A プロトコルは、エージェントを 1 つの HTTP サービスとして扱い、別のエージェントがそのサービスに対して構造化されたリクエストを送ることで会話を成立させます。中心概念は 3 つです。

  • Agent Card: エージェントが自己申告する「何ができるか」のスキーマ。公開 URL・対応タスク・認証方式を含みます
  • Task: 依頼を送る側が作成するオブジェクト。入力メッセージとメタデータを持ちます
  • Message Stream: タスクの進行中に発生するメッセージ列。途中経過・確認の問い返し・最終結果が流れます

図にすると、「依頼する側(クライアント・エージェント)」「引き受ける側(リモート・エージェント)」「両者をつなぐタスク」の三角関係です。

最小実装 — 2 エージェントのタスク委譲

まず最小構成で動かしてみます。エージェント A が「要約してほしい記事テキスト」をエージェント B に渡し、B が要約を返す、という単純なケースです。

# agent_b_server.py ― 要約を担当するエージェント
from antigravity.a2a import AgentServer, AgentCard, TaskHandler
 
card = AgentCard(
    name="summarizer",
    description="Summarize long-form text in 3 bullet points.",
    supported_tasks=["text/summarize"],
    endpoint="http://localhost:8081",
)
 
handler = TaskHandler(card=card)
 
@handler.on_task("text/summarize")
async def summarize(task):
    text = task.input["text"]
    result = await task.call_llm(
        prompt=f"Summarize this text in 3 bullet points:\n\n{text}",
    )
    return {"summary": result}
 
if __name__ == "__main__":
    AgentServer(handler).run(port=8081)
# agent_a_client.py ― 依頼する側
from antigravity.a2a import AgentClient
 
async def main():
    client = AgentClient(remote="http://localhost:8081")
    result = await client.submit_task(
        kind="text/summarize",
        input={"text": open("article.md").read()},
    )
    print(result["summary"])

ポイントは 2 つあります。1 つは Agent Card で「何ができるか」を宣言的に記述している点。もう 1 つは、タスクの種類(kind)を文字列 ID で揃えている点です。この 2 つが決まっていれば、エージェント A は B の実装を知らなくても委譲できます。

パターン 1: 単方向委譲(Fire-and-Forget 型)

上のサンプルのように、A から B にタスクを投げ、B が結果を返す一方向の流れです。最も単純で、最も多用する形です。

適しているケースとしては、次のような条件が揃うときです。

  • タスクの入出力が明確に定義されている(要約、翻訳、分類、データ整形)
  • 中間で人間の確認が不要
  • 結果が得られたら A 側の処理は完結する

この形は REST API 呼び出しと本質的に同じですので、「A2A を使う意義はあるのか」と感じられるかもしれません。答えは、エージェントを差し替え可能なコンポーネントとして扱える点にあります。同じ text/summarize タスクを受け付ける別実装(性能の違う LLM・別言語特化・無料版)に切り替えるときに、クライアント側のコードを変えずに済みます。

パターン 2: 双方向対話(途中で確認を取る型)

タスクの途中でエージェント B が A に確認したくなるケースもあります。たとえば B が資料生成中に「タイトルはこれで良いですか?」と聞き返したい、といった状況です。A2A は Message Stream で双方向のメッセージをやり取りできるため、これを型として書けます。

@handler.on_task("doc/generate")
async def generate_doc(task):
    draft_title = await task.call_llm(prompt="Propose a title for this report: ...")
    
    # A にタイトル候補を確認する
    response = await task.ask(
        message=f"Is this title OK? '{draft_title}'. Reply 'yes' or a new title.",
    )
    
    final_title = draft_title if response.strip().lower() == "yes" else response.strip()
    # ... 以下、本文生成 ...
    return {"title": final_title, "body": body}

このパターンは、完全自動化したいけれども重要な分岐点では人間的判断を挟みたい、というニーズに合います。A 側の実装によっては、確認要求が来たときに別エージェント(権限を持つ上位エージェント)にさらに委譲することも可能です。

パターン 3: 並列分散(Scatter-Gather 型)

A が同時に複数の B1・B2・B3 にタスクを投げ、結果を集約するパターンです。大量の類似タスクを高速化したいときに効きます。

import asyncio
 
async def process_articles(article_list):
    clients = [AgentClient(remote=url) for url in worker_endpoints]
    tasks = [
        clients[i % len(clients)].submit_task(
            kind="text/summarize",
            input={"text": text},
        )
        for i, text in enumerate(article_list)
    ]
    results = await asyncio.gather(*tasks)
    return [r["summary"] for r in results]

シンプルなキュー+ワーカーと思えるかもしれませんが、A2A 経由で実装しておく利点は、ワーカーごとに異なる能力(日本語特化・英語特化・コード特化)を持たせられる点です。tasks を構築する段階で「日本語記事は日本語特化ワーカーに」「コード記事はコード特化ワーカーに」と振り分けるロジックを挟むと、単純な並列処理以上の価値が出てきます。

実装で気をつけたい 3 つの落とし穴

認証とアクセス制御: A2A エンドポイントをそのままインターネットに公開すると、任意のクライアントからタスクを受け取ってしまいます。Agent Card に auth 要件を書き、Bearer トークンまたは mTLS で絞ることをおすすめします。社内ネットワーク内でも、VPN 越しのアクセスを想定するなら最低限のトークン認証は必須です。

タイムアウトと再送: リモートエージェントが応答しないとき、クライアント側で無限に待たないようタイムアウトを設定してください。加えて、同じタスクを 2 回送っても副作用が重複しないように、タスクに idempotency_key を付与する設計が安全です。

エラー情報の粒度: リモートエージェント内で発生した例外をそのまま A に返すと、内部実装が漏れます。TaskError(code="llm_timeout", message="...", retry_after=30) のような形でコード化し、受け取った側が意味のあるフォールバックを取れるようにするとよいです。

どこから試すと良いか

本記事のサンプルは、Antigravity の Python SDK をインストールして 2 つのターミナルで動かすだけで体験できます。まずは単方向委譲(パターン 1)を動かしてみて、感覚がつかめたら双方向対話に進むのが無理のない順番です。

複雑なマルチエージェント構成を設計する段階に入ったら、Antigravity マルチエージェント・オーケストレーション入門 も合わせて読んでみてください。A2A をどこで使い、どこで避けるかの判断基準が得られるはずです。

シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Agents & Manager2026-07-12
A2A のタスクが working のまま静かに滞留していたとき — 状態遷移を計測して詰まりを名指しする運用メモ
Antigravity の A2A 連携は、エラーで落ちるより「タスクが working のまま進まない」形で静かに詰まります。状態遷移を一本の時系列として記録し、滞留したタスクをどのエージェントのどの辺で止まったかまで名指しする監視の実装を、運用の実感とあわせて整理します。
Agents & Manager2026-04-27
AgentKit 2.0 でマルチエージェント開発を始める — Antigravity 環境での設計と実装
AgentKit 2.0 はマルチエージェント開発の入り口を一気に下げました。私が Antigravity 上で 3 種類のエージェント連携パターンを実装して見えた、設計判断・落とし穴・本番運用の勘所を体系化します。
Agents & Manager2026-04-23
Antigravity AgentKit 2.0 で作る本番マルチエージェント — 実戦で使える設計パターンと落とし穴
AgentKit 2.0 の Planning / Fast モードの使い分けから、Orchestrator-Worker 構成・状態管理・コスト制御・プロンプトインジェクション対策まで、実運用で詰まるポイントを設計パターン単位で整理しました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →