ai for designersMay 1, 202610 min read

ストリーミングUIの設計

ストリーミング出力領域は新しいキャンバスだ。AIストリーミングUIを本物のインタラクションモデルとして設計するための実践プレイブック。5つのレイヤー、実プロダクトの分解、アンチパターン、出荷前監査を収録。

By Boone
XLinkedIn
designing streaming uis

ストリーミングレスポンスは、現代のソフトウェアで最も設計されていないサーフェスだ。多くのチームは TypeScript の fetch フックを書き、div につなぎ、それをプロダクトデザインと呼んで出荷した。結果はインターフェースのふりをしたタイプライターである。

ストリーミングとは、テキストが現れることではない。リズム、間、スクロール挙動、割り込み操作、そして信頼シグナルを備えたインタラクションモデルだ。入力だけを設計したチームは、プロダクトの半分しか出荷していない。出力領域こそがもう半分であり、多くのAIプロダクトがユーザーを失っているのはそこだ。

この記事は実践版だ。ストリーミングUIとは実際に何か、優れたものが必ず備える5つのレイヤー、実プロダクトの分解、本番でサーフェスを殺しているアンチパターン、そして出荷前監査を扱う。

ストリーミングUIはサーフェスであり、fetchループではない

ストリーミングUIとは、モデルが動いている間にユーザーが読み返す領域全体のことだ。見えているテキストはその一部にすぎない。リズム、カーソル、スクロール挙動、構造的コミットメント、割り込みコントロール、ストリーム後の状態が残りを構成する。

このサーフェスには計測可能な特性がある。Time-to-first-token。トークンのケイデンス。構造的コミットメント。割り込みレイテンシ。完了シグナル。ストリーム後のアフォーダンス。どれかを無視すれば、そのストリームは設計されたコンポーネントではなく、APIの副作用だ。

Cursor、Claude、v0、Lovable、Linear AI、Raycast AI。どれもストリーミングを生のトークン出力として扱っていない。それぞれが構造化されたサーフェスを出荷している。それが基準だ。

優れたストリーミングサーフェスの5つのレイヤー

ユーザーが体験する順に5つのレイヤーがある。4つ未満しか備えないストリーミングUIは未完成だ。

time-to-first-token、トークンのリズム、構造的コミットメント、割り込みと編集、完了とラベル付けされた5層のタワーを描いたボクセル図
time-to-first-token、トークンのリズム、構造的コミットメント、割り込みと編集、完了とラベル付けされた5層のタワーを描いたボクセル図

Time-to-first-token は、虚無がフィードバックに変わる瞬間だ。トークンのリズムは、動き出したストリームの手触りである。構造的コミットメントは、リスト、テーブル、コードをリフローなしで扱う方法だ。割り込みと編集はユーザーの脱出口。完了はストリームが終わり、成果物がインタラクティブになる瞬間だ。どれか一つでも飛ばせば、ストリームはそのレイヤーから腐り始める。

レイヤー1:Time-to-first-token

最初の200ミリ秒で、ユーザーがそのサーフェスを信頼するかどうかが決まる。本物のフィードバックシグナル付きで200ms未満なら即時に感じる。フィードバックなしで800msを超えれば、ユーザーはすでにプロダクトが壊れていると判断し始めている。

選択肢は具体的だ。出力領域をあらかじめ確保するスケルトンプレースホルダー。点滅するカーソル。タイピングドットのアフォーダンス。「こちらが」のような決まり文句を、本文より300ms早く出すストリーミングプレフィックス。

ChatGPTの3つのドットが機能するのは正直だからだ。Claudeのグラデーションパルスはそのアップグレードで、偽のコンテンツを約束せずに、サーフェスが生きていることを知らせる柔らかなアニメーションの帯だ。Cursorは細いカーソルラインと、いま何が起きているかを名指しするステータスチップを描画する。どのケースでも、ユーザーは200ms以内に何かを見ている。

失敗とは虚無だ。600msも固まる空白の領域は、AIとは待ち続けるものだとユーザーに教え込む。モデルを出荷する前に、カーソルを出荷しろ。

レイヤー2:トークンのリズム

生のトークンストリームはガタつく。4トークン、次に20、次に1と出すモデルは、下層の配信が問題なくても、バグったターミナルに見える。リズムは設計上の判断だ。

解決策は、平滑化されたケイデンスだ。入ってくるトークンを30〜60ミリ秒バッファし、一定のレートで描画する。ユーザーは毎分250〜400語で読むので、目標は、スパイクせず読書速度ちょうどかそれをわずかに上回って届くストリームだ。Claudeはこの規律を早くから出荷した。

