つれづれなる Agent OPS
Generative UI

Generative UIを爆速で実装できる「OpenUI」が面白そう

Generative UIを一から実装するとコンポーネントの管理やストリーミングの制御がめちゃくちゃ面倒なのだが、それを綺麗に共通化・隠蔽してくれるフレームワーク「OpenUI」

最近話題の Generative UI(生成AIが動的にUIを生成してユーザーに提示する技術)。 一から実装するとコンポーネントの管理やストリーミングの制御がめちゃくちゃ面倒なのだが、それを綺麗に共通化・隠蔽してくれるフレームワーク「OpenUI」というものを見つけたので、気になったポイントをメモ。

そもそも「OpenUI」とは?

Generative UIの実装に特化した軽量なフレームワーク。 AI(LLM)から返ってきた構造化データ(JSONなど)をキャッチして、フロントエンド側で動的にReact(Next.js)などのコンポーネントへマッピングする処理をいい感じに共通化してくれる。

ざっくりメリット

  • ボイラープレートの削減: ストリーミング処理やローディング状態の管理、コンポーネントの動的レンダリングに必要な定型コードがほぼ不要になる。
  • 特定のLLMに依存しない: OpenAI、Anthropic(Claude)、Geminiなど、主要なプロバイダやVercel AI SDK等と組み合わせて柔軟に使える(インターフェースが抽象化されている)。
  • UIの型安全性の担保: 生成されるUIのスキーマ(引数やプロパティ)を定義しやすく、TypeScriptとの相性も良さそう。

どうやって動くのか?(処理の流れ)

大まかな流れは以下の3ステップ。

  1. バックエンド(AI側): 「ユーザーの要求(例:『進捗グラフを見せて』)」に対して、LLMに関数呼び出し(Tool Calling / Structured Outputs)を行わせ、画面描画に必要なパラメータ(JSON)を生成・ストリーミングする。
  2. OpenUI(仲介役): ストリーミングされてくる途中のデータ(未完成のJSON)や完成したデータをリアルタイムに解析し、UIコンポーネントの状態(Props)に落とし込む。
  3. フロントエンド(描画側): OpenUIから渡されたコンポーネント名とPropsを元に、あらかじめ用意しておいたReactコンポーネント(例:<ProgressBar/><Card/>)を動的にマッピングしてレンダリングする。

基本的な実装のイメージ

※手元で試す用のざっくりとしたコードメモ。

1. UIコンポーネントのレジストリ登録

生成したいUI(コンポーネント)と、その識別子をあらかじめマッピングしておく。

// 描画したい自作のコンポーネント群
import { WeatherCard } from '@/components/WeatherCard';
import { StockChart } from '@/components/StockChart';

// OpenUI側に「この名前が来たらこのコンポーネントを出す」と登録
export const uiRegistry = {
  weather: WeatherCard,
  stock: StockChart,
};

2. フロントエンドでのレンダリング

OpenUIが提供するコンポーネントやHooksを使うことで、ストリーミング中の「ローディング状態」や「徐々にUIが組み立てられていく様子」を最小限のコードで表現できる。

import { useGenerativeUI } from 'openui-framework-package'; // ※実際のパッケージ名に合わせる
import { uiRegistry } from './registry';

export default function ChatView() {
  // AIからのストリームや出力をOpenUIのHookに流し込む
  const { uiElements, submitMessage } = useGenerativeUI({
    api: '/api/chat',
    registry: uiRegistry,
  });

  return (
    <div className="flex flex-col gap-4 p-4">
      {uiElements.map((element, index) => {
        // OpenUIがストリームを解析し、自動で適切なコンポーネントを割り当ててくれる
        return <element.Component key={index} {...element.props} />;
      })}
    </div>
  );
}

個人的な注目ポイントと使い所

💡 どんな時に使えそう?

  • AIエージェント系アプリ: ユーザーの指示に応じて、チャットUIの中に「フォーム」や「タスク一覧」「グラフ」を動的に差し込みたい時。

  • UXの向上: 完全にLLMの出力が終わるのを待つのではなく、ストリーミング中に「今まさにUIが生成されている感(骨組みから徐々にデータが埋まる挙動)」をユーザーに見せたい時。

次に触るときに深掘りしたい点

  • コンポーネントのPropsの型定義(Zodなど)を、LLMのStructured Outputsのスキーマとどうやって一番スマートに同期させるか。
  • ストリームが途中でエラー落ちした際のフォールバック処理の挙動。
DUO

Author

DUOps

LLMOps、Agent、MCP、Langfuse、Cloudflare 周辺の実装と運用を、個人で試しながら記録しています。

Xを見る