パーソナライズされた UI を自動生成する EC サイトをGPT-4でSSRして構築してみた

GPT-4にサーバーサイドアプリケーションの役割を与え、ユーザーのリクエストに応じてパーソナライズされたUIを自動生成するデモの紹介です
2024.02.21

こんにちは。リテールアプリ共創部のきんじょーです。

皆さんは EC サイトで買い物をするときに、このサイト使いづらいなぁ・・と感じることはありますか?
ユーザー体験を悪化させる原因はいくつもありますが、UI がユーザーフレンドリーではなかったり、なかなか欲しい商品に辿り着けない時に私は使いづらさを感じます。

では、もしもユーザーの望む形で UI をパーソナライズできるサービスがあったら皆さんは使ってみたいでしょうか?

少し前に、以下のような記事を書きました。

この記事は対話形式のインタフェースにGPT-4を使用して、サーバーサイドで検索結果を絞り込むという検証で、フロントエンドは自前で実装したチャット UI でした。

今回はフロントエンド部分に着目し、チャット UI に囚われることなく、ユーザーのリクエストに応じてフロントエンドの見せ方を自由に変更する体験を検証してみました。

ここの記事で紹介するデモのコードは以下のリポジトリに格納してあります。もし興味を持った方は参照してみてください。

動作イメージ

初期表示

AWS にホスティングしたサービスにアクセスすると、以下の商品一覧が表示されます。

前回同様家具検索をテーマにしていますが、大きく違う点は、HTML、CSS、JavaScript は一切コーディングしておらず、後述する初期プロンプトにより生成したものをそのまま返却しているという点です。

※今回はフロントエンドの UI 生成の検証が目的のため、商品検索処理はモックしてあり、表示する情報は GPT が生成したダミーデータです。

商品情報の詳細化

以下のメッセージを送信します。

これらの商品の詳細が知りたいので、「サイズ」、「色」の情報もカードに追加してください。

各商品情報にリクエストした詳細情報が追加されました。

チャット形式という UI の縛りがあれば、LLMのレスポンスは、次のチャットメッセージとして受信されます。 今回は LLM が HTML をそのまま生成・返却しているので、前回見たページに欲しい情報が追加される自然な形でレスポンスを受信できます。

表形式に切り替え

次は、表形式で表示するため、以下のメッセージを送信します。

もっと沢山の商品を一覧で見たいです。
スプレッドシートのように表形式で見せてくれますか?
商品名をクリックするとクリックした商品の画像をモーダルで表示してください。
表のラベルをクリックするとソート順を切り替えられるようにしてください。

指示通り、商品一覧が表形式になりました。 ソート機能と商品画像のモーダル表示もきちんと実装されています。

一方で、ユーザーがメッセージを入力するインプットが消えてしまいました。 表形式の UI なのでメッセージ入力欄は不要ということで、GPT が気を利かせて消してしまったのでしょうか。

これでは追加のメッセージを送信することができないので、もう一度初めからサービスを開いて仕切り直します。

カルーセル表示に切り替え

こちらは仕切り直した初期表示です。
初回のデザインとは少し変わり、横並びで小さいカードを並べてくれました。

以下のメッセージを送信し、画像を大きく表示したカルーセルに変更してもらいます。

1つ目のモダンなソファに興味があります。
カルーセル表示に切り替えて、モダンなソファの画像をたくさん見せてくれますか?

表示される画像はダミーですが、横スクロールで次の画像が表示できており、指示通りのカルーセル表示となりました。

テーマ変更

最後にテーマを変更してみます。

ダークテーマで見せて

デザインはそのまま、テーマだけがダークに変更されました。

どのように実現しているか

アーキテクチャ

aws-architecture

Lambda が OpenAI API のGPT-4とユーザーの橋渡しをし、ユーザーからのリクエスト/レスポンス履歴の保存に DynamoDB を使用しています。

