6月26日、AWSが「Retrofit, don't rebuild: Agentic overlays for transforming legacy enterprise services」と題した記事を公開した。この記事では、既存のREST APIベースのサービスを書き直さずにAgent-to-Agent(A2A)通信に対応させる「Agentic Overlay」パターンの実装方法について詳しく紹介されている。
レガシーREST APIをA2Aエージェントに変える「Agentic Overlay」とは
本記事の核心は一点だ。既存のREST APIサービスをゼロから書き直すことなく、薄いラッパー層(Agentic Overlay)を被せるだけでA2A対応エージェントに変換できるという提案である。
A2A(Agent-to-Agent)プロトコルは、自律エージェント同士がメタデータ(エージェントカード)で互いを発見し、JSON-RPC経由で構造化メッセージを交換しながら複数ステップのタスクを協調実行するための仕様だ。A2Aが標準化される以前、多くの企業はエージェントをREST APIとして実装してきた。その結果、既存のエージェント資産がA2A非対応のまま残るという新たな移行問題が生じている。
なぜ「別スタックを並行運用」はまずいのか
記事はまず、A2A対応を追加する際の既存アプローチの問題点を整理している。
アプローチ1: REST/A2Aを別スタックで並行運用
/api/v2/...と/a2a/...の2系統のエンドポイント- 認証・バリデーション・エラーハンドリングも二重実装
- ビルド・テスト・デプロイパイプラインが2本
- ログ・メトリクス・トレースの監視コストが倍増
- 同じ操作でREST/A2Aが異なる結果を返すリスク
アプローチ2: ビジネスロジックを共有化してリファクタリング
既存RESTエンドポイントのコードを再構成し、共有サービス層を抽出してA2Aからも呼び出す設計。外部のRESTパスは変わらなくても、リファクタリング自体がリグレッションや動作のズレを生み、テスト負荷が大きい。
これらに対し、Agentic Overlayはアプリケーション内に新しいルートを追加するだけで済む。デプロイパイプラインは1本のまま、同一ホスト・同一ポートで /api/v2/... と /a2a/... の両方を提供する。下位のRESTサービスは一切変更しない。
実装の核心:FlaskアプリをA2A対応に変える5ステップ
記事は電卓(Calculator)サービスをFlaskで実装した既存REST APIをA2A化するPoC(概念実証)コードを示している。
リクエスト形式の対比
A2Aへの移行で最初に意識すべきは入出力形式の変化だ。
| REST | A2A | |
|---|---|---|
| 入力 | {"operation": "add", "operands": [5, 3]} |
JSON-RPC 2.0でラップされたSendMessage |
| 出力 | {"result": 8} |
messageId・contextId付きのJSON-RPC応答 |
ステップ1: エージェントカードの構築
A2A仕様ではエージェントが/.well-known/agent-card.jsonを提供する必要がある。build_agent_card()関数が動的にこれを生成し、スキル定義はskills.jsonから読み込んでキャッシュする。
def build_agent_card(api_url: Optional[str] = None) -> Dict[str, Any]:
return {
"name": "Calculator Agent",
"supportedInterfaces": [
{"url": api_url, "protocolBinding": "JSONRPC", "protocolVersion": "0.3"},
],
"capabilities": {
"streaming": False,
"pushNotifications": False,
},
"skills": _load_skills(),
}
ステップ2: 内部RESTエンドポイントの呼び出し
Overlayの中心となるのがinvoke_rest_endpoint()だ。A2Aで受け取ったメッセージを既存RESTエンドポイントへHTTPリクエストとして転送し、レスポンスをA2A形式に変換して返す。Authorizationヘッダーの透過的なフォワードも実装されている。
def invoke_rest_endpoint(endpoint, json_data=None, http_method="POST"):
base_url = request.host_url.rstrip("/")
url = f"{base_url}{endpoint}"
headers = {"Content-Type": "application/json"}
auth_header = request.headers.get("Authorization")
if auth_header:
headers["Authorization"] = auth_header
response = http_requests.post(url, json=json_data, headers=headers, timeout=30)
return response.json(), response.status_code
ステップ3〜5: メッセージ変換
変換レイヤーの実装は3つの処理に分かれる。まずextract_message_payload()がA2A Spec 0.3形式のJSON-RPCリクエストを受け取り、params.message.parts配列からテキストコンテンツを取り出して既存RESTエンドポイントが期待するペイロード構造へと整形する。次に整形済みペイロードをステップ2のinvoke_rest_endpoint()へ渡してRESTレスポンスを得る。最後にbuild_a2a_message()がそのRESTレスポンスを受け取り、messageId・contextId・roleといったA2A必須フィールドを付与したJSON-RPC 2.0準拠のレスポンスオブジェクトを組み立てる。この3段階により、既存RESTロジックを一切変更せずにA2Aのメッセージングセマンティクスへ適合させることができる。
アーキテクチャ上の利点
- エージェントスプロール(agent sprawl:エージェントの無秩序な増殖)の抑制: 既存サービスをそのままエージェントとして再利用するため、インフラ上にエージェントが乱立しない
- MCP(Model Context Protocol)との併用: RESTエンドポイントをMCPサーバーのツールとしても公開でき、A2AとMCPの両方のエコシステムに対応可能
- スーパーバイザーエージェントとの親和性: インテント分類やルーティングなど限定的な機能スコープを持つスーパーバイザーエージェントに特に適している
整理すると
Agentic Overlayの本質は「インターフェースの追加であって、APIの置き換えではない」という点だ。A2Aは新しいAPIではなく、既存APIへの新しい窓口として機能する。エンタープライズ環境でA2A移行を検討する際、まず既存REST資産を温存しながら段階的に対応できる現実的な選択肢として参照に値する。
詳細はRetrofit, don't rebuild: Agentic overlays for transforming legacy enterprise servicesを参照していただきたい。