v0にあるVercelのストリーミングUIプリミティブも同じ発想で、ネットワークと視覚更新を切り離す描画ループを備える。APIからのトークンストリームは1つのレイヤーだ。視覚的なストリームは別のレイヤーである。この2つを決して同一にしてはならない。

カーソルは重要だ。最後に描画されたトークンに追従し、柔らかい尾を引いてフェードするカーソルが、視線をつなぎ止める。それがなければ、ユーザーの目はストリームの現在地を探して飛び回る。Cursorのコンポーザーにあるカーソルは、名前が偶然同じなわけではない。

レイヤー3:構造的コミットメント

最も難しいレイヤーだ。平坦な文章は簡単。レスポンスの途中でリスト、テーブル、コードブロック、チャートにコミットするストリームこそ、多くのサーフェスが壊れる場所である。

段落が完全に描画され、リストが半分描画され、コードブロックがレイアウトを確保済みのストリーミング出力パネルのボクセル表現
段落が完全に描画され、リストが半分描画され、コードブロックがレイアウトを確保済みのストリーミング出力パネルのボクセル表現

素朴な実装は、markdownをそのままストリーミングすることだ。レンダラーはチャンクごとにパースし、コミットのたびにレイアウトがリフローし、リストは番号を振り直し、コードブロックはストリーム途中でフォントが入れ替わり、ページが跳ねる。リフローのたびに、注意力に税がかかる。

正しい実装は、構造が検出できた瞬間にそれをコミットし、その後はリフローなしで、コミット済みのレイアウトにコンテンツを流し込む。リストは最初のハイフンが届いた瞬間に領域を確保する。コードブロックはバッククォート3つで等幅ペインを確保する。テーブルは列数を即座に確定する。Cursorのdiffストリーミングが教科書的な例だ。diffペインはレイアウトを確保し、ファイルパスが最初に届き、個々の行はあらかじめ確保された行に流れ込む。v0の選択範囲を認識するストリーミングも、キャンバス側で同じパターンを出荷している。

Linear AIの構造化された提案は、ユーザーに「読み込み中」状態を一度も見せずにコミットメントを実現する。提案は型付きオブジェクトとして届き、フィールドは依存関係の順に埋まり、ワークフローは決してブロックされない。Linearは仕事を出荷し、他は議事録を出荷している。

レイヤー4:割り込みと編集

割り込みのないストリーミングUIは敵対的だ。ユーザーは、モデルがすでに間違いだとわかっていることを書いていくのを眺めていて、逃げる唯一の方法はタブを閉じることだけ。プロダクトではない。トークンカウンター付きの人質事件だ。

停止ボタンは、サーフェス上で最も安く、最もレバレッジの高い要素だ。100トークン目ではなく、1トークン目から見えていること。Claude、Cursor、ChatGPT、v0はすべて備えている。自前のチャットUIの多くは忘れている。

割り込みは床であり、編集は天井だ。多くのチームがまだ獲得していないパターンが、ライブ編集である。ユーザーがストリーム中にプロンプトを修正し、サーフェスが経路を切り替える。Cursorのストリーミング中のacceptとrejectが、出荷済みで最も近いものだ。ユーザーはdiffが届くそばから読み、使える部分を受け入れ、そうでない部分を却下する。これが本物のインタラクションループだ。

ChatGPTのregenerateは対照的だ。ボタンは前のレスポンスを上書きし、ユーザーは気に入っていたバージョンを失う。上書きとしてのregenerateは破壊的だ。ブランチとしてのregenerateがデザインである。Claudeの履歴サーフェスはブランチを出荷している。

レイヤー5:完了とストリーム後

ストリームが終わる瞬間は、デザインの瞬間だ。ほとんどのプロダクトはそれを無として扱う。ストリームが止まり、カーソルが消え、ユーザーは次に何をすればいいのかわからないまま、テキストの壁を見つめる。

Claudeのartifactの具現化はゴールドスタンダードだ。ストリーミングテキストは静かな完了シグナルを受け取り、artifactペインはストリーミングプレビューからインタラクティブなサーフェスへ、同じ拍で入れ替わる。ユーザーは「読み終えた」のではなく、いまや「artifactの中にいる」。この遷移こそが核心だ。

v0のプレビュー入れ替えは、デザイン側のバージョンだ。ストリーミングされるコードが終わると、ライブプレビューのiframeが最終ビルドでリロードされ、デプロイボタンが現れる。3つの状態、1つの遷移、無音の時間なし。

Cursorのdiffからacceptへの流れが3つ目のパターンだ。ストリームが終わっても、diffは編集可能なままで、acceptとrejectも残り、ユーザーが言うまでファイルはコミットされない。ストリームは終わったが、判断は終わっていない。その分離が、サーフェスをチャットログではなくツールに感じさせる。

悪いバージョンは、ストリームを終えて何も出荷しない。カーソルが消え、文章がそこに居座り、ユーザーは実際に使うためにテキストを別のツールにコピーする。モデルが付いたコピペのパイプラインだ。

実プロダクトの分解

Cursor はコンポーザーのストリーミングとdiffの具現化を組み合わせている。コンポーザーが計画をストリームし、diffペインがパッチをストリームし、acceptとrejectは有効なまま、ストリーム後の状態はユーザーが所有する保留中のdiffだ。全レイヤーが決まっている。

Claude は平滑化されたトークンのリズムと、artifactペインの入れ替えを出荷している。最初のトークンの前にグラデーションパルス、安定したケイデンス、完了時のartifactの具現化、ブランチする会話履歴。すべての遷移が設計されているから、サーフェスが設計されたものに感じられる。

v0 はライブプレビュー付きの、選択駆動のストリーミングを出荷している。ユーザーがキャンバスの領域をクリックすると、プロンプトが自らスコープを絞り、ストリームはコードとして届き、プレビューはiframeで入れ替わる。完了はデプロイボタンに引き継がれる。

ChatGPT はベースラインだ。3つのドットのフィードバック付きトークンストリーミング、上書きとしてのregenerate、最近追加されたbranch-from-here。カテゴリのデフォルトであって、基準ではない。

Vercel AI Playground、Lovable、Anthropic Computer Use、Raycast AI、GitHub Copilot Workspace は、それぞれ一部を出荷している。Vercelはストリーム中にモデルピッカーをライブで公開する。Lovableはストリームからアプリへのパターンを実行し、ユーザーは自分のアプリがリアルタイムで組み上がるのを見る。Computer Useはスクリーンショットと推論トレースを並行してストリームする。Raycastはコマンドパレットのマイクロサーフェスへストリームする。Copilot Workspaceはチェックポイント付きの、計画してから実行するストリーミングを出荷している。

5つのルール

  1. 200ミリ秒以内にフィードバックを出す。 カーソル、パルス、タイピングドット、ストリーミングプレフィックス。虚無以外なら何でもいい。
  2. ケイデンスを平滑化する。 ネットワークストリームをバッファし、読書速度で描画し、カーソルを固定する。ガタつきはネットワークの状態ではなく、デザインの失敗だ。
  3. リフローなしで構造をコミットする。 リスト、テーブル、コードブロックが検出できた瞬間にレイアウトを確保する。決してリフローしない。
  4. 100トークン目までに停止ボタンを出荷する。 見える。届く。ワンクリック。例外なし。
  5. ストリームの後の瞬間を、ストリームと同じ丁寧さで設計する。 完了は引き継ぎだ。引き継ぎこそがプロダクトである。

本番でストリームを殺しているアンチパターン

死んだスピナー。 モデルが閉じた描画レイヤーの裏でストリームしている間、スピナーが回り続ける。スピナーを消せ。ストリームを出荷しろ。

トークンのジッター。 生のトークン出力、バッファなし、ケイデンスはバーストと停止の間でちらつく。平滑化しろ。

ユーザーと戦うオートスクロール。 ユーザーが前の段落を読んでいるのに、ページがストリームを追ってオートスクロールする。手動スクロールを検出し、ユーザーが再び固定するまでオートスクロールを止める。ClaudeとCursorはこれを処理している。

停止ボタンなしの過ち。 割り込みが設定メニューの奥に埋もれている、30秒後にしか現れない、あるいは存在しない。1トークン目から見えるようにしろ。

終わってユーザーを呆然とさせるストリーム。 完了シグナルなし、次のステップなし。ストリーム後を設計しろ。

破壊的なregenerate。 新しいレスポンスが古いものを上書きし、ユーザーは気に入っていたバージョンを失う。regenerateはブランチとして、決して上書きにしない。

生のmarkdownをそのままストリーミング。 レンダラーがチャンクごとにリフローし、ページが跳ねる。構造を一度コミットし、確保したレイアウトにストリームする。

修正は小さい。それを出荷したサーフェスは2026年らしく感じる。そうでないものは、2026年のモデルにつながれた2022年のチャットサイドバーに感じる。