フロントエンドは LLM がサーバーサイドレンダリングしているため、S3 や CloudFront のリソースはありません。 商品検索処理もモックしているので、Lambda と DynamoDB のみのシンプルな構成となっています。

Lambda で HTTP リクエストを受け付ける際、通常であれば API Gateway を前段に立てます。 しかし、LLM のレスポンスを待っていると API Gateway のリクエストタイムアウト制限(29 秒)に抵触するため、今回はLambda Function Urlsを利用しています。

App Runner よりも構成がシンプルになるので、検証目的であれば Lambda Function Urls と LLM の組み合わせを次回も使いたいと感じました。

処理フロー

初期表示時

flow-chart-1

ユーザーから Lambda が HTTP リクエストを受けると、まずセッション ID を採番します。
次に GPT に家具検索サイトの サーバーサイドアプリケーションとしてのプロンプトを与え、初期画面を生成してもらいます。
生成されたコードを DB に保存し、HTTP レスポンスとしてユーザーに HTML を返却します。

この時払い出したセッション ID もユーザーに返却し、次のリクエストでユーザーを識別できるようにしています。
Lambda の役割をなるべく減らしたかったので、セッション ID はレスポンスの HTML 内に直接埋め込んでいます。

ユーザーからメッセージ送信時

flow-chart-2

ユーザーがメッセージを入力して送信ボタンを押すと、Lambda Functions Url に対して、POST /messagesのリクエストが飛びます。
これはあらかじめ、ボタン押下イベントにリクエスト送信の JavaScript を仕込むように、後述の初期プロンプトで指示を出しています。

それ以降は、LLM に会話履歴を持たせる通常のフローと同様です。 保存する状態が会話履歴ではなくリクエスト・レスポンス履歴になっても、LLM にはサーバーサイドアプリケーションとしての役割を与えているので問題なく動作しました。

プロンプト

初回リクエスト時に、GPT に以下のプロンプトを与えています。
プロンプトの作成は詳細設計書を記述する感覚に近かったです。

## 指示概要

LLM だけで EC サイトを構築する PoC を開始します。
あなたはユーザーとチャットをしつつ、ユーザーの要望にパーソナライズされた画面表示を行い、商品検索を手助けするアシスタントです。
HTML をレンダリングをするサーバーサイドのアプリケーションとして振る舞ってください。

## 機能要件

レンダリングする HTML は、クライアントにそのまま届けられます。
確実に動作するコードを出力してください。

サイトのユーザーは日本人です。サイトの言語は日本語を使用してください。

### 画面構成要素

サイトを構成する要素は以下のとおりです。

1. 商品紹介フィールド
   1. 検索した商品結果を表示します。
2. アシスタントからのメッセージフィールド
   1. LLM から商品について補足や、ユーザーをフォローする必要があれば、このフィールドでメッセージを伝えてください。
3. チャット入力フォーム

   1. このページでは操作はチャットによる LLM との対話で行います。
   2. このフィールドから、商品の検索、ページの見え方についてなどの指示を LLM に行います。
   3. チャット入力用のテキストエリアと、送信ボタンを表示してください。
   4. 送信ボタンを押すと、以下にフォームを submit して LLM にメッセージを送信し、LLM からの返答を画面に表示してください。
      - endpoint: ${endpoint}
      - path: /messages
      - method: POST
      - body:
        - message:
          チャット入力フィールドに入力されたメッセージ
        - sessionId:
          hidden フィールドに格納しているセッション ID
      - content-type: application/x-www-form-urlencoded

   - ※ 4.送信ボタンの機能は重要です。必ず実装してください。

4. セッション ID を格納する hidden フィールド
   - SessionID: ${sessionId}を、hidden フィールドに格納してください。
   - このフィールドはユーザーに見せる必要がないため hidden 属性を付与してください。

上記 4 つのフィールド以外は自由にデザインしてください。
ユーザーは商品検索だけに興味があり、裏側がどう作られているかは知る必要はありません。HTML を LLM でサーバーサイドレンダリングしている旨は伝えないでください。

#### 初期表示

