2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Generative UI】3Dアバターとの対話体験を壊さない設計 - ホワイトボードAIエージェントを作った話

2
Posted at

はじめに

今回、3D空間上でアバターと対話しながら、必要に応じてUIを生成するAIエージェントアプリを作りました。(まだ試作ですが...)

Generative UIでは、チャット欄の中にテキスト応答とUIを一緒に表示することが多いと思います。今回は少し変えて、会話はチャット欄、UIはホワイトボードに分けてみました。

そのあたりの構成や、作ってみて感じたことを書いていきます。

作ったアプリデモ

試しにスライドを表示してみてます。
一応、他にもクイズ機能や用途不明な入力フォームも表示・操作できます。

Generative UI について

前提として「Generative UI」という言葉には、主に2つの意味があります。

  • AIがフロントエンドのソースコードそのものを生成する(例:v0とか)
  • 生成AIやAIエージェントが、会話の文脈に応じてUIを動的に生成する

この記事で扱うのは後者です。

Generative UIとは

従来のAIエージェントとのやり取りは、テキストだけで行うことが多いと思います。
ただ、テキストだけだと表現しづらい場面もあります。

  • 長文の文字だらけで読みにくい
  • 他のWebサイトと横断して操作する必要がある
  • テキスト入力が手間

Generative UIは、こうした課題を解決するための考え方です。

AIエージェントが会話の文脈やタスクに応じてUIを生成することで、テキストだけでは扱いづらい情報を、より分かりやすく表現できます。

  • 長文の文字だらけで読みにくい ⇒ カードやグラフでグラフィカルに表現
  • 他のWebサイトと横断して操作する必要がある ⇒ 必要な情報や操作を1つのUIに集約
  • テキスト入力が手間 ⇒ 入力フォームからユーザーが直接入力

image.png

Generative UIをアプリで実現する選択肢

Generative UIを実現する方法には、大きく以下の3つの方式があります。

方式 概要 代表例
事前定義したUIを使用する あらかじめ用意したUIコンポーネントを、AIエージェントのツール呼び出しや状態に応じて表示する CopilotKit(標準機能) / Vercel AI SDK など
宣言的にUIを定義する AIエージェントがJSON形式のUI定義を返し、フロントエンド側で解釈して描画する A2UI / Open JSON UI
アプリを埋め込む MCPサーバーがUIリソースを提供し、ホスト側がiframeとして表示する MCP Apps

次に、今回の用途に対して見たときのメリット・デメリットを考えてみます。

方式 メリット デメリット
事前定義UIを使用する UI品質が安定しやすい
アプリ側でコンポーネントや引数を管理するため、表示されるUIを制御しやすい
柔軟性には限界がある
AIが使えるUIは、基本的に事前に用意したコンポーネントに限られる
宣言的にUIを定義する 柔軟にUIを組み立てられる
AIが複数のコンポーネントを組み合わせて、UI構造を定義できる
出力の制御が難しい
自由度が高い分、UI構造の一貫性や適切さを担保しにくい
アプリを埋め込む 疎結合で再利用しやすい
UIをMCPサーバー側で管理できるため、複数のホストやエージェントから使いやすい
アプリ全体との統一感を出しにくい
UIがiframe内で独立するため、デザインやレイアウトをそろえにくい

なぜ今回はA2UIを使ったのか

今回は最初から、生成されたUIをチャット欄ではなく、ホワイトボード上に表示するというコンセプトで考えていました。

ホワイトボードを想像してみると、決まった情報を表示する場所というより、必要に応じて要素を自由に配置できる領域です。

そのため、会話の内容に応じてUIの構造を柔軟に変えられる仕組みが合いそうだということで、「A2UI」を使ってみました。(元々、使ってみたかったということもありますが....)

2. コンセプト

元々やりたかったこと

元々、作りたかったのは、チャット型ではなく3D空間のアバターと対話するAIエージェントアプリです。

  • チャット欄は入力・履歴の補助として位置づけ、体験の中心はアバターとの対話に置くこと
  • 会話の内容に応じて、カード・一覧・比較表などのUIも生成できること

image.png
by ChatGPT

感じた課題

