---
title: "Generative UIを爆速で実装できる「OpenUI」が面白そう"
description: "Generative UIを一から実装するとコンポーネントの管理やストリーミングの制御がめちゃくちゃ面倒なのだが、それを綺麗に共通化・隠蔽してくれるフレームワーク「OpenUI」"
lang: "ja"
canonical: "https://llm-lab.dev/posts/generative-ui-fast-development-openui/"
source: "https://llm-lab.dev/posts/generative-ui-fast-development-openui.md"
publishedAt: "2026-04-21"
updatedAt: "2026-04-21"
category: "Generative UI"
tags:
  - "generative-ui"
  - "openui"
---

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

> [!NOTE]
> この記事で確認したこと: Generative UIは、LLMに任意のUIコードを書かせるより、構造化された「どのコンポーネントをどんなpropsで出すか」という意図として扱う方が整理しやすくなります。バックエンド側ではTool CallingやStructured OutputsでJSONを制約し、フロントエンド側ではレジストリに登録済みのReactコンポーネントへマッピングする構成が、型安全性とストリーミング表示を両立させる基本形になります。

最近話題の **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（コンポーネント）と、その識別子をあらかじめマッピングしておく。

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

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

```

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

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

```tsx
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のスキーマとどうやって一番スマートに同期させるか。
* ストリームが途中でエラー落ちした際のフォールバック処理の挙動。