まず初めに、商品一覧フィールドに、家具情報を 5 つ紹介してください。
家具の情報は LLM が適当に考えてください。
使用する画像は unsplash などのフリー素材を利用して、確実に表示できる URL を使用してください。
「アシスタントからのメッセージフィールド」、「チャット入力フィールド」も忘れずにレンダリングしてください。

その後、ユーザーからの要求を満たすように、商品検索や、サイトの見せ方を工夫してください。

## デザイン要件

CSS は Material Design をイメージして適切に当ててください。

## 出力形式

HTML 形式で返却してください。出力結果はそのままユーザーへ HTML のレスポンスとして返却します。
ブラウザが理解できる形で返却してください。
CSS や JS も HTML の中にインラインで記述してください。

HTML 形式以外の出力は受け付けません。

実用化に向けた課題

モデルの応答速度

1 番の課題はモデルの応答速度です。 モデルにはgpt-4-turbo-previewを使用していますが、リクエストから画面に表示されるまで 20~30 秒ほど要します。 gpt-3.5-turboなど、より早いモデルを使用することも検討しましたが、ブラウザ上で問題なく動作するレスポンスを生成する必要があり、回答精度も捨てられません。

そして、レスポンスを HTML にしている制約上、ストリーミングでレスポンスを返すような工夫も難しいです。 これだけはモデルの高速化を待つ以外方法が思い浮かびませんでした。

商品検索処理の実装

対話型ゆるふわ検索 AI アシスタントでも、検索精度の向上は大きな課題でした。

今回の体験を本当に実装するには、ユーザーのリクエストに応じて必要な情報をどこから取得すれば良いのかFunction callingなどを使い、LLM 自身に考えさせる必要があります。

この辺りは弊社でも活発に検証が進んでいるので、動向を追っていきたいと思います。

レスポンスの安定化

何度か検証を進める中で、チャット入力のインタフェースが消えてしまう事象や、メッセージ送信の JavaScript が正しく実装されず送信ができなくなる事象が発生しました。 LLM にリクエストを送信する際は、上記実装の漏れがないことをsystemロールから毎回指示することで改善しましたが、100%の精度ではありません。

リクエスト/レスポンス履歴をHTML形式で保存しているため、通常の会話よりもトークンの消費量が激しいという問題点もあります。

そのため、現時点では実際の EC サイトで求められるトランザクション処理などを、LLM と Lambda だけで実装できる気は全くしません。
全てを LLM でまかなおうとするのではなく、LLM が提供するのは検索 UI までにして商品詳細への遷移は既存の EC サイトに流すなど、ユーザーの体験向上の新しい施策であれば検討の余地があると感じました。

漠然とした指示への対応

検証時の送信メッセージを見るとお気づきかもしれませんが、意図通りの出力を引き出すために「表形式で見たい」「カルーセルで見たい」など、UI の表示形式をかなり明確に指示しています。

ただ商品を検索したいだけのユーザーは上記のような指示を出すことはしません。
使う側に特殊なスキルが求められるようでは、ユーザービリティを下げてしまい本末転倒です。

「写真から探したい」を「カルーセル表示」に読み替えさせたり、チューニングの余地があります。
また、漠然とした指示を LLM 側からの問いかけにより明確にしても良いでしょう。

まとめ

この検証は「アクセシビリティを考慮して、パーソナライズされた UI を自動生成できないかな?」という問いかけ始まりました。
普段 GPT-4 が出力してくれるコードの精度を考えると、意外と簡単にできるのでは?と思いつきで実装してみましたが、思ったよりもしっかり動くものができて驚きました。

チャット形式ではありませんが対話型 UI なので、音声コマンドによる画面操作なども応用できそうです。
課題はいくつもありますが、あったらいいなを実現する夢のある話ではないでしょうか?

最後に、検証のきっかけをいただきあんでぃさんありがとうございました。

この記事が誰かの役に立つと幸いです。
以上。リテールアプリ共創部のきんじょーでした。