Generative UIをチャット欄に表示するにあたり、いくつか課題を感じました。

没入感の欠如

  • チャット欄でテキストをやり取りしながらも、3Dアバターがいることで「誰かと話している」感覚が生まれる。
  • しかし、その流れの中に突然グラフやフォームなどのUIが現れると、その感覚が一気に冷めてしまう

操作性

  • チャット欄に表示したUIは会話の流れとともに上へ流れていってしまい、固定して参照し続けることができない

3Dアバターとの対話体験を壊さない設計

考えたのは、「Generative UIの表示場所をチャット欄から分離し、3D空間の世界観に溶け込ませる」というアプローチです。

チャット欄へのUIの割り込みをなくしながら、アバターがいる空間の中でUIを見せることで、対話の流れを保ったまま情報を伝えられます。

現実世界で誰かがホワイトボードを使いながら説明してくれる体験に近いイメージです。

今回は、適当にホワイトボードを使いましたが、用途に応じて、ディスプレイ・パネルなど、別の形に置き換えることもできると思います

3. システム構成

実際に構築したシステムの構成を記載したいと思います。
今回は主にAWSを使用しています。

機能概要

今回のアプリでできることは以下のとおりです。

  • 3Dアバターとテキストでやり取りできる
  • 会話の内容に応じて、スライド・グラフなどのUIをホワイトボードに描画できる
  • AIの返答を音声で読み上げられる
  • ユーザー認証などログイン・ログアウトができる

前提

  • A2UIバージョン:v0.9を使用
  • フロントエンドとAIエージェント間の通信:SSE + AG-UIを使用

AG-UI
AIエージェントとフロントエンド間のリアルタイム通信を標準化するオープンプロトコルです。
エージェントの状態・ツール実行・テキストストリームなどをサーバー送信イベント(SSE)として送受信します。

アーキテクチャ図

これらの機能は、フロントエンド・バックエンド・AIエージェントの3層で実現しています。

aws_architecture_chrome.png

フロントエンド

フロントエンドを構想する主な要素は以下になります。

分類 構成 役割
アプリ React アプリケーション本体を構成する
アプリ Three.js 3D空間を描画する
アプリ @pixiv/three-vrm VRMアバターをThree.js上でレンダリングする
インフラ AWS Amplify Hosting WebアプリをAWS上でホスティングする
インフラ AWS Amplify Auth Amazon Cognitoを構築し、ユーザー認証を担う

3DモデルはVRM*を使用
VRMは、人型アバター向けの3Dモデル形式です。
.vrm というファイル形式で、VTuber、メタバース、3Dアバターアプリなどでよく使われます。
今回はデフォルトのモデルを使ってるので、自分でモデル作りたいですね。

バックエンド

バックエンドを構想する主な要素は以下になります。

分類 構成 役割
インフラ Amazon API Gateway ストリーミング通信のHTTPエンドポイントを提供する
インフラ AWS Lambda CopilotKit Runtimeを動作させる実行環境を提供する
アプリ CopilotKit Runtime フロントエンドとAgentCore上の
Strands Agentsをつなぐブリッジ
インフラ AWS Lambda Web Adapter VOICEVOXをコンテナとしてLambda上で動作させる
アプリ VOICEVOX 音声合成を担う
インフラ Amplify Data AWS AppSync + DynamoDBを構築し、
ユーザー設定などのデータを管理する

音声読み上げはVOICEVOXを使用
VOICEVOXは、テキストを入力すると音声を生成できる、無料の音声合成ソフトウェアです。
ずんだもん、四国めたん、春日部つむぎ などの声が使えます。(ずんだもん最高!)

AIエージェント

AIエージェントを構想する主な要素は以下になります。
※ Amazon Bedrock AgentCoreは長いので、Agent Coreと略してます。

分類 構成 役割
アプリ Strands Agents AIエージェント本体として動作する
アプリ AG-UIアダプター Strands AgentsをCopilotKit経由のAG-UI通信に対応させる
インフラ AgentCore Runtime Strands Agentsをホスティングする
インフラ AgentCore Memory AIエージェントの会話コンテキストを記憶・管理する
インフラ AgentCore Identity Tavily検索APIなど外部サービスのAPIキーを管理する

