はじめに
Google Developers Blogで2026年10月29日、生成UI(Generative UI)アプリの構築方法が紹介されました。Googleのオープン標準「A2UI」と、エージェント統合基盤「CopilotKit」を組み合わせる方法です。この記事では、仕組みと導入手順、試す際の注意点を解説します。
参考記事
- タイトル: Build Generative UI Apps with A2UI & CopilotKit Agents
- 発行元: Google Developers Blog
- 発行日: 2026年10月29日
- URL: https://developers.googleblog.com/build-generative-ui-apps-with-a2ui-copilotkit-agents/
要点
- A2UIは、エージェントがUIをデータとして記述し、アプリ側の既存コンポーネントで描画するGoogleのオープン標準である
- CopilotKitはAG-UIを基盤とし、Google ADKやLangChainなどのエージェントとA2UI対応のフロントエンドを接続する
- 導入は、エージェントのAG-UIエンドポイント化と、クライアント側でのコンポーネントカタログ定義の2つで構成される
- A2UIの画面は双方向で、ユーザーの入力値が同じストリームでエージェントに戻り、複数ステップの手続きを1つの画面で扱える
- スターターアプリは `npx copilotkit@latest create –name my-app –framework a2ui` で作成できる
詳細解説
生成UIとA2UI:UIを「データ」として記述する
これまでのエージェントは、旅行の計画まではできても、結果を長い文章で返すだけでした。選べるパッケージ一覧や日付ピッカーを、会話内に描く標準的な方法がなかったためです。
生成UIは、リクエストに合わせてエージェントが実行時に画面を組み立てる層です。ユーザーは文章を読んで入力し直す代わりに、ボタンやフォームを操作できます。予約や申し込みなど、入力項目が多い業務ほど効果が出やすいとみられます。
A2UI(Agent-to-UI)は、Googleが策定した生成UI向けのオープン標準です。UIフレームワークにも通信方式にも依存しません。エージェントは画面をデータとして記述し、アプリは手持ちのコンポーネントで描画します。主な特徴は次の3点です。
- セキュリティ優先:実行可能なコードではなく宣言的なデータ形式。カタログ外の部品は画面に届く前に弾かれる
- ストリーミング対応:小さなJSONメッセージをIDで参照し合うフラットな形式。届いた順に描画できる
- 移植しやすい:同じ応答をReact、Lit、Angular、SwiftUI、Jetpack Compose(Android)、Flutterで描画できる
最も広く使われているのは宣言的モードです。エージェントは、事前に宣言された部品と関数を組み合わせてUIを作ります。HTMLを丸ごと生成させる方式より、スクリプト混入などのリスクを抑えやすい設計です。
部品の一覧は「カタログ」と呼ばれます。A2UIには、レイアウト、表示、入力、コンテナの4分野で18個の基本部品を持つBasic Catalogがあります。Basic Catalogは意図的に最小限のため、本番アプリの多くは独自のカスタムカタログを定義します。社内のデザインシステムを登録すれば、生成画面の見た目も揃えやすくなります。
まず試す:スターターアプリ
A2UIとCopilotKitを組み合わせたアプリ一式は、次のコマンドで作成できます。npx(Node.jsのパッケージを取得して実行するツール)で、エージェント統合済みのスターターを生成します。
npx copilotkit@latest create --name my-app --framework a2ui
- `–name my-app`:作成するアプリの名前
- `–framework a2ui`:A2UI向けの構成を選ぶ指定
CopilotKit Dojoでは、実行できるデモが公開されています。固定スキーマ、カスタムカタログでの動的スキーマ、エラー回復の3種類です。ほかにA2UI ComposerやCopilotKit A2UI Docsも案内されています。
CopilotKitとAG-UIの役割分担
CopilotKitは、利用者向けエージェントアプリの統合スタックです。LangChain、AWS Strands、Google ADKなどとつながります。チャット画面、ランタイム、A2UIレンダラーをReactとAngular向けに提供します。
土台はAG-UI(Agent-User Interaction Protocol)です。データは次のように流れます。
- エージェントがA2UIの操作(オペレーション)を出力する
- AG-UIがそれを型付きイベントとしてクライアントへ届ける
- ユーザーの操作値が、同じストリームでエージェントへ戻る
A2UIは「何を描くか」、AG-UIは「どう運ぶか」を担います。Google ADK、LangChain、Mastra、StrandsはいずれもAG-UI互換で、セットアップは共通です。
AG-UIで統合すると、次の機能を自前で作らずに済みます。
- カタログはセットアップ時にエージェントへ届き、サーバー側の設定が最小限で済む
- 専用のサブエージェントが生成するため、メインのコンテキストを圧迫しない
- 不正な生成は検出され、エラー内容を差し戻して自己修復する
- 再試行の上限に達すると短いメッセージに置き換わり、会話は続く
セットアップ1:ADKエージェントをエンドポイントとして公開する
Google ADKでは、`ag_ui_adk` パッケージでエージェントを包み、FastAPI上のAG-UIエンドポイントとして公開します。次は航空券検索エージェントの例です。
from fastapi import FastAPI
from google.adk.agents import LlmAgent
from ag_ui_adk import ADKAgent, add_adk_fastapi_endpoint
root_agent = LlmAgent(
name="flight_agent",
model="gemini-3.8-flash",
instruction="Help users find and book flights. Call generate_a2ui to show results.",
)
adk_agent = ADKAgent(
adk_agent=root_agent,
app_name="flights",
user_id="demo_user",
use_in_memory_services=True,
)
app = FastAPI()
add_adk_fastapi_endpoint(app, adk_agent, path="/")
- `LlmAgent`:エージェント本体。結果の表示に `generate_a2ui` を呼ぶよう指示している
- `ADKAgent`:AG-UI向けのラッパー
- `add_adk_fastapi_endpoint`:`path=”/”` にエンドポイントを追加する
`generate_a2ui` はコード内にありません。A2UIの設定をクライアントからリクエストと一緒に送る、動的設定を使うためです。
`user_id` や `use_in_memory_services` はデモ向けの値とみられます。実運用では、ユーザーとの対応づけやセッションの保存先を別途設計します。モデル名も利用環境に合わせて変えてください。
アプリ側では、このエンドポイントをCopilotKitランタイムの `/api/copilotkit` に登録します。手順はGoogle ADKクイックスタートにあります。
セットアップ2:クライアント側でカタログを登録する
クライアント側では、部品を定義し、レンダラーを対応づけ、カタログをプロバイダーに渡します。次は `FlightCard` を登録する例です。
import { CopilotKit, CopilotChat } from '@copilotkit/react-core/v2';
import {
createCatalog,
type CatalogDefinitions,
type CatalogRenderers,
} from '@copilotkit/a2ui-renderer';
import { z } from 'zod';
const catalogDefinitions = {
FlightCard: {
description: 'A flight result with airline, times, and stops.',
props: z.object({
airline: z.string(),
departs: z.string(),
arrives: z.string(),
stops: z.number(),
}),
},
} satisfies CatalogDefinitions;
const catalogRenderers = {
FlightCard: MyFlightCard, // your React component
} satisfies CatalogRenderers<typeof catalogDefinitions>;
const catalog = createCatalog(catalogDefinitions, catalogRenderers, {
catalogId: 'flight-catalog',
includeBasicCatalog: true,
});
<CopilotKit runtimeUrl="/api/copilotkit" a2ui={{ catalog }}>
<CopilotChat />
</CopilotKit>
- `description`:エージェントのプロンプトに入り、モデルが部品を選ぶ手がかりになる
- `props`:Zodのスキーマで、エージェントが返した値を検証する
- `catalogRenderers`:定義名と実際のReactコンポーネントを対応づける
- `includeBasicCatalog: true`:Basic Catalogの部品もあわせて使える
`description` には、用途や使う場面を具体的に書くのが良さそうです。CopilotKitを使わず、`@ag-ui/client` と @a2ui/react などで組む構成も可能です。
双方向の画面で複数ステップの手続きを組む
A2UIの画面(サーフェス)は双方向で、部品は状態の変化に反応します。日付の選択や搭乗者情報の入力は、同じストリームでエージェントに戻ります。エージェントはその値で画面を出し直します。
往復は、データパスにバインドした入力欄と、送り返すパスを指定したボタンで成り立ちます。次は2つの部品定義を並べた抜粋です。
{ "id": "cabin", "component": "ChoicePicker", "variant": "mutuallyExclusive",
"options": [ { "label": "Economy", "value": "eco" },
{ "label": "Business", "value": "biz" } ],
"value": { "path": "/booking/cabin" } },
{ "id": "confirm", "component": "Button", "child": "confirm_label",
"action": { "event": { "name": "confirmBooking",
"context": { "cabin": { "path": "/booking/cabin" },
"email": { "path": "/booking/email" } } } } }
- `cabin`:客室クラスを排他選択させ、値を `/booking/cabin` に入れる
- `confirm`:押すと `/booking/cabin` と `/booking/email` の値をまとめて送る
検証はクライアント側で行われ、メールアドレスの誤りはモデルを呼ばずに表示されます。ボタンが押されると、エージェントは同じ `surfaceId` に画面を出し直します。航空便の検索から予約確定までを、1つの画面で扱えます。
導入時の注意点
- 最初はスターターとBasic Catalogで動きをつかみ、その後に自社部品をカスタムカタログへ移す
- 部品に渡す値はモデルが生成する。価格や予約内容など重要な値はサーバー側でも検証する
- クライアント側の検証は入力の補助にすぎない。確定処理ではサーバーで改めて確認する
- 自己修復や再試行は、裏でモデル呼び出しが増える。本番前にレイテンシーと料金への影響を測る
- サンプルの引数名や関数名は、利用するバージョンのドキュメントと照合する
まとめ
A2UIは、エージェントにUIをデータで記述させ、描画は手元のコンポーネントに任せる標準です。CopilotKitと組み合わせると、エンドポイント公開とカタログ登録の2つで双方向の画面を組めます。まずBasic Catalogで試作し、業務に合う部品を順に増やす進め方が現実的と言えます。