ストリーミングサーフェス監査

出荷前に、あらゆるAIストリーミングサーフェスでこれを実行しろ。

ストリーミングサーフェス監査を表す、コーラル色のチェックボックスが並ぶ縦型の監査カードスタックのボクセル表現
ストリーミングサーフェス監査を表す、コーラル色のチェックボックスが並ぶ縦型の監査カードスタックのボクセル表現
  1. 最初のフィードバック。 送信から200ミリ秒以内に、サーフェスは何かを表示するか?
  2. ケイデンス。 トークンストリームは読書速度に平滑化されているか、それとも生のネットワークジッターか?
  3. 構造的コミットメント。 コンテンツが届く前に、リスト、テーブル、コードブロックのレイアウトを確保しているか?
  4. 停止のアフォーダンス。 停止ボタンは最初のトークンから見え、ワンクリックで押せるか?
  5. 編集のアフォーダンス。 ユーザーはストリーム中に修正、承認、却下できるか?
  6. 完了のデザイン。 ストリームが終わる瞬間は、本物の次のステップへ引き継がれるか?
  7. ストリーム後の成果物。 出力はストリーム後もインタラクティブか、それとも固まった議事録にすぎないか?

7つすべてを通過するサーフェスは、設計されたコンポーネントに感じられる。3つ以上失敗するサーフェスは、モデルが付いたコンソールログに感じられる。この差が、AIネイティブなプロダクトデザインと後付けのAIを分ける。

ここまで丁寧にストリーミングサーフェスを出荷するチームは、入力側でプロンプトサーフェスを本物のコンポーネントとして扱い、システムレベルでAIレイテンシを設計しているチームと同じだ。空の状態、エージェントUIパターン、信頼シグナルと組み合わせて、ストリーミング出力が読まれるに値するものにしろ。

FAQ

ストリーミングUIデザインとは何か?

ストリーミングUIデザインとは、モデルが生成するそばから、AIの出力が画面にどう現れるかを形づくる専門領域だ。time-to-first-token、トークンのケイデンス、構造的コミットメント、割り込みのアフォーダンス、ストリーム後の成果物を扱う。ストリーミングUIは、テキストで埋まっていくテキストエリアではない。計測可能な特性を持つ、設計されたサーフェスであり、いま勝っているプロダクトはそう扱っている。

なぜトークンストリーミングはプロダクトごとに感じ方が違うのか?

ケイデンスはネットワークの結果ではなく、デザイン上の判断だからだ。生のトークンストリームはガタつく。バッファされ平滑化されたストリームは、読書速度で届く。Claudeは、ネットワークと視覚更新を切り離す描画ループでケイデンスを平滑化している。ChatGPTは生の配信に近い。同じクラスのモデルでも、サーフェスの感触は違う。

ストリーミングUIで最もよくある間違いは何か?

見える停止ボタンのないストリームを出荷することだ。ユーザーはモデルが間違いだとわかっていることを書くのを眺めていて、逃げ道がない。ほかのよくある失敗は、死んだスピナー、ユーザーと戦うオートスクロール、破壊的なregenerate、チャンクごとにリフローする生のmarkdown、そして何にも引き継がれない完了だ。どれも小さなサーフェスの変更で直せる。

ストリームをキャンバスのように作れ

ストリーミング出力領域は新しいキャンバスだ。AIプロダクトは、最初の800ミリ秒でこのサーフェスがどう感じられるか、そして30秒のレスポンスを通してどれだけ読みやすさを保てるかで、生きるか死ぬかが決まる。多くのチームはそれをタイプライターのように扱う。基準を出荷しているチームは、それをインフラのように扱う。

5つのレイヤーを出荷しろ。監査を実行しろ。アンチパターンを避けろ。その先に出てくるプロダクトは、ツールのふりをしたチャットサイドバーではなく、本物のツールに感じられる。

ストリーミングサーフェスを、後付けのトークンループではなく完全なコンポーネントとして出荷するチームが欲しいなら、Brainyに依頼してほしい。私たちは、最初のトークンからストリーム後の成果物まで、最初のユーザーが送信を押すより前に、信頼シグナルと割り込みのアフォーダンスを組み込んだ形で、AIネイティブなプロダクトUIをエンドツーエンドで設計する。

Want a streaming surface that feels designed instead of bolted on? Brainy ships AI-native product UI end to end, from the first token to the post-stream artifact.

Get Started

More from Brainy Papers

Keep reading