AIエージェントがA2UIでUIを表示する仕組み

CopilotKit RuntimeがAIエージェントへRender A2UIツールを注入する

CopilotKit Runtimeの設定で a2ui: { injectA2UITool: true } を指定すると、render_a2ui というツールがエージェントに自動的に注入されます。

a2ui-tool-injection.png

現時点で Strands Agents 用の AG-UI アダプター(ag_ui_strands)には、RunAgentInput.context をモデル入力に反映しないという制約があります。render_a2ui ツール自体はエージェントに注入されますが、A2UIのカタログスキーマや使用ガイドラインといったコンテキストはエージェントに伝わりません。ツールの存在は認識できても、どのコンポーネントをどう使うかを把握できない状態です。

この問題についてIssueを提出しています。
https://github.com/ag-ui-protocol/ag-ui/issues/1636

この制約への対策として、Strands Agents の「スキル」機能を利用し、A2UI 用のスキルを定義しました。スキルにカタログの定義や使用ガイドラインを記述することで、エージェントがコンポーネントの使い方を把握できるようにしています。

エージェントがrender_a2uiツールを呼び出す

Strands Agentsは会話の文脈に応じてUIが有効と判断したとき、render_a2ui ツールを呼び出し、UIコンポーネントの組み合わせをJSON形式でフロントエンドへ渡します。

このとき参照できるコンポーネントには2種類あります。

  • デフォルトコンポーネント: A2UIが標準で提供するもの
  • カスタムコンポーネント: 独自カタログに定義するもの。今回はスライド表示やグラフ表示など、ホワイトボード向けのコンポーネントを追加しています

a2ui-tool-call.png

フロントエンドがUIをホワイトボードへ描画する

フロントエンドでは、以下の2つのパッケージを使用しています。

  • @copilotkit/react-core: CopilotKitのコア機能を提供するパッケージ。CopilotKitProvider でアプリ全体をラップし、エージェントとの通信基盤を担います
  • @copilotkit/a2ui-renderer: A2UI専用の独立したパッケージ。カタログの構築とUI定義のレンダリングを担います

CopilotKitProvidera2ui={{ catalog: appCatalog }} を指定することで、カスタムカタログを登録します。

エージェントが render_a2ui を呼び出すと、その結果はAG-UIメッセージとしてフロントエンドに届きます。フロントエンドはこのメッセージを検知してZustandストアに保持し、ホワイトボード側へ渡します。

ホワイトボード側は createA2UIMessageRenderer で作成したレンダラーを持っており、ストアからメッセージを受け取るとカタログを参照してUIを描画します。描画先は @react-three/dreiHtml コンポーネントで、ホワイトボードの表面にUIを埋め込んでいます。

a2ui-whiteboard-flow.png

Zustand
Reactアプリ向けの軽量な状態管理ライブラリです。今回はAG-UIメッセージをホワイトボードへ橋渡しするためのストアとして使用しています。

A2UIActivitiesHost
AG-UIメッセージを監視し、A2UI用のメッセージを検知してZustandストアに格納するコンポーネントです。エージェントからのA2UIレスポンスをホワイトボードへ橋渡しする役割を担います。

createA2UIMessageRenderer
A2UIのカタログとテーマを渡すことでA2UIメッセージをReactコンポーネントとして描画するレンダラーを生成する関数です。

@react-three/dreiHtml
3D空間の任意の座標にDOMを配置できるコンポーネントです。Three.js内に通常のReactコンポーネントをそのまま表示できます。

まとめ

ということで、Generative UIの実現パターンのひとつとして、独自のUI表示領域を持つAIエージェントを作ってみました。とはいえ、まだまだ道半ばです。

Generative UIを「どこに表示するか」という設計は、アプリの体験にかなり影響するポイントだと感じています。本アプリでは、その体験を少しでも良くできそうな感触があり、Generative UIの自由度も一段広がった気がしています。

A2UIがベストかというとケース次第ですが、今後はより多様なUIを試しつつ、検証を深めていきたいです。

3D部分もまだほぼデフォルト状態なので、アプリ全体としてもう少し作り込んでいければと思っています。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?