はじめに
今回、CopilotKitとAWSが提供するStrandsAgentsを使って、A2UI対応のAIエージェントを作ってみました。
A2UI(Agent-to-UI)は、AIエージェントがJSON形式のメッセージでフロントエンドのUIを制御することでGenerative UIを実現する仕様です。
Generative UIは、AIがユーザーインターフェースを動的に生成するという考え方です。
CopilotKitというフレームワークを使用することで、うした AI エージェントを容易に実装できます。
↓コードはこちら
A2UI とは
A2UI はGenerative UIを実現するための仕様の1つ
Generative UIとは、AIがユーザーインターフェースを動的に生成するアプローチです。テキストだけでなく、ボタン・カード・グラフなどのインタラクティブなUIをAIが状況に応じて生成できます。
そのGenerative UIを実現するための仕様のひとつがGoogleが提供する「A2UI」です。
A2UIはUIをJSONで表現する
では、A2UIはどのようにGenerative UIを実現するのでしょうか。
A2UIは、UIをソースコードではなく「JSON」で定義します。
AIエージェントは、フロントエンドからのプロンプトを受け取り、表示すべきUIをJSONとして返します。フロントエンドはその JSON をもとに画面へ UI を描画します。

JSON では、次の3つの要素を定義します。これらを組み合わせることで UI を構成します。
| 要素 | 説明 |
|---|---|
| Surface (サーフェス) |
UIを描画するキャンバスのような領域 |
| Component (コンポーネント) |
Surfaseに表示するUI要素 ボタン、テキストフィールド、カードなど |
| Data Model (データモデル) |
UIやアプリケーションの状態 テキストの入力状態とか |
A2UIは、Surfaceという白紙の図面を用意し、その中にComponentを配置することでUIを表現します。
そして、Data Modelで表示するデータをComponentに紐付けることでUI全体を構築します。
つまりA2UIは、AIがUIの設計図となるJSONを生成し、フロントエンドがその設計図をもとにUIを描画する仕組みです。
AIエージェントは4種類のJSONメッセージでUIを組み立てる
先ほどは、A2UI が Surface・Component・Data Model という3つの要素で UI を表現するという話を書きました。では、これらの要素はどのようにやり取りされるのでしょうか。
AIエージェントからフロントエンドへ送られるJSONのメッセージには4種類あります。
| 種類 | 説明 |
|---|---|
createSurface |
Surfaceを作成するよう指示する |
updateComponents |
Surface上のComponentsを追加・更新するよう指示する |
updateDataModel |
Data Modelを更新するよう指示する |
deleteSurface |
SurfaceとそのComponents、Data Modelをすべて削除する |
これらのJSONメッセージが送られ、UIが構築されるまでの流れを見てみます。
実際にどのようなJSONメッセージでやりとりされるかは、以下のサンプルを見るとイメージがつくと思います。
A2UIはv0.8とv0.9でメッセージの仕様が異なります。上記はv0.9を前提としています。
UIのパターンはカタログから決める
updateComponentsで指定するUIコンポーネントは、カタログとして管理します。
カタログは「どのコンポーネントが使えるか」「各コンポーネントのプロパティは何か」を定義するものです。
カタログには大きく2種類あります。
| カタログ | 説明 |
|---|---|
| basicCatalog (デフォルトカタログ) |
A2UIが標準で提供するUIのカタログ |
| BYOC (カスタムカタログ) |
独自のコンポーネントを登録できるカスタムカタログ |
basicCatalogに登録されたUIのラインナップは、以下から参照できます。
フロントエンドはA2UI専用レンダラーで表示する
カタログで定義されたコンポーネントは、レンダラーによってフロントエンド上に描画されます。
レンダラーは、A2UIのJSONメッセージを受け取ってフロントエンドでUIを描画するライブラリです。
A2UIはReact・Lit(Web Components)・Angular・Flutterなど複数のプラットフォーム向けのレンダラーを公式に提供しています。
Action機能
A2UIで表示したUIに対して、ユーザー操作を受け付けることができます。
https://a2ui.org/concepts/actions/
これにより、Human In The Loopを実現や、よりインタラクティブなGeneratieve UIを実現できます。(ややこしくなるので、別記事でまとめます)
今回の全体アーキテクチャ
今回のアプリケーションの全体アーキテクチャです。
ここまでA2UIの概要を説明しましたが、ここからはCopilotKit + StrandsAgentsを組み合わせた場合の話をします。
あと実はaws-sampleにCopilotKit + Generatiev UIのサンプルがあるので、こちらを参考にさせてもらってます。
CopilotKitでAG-UIに準拠したエージェントを構築
CopilotKitは、AIエージェントを構築する上でのフレームワークです。
CopilotKitを使用することで、A2UIなどを活用したグラフィカルなUIを持つAIエージェントを、容易に構築できます。
AG-UIは、フロントエンドとAIエージェントを繋ぐイベントベースのプロトコルです。CopilotKitはAG-UIに準拠しています。
これにより、フロントエンドとAIエージェントが共通の言語で対話できるようになるため、お互いを疎結合に保つことができ、AIエージェントの差し替えも容易になります。
AG-UIとStrandsAgentsと組み合わせる
StrandsAgentsは、AWSが提供するAIエージェント実装のためのSDKです。
標準ではAG-UIに対応していないため、専用のアダプタを追加する必要があります。
これでAG-UI対応エージェントを構築できます。
さらにA2UIを組み合わせる
CopilotKit + AG-UI構成でA2UIも組み合わせることができます。
A2UIとAG-UIは、レイヤーが異なります。
AG-UIはイベントをやり取りするための通信経路、A2UIはそのの通信経路で運ばれるメッセージの中身のイメージです。
今回は、AWS上でこれらを構築するため、以下のAWSサービスにデプロイしています。
- フロントエンド:AWS Amplify (Hosting)
- バックエンド:AWS Lambda + Amazon API Gateway (HTTPS)
- AIエージェント:Amazon Bedrock AgentCore
実装内容
次に各種ソースコードの実装を説明します。
今回のAIエージェントは、勉強会などのイベントを検索して、カードのリスト表示などでグラフィカルに提案してくれます。
フロントエンド
スキーマとコンポーネントの作成
今回、コンポーネントとしてStudyEventCard(勉強会カード)やStudyEventList(リスト表示)などを定義しています。
スキーマはZodで定義し、propsとしてコンポーネントが受け取る形にします。
作成したコンポーネントとスキーマからカタログを作成します。
includeBasicCatalog: trueを指定すると、A2UIデフォルトのコンポーネント(basicCatalog)を取り込みます。falseを指定するとbasicCatalogを取り込まず、カスタムコンポーネントのみになります。
createA2UIMessageRendererを使って、カタログを元にレンダラーを定義します。
最後にCopilotKitへ作ったカタログとレンダラーを設定します。
CopilotKit対応のA2UIレンダラー
A2UIは、Reactの公式レンダラーを公開しています。
CopilotKitでは、CopilotKit向けにカスタマイズしたレンダラーを使います。
https://github.com/CopilotKit/CopilotKit/tree/v1.56.5/packages/a2ui-renderer
バックエンド
次にバックエンドの実装です。
CopilotKit RuntimeのA2UIを有効化する
CopilotRuntimeの設定にa2ui: { injectA2UITool: true }を追加することでA2UIを有効化できます。
injectA2UITool: trueを指定すると、@ag-ui/a2ui-middlewareのA2UIMiddlewareがリクエスト処理に自動的に適用されます。
A2UIMiddlewareは、フロントエンドがカタログを登録している場合に限り、render_a2uiツールをAIエージェントへ注入します。このときAIエージェントがツールの使い方を理解できるように、説明書がcontextに注入されます。
しかし、後述するStrandsAgentsのAG-UIアダプタがcontextを無視しているため、説明書を自分で追加する必要があります。
AIエージェント
AIエージェントは、StrandsAgentsとAG-UIアダプタを組み合わせます。

AG-UIアダプタのStrandsAgentでラップする
StrandsAgentでラップし、StrandsAgentsをAG-UIに対応させます。
この辺りは、別記事にまとめています。
A2UIスキルを用意する
前述した通り、ag_ui_strands(AG-UIアダプタ)は、現時点でcontextをAIエージェントへ自動注入できません。
そのため暫定対処として、StrandsAgentsのSkillsを用意します。
このファイルにA2UIの使い方を記述することで、AIエージェントがシステムプロンプトとして読み込み、render_a2uiツールをどう呼べばよいかを理解できるようになります。
スキルをエージェントに読み込ませる
AgentSkillsプラグインを使うと、指定ディレクトリ配下のSKILL.mdをエージェントのシステムプロンプトに自動結合できます。
これでCopilotKitとStrandsAgents構成のAIエージェントでA2UIが使えます。
まとめ
今回は、CopilotKitとStrandsAgentsを使ったA2UIに入門してみました。
A2UI は、AI エージェントが自由にコンポーネントを組み合わせられる柔軟性があります。
ただし、あらかじめ定義されたコンポーネント以上の表現はできないという制約もあります。
このあたりの設計が難しいなーと思ってまして(フロントガチ勢は余裕かもですが...)、1つのコンポーネントを大きく作りすぎると AIの自由度が減り、柔軟性が失われます。
逆に細かく分割しすぎると、AIがコンポーネントを選ぶ組み合わせが毎回バラつき、ユーザー体験の一貫性が損なわれるかなと思います。
このバランスはコンポーネントの粒度設計だけでなく、LLM の賢さや指示の出し方にも依存するので、割と動かしながら調整が必要かな、思ってます。(A2UIムズカシイ)
おまけ:別パターンで3DアバターつきのAIエージェントも構築してみてたりします。







