mcpField
B
building-ai-chat

building-ai-chat

github.com/ancolemanデザイン・UI525144 回インストール46 週間前に更新
リポジトリ

building-ai-chat について

building-ai-chat は、対話型 AI インターフェースを開発する人向けの設計・実装ガイドです。ストリーミング応答、コンテキスト、マルチモーダル入力、エラー処理に加え、ツール利用の表示やアクセシビリティも扱います。

主な機能

  1. 01ストリーミングと Markdown 表示のパターン
  2. 02コンテキストとトークン使用量の管理
  3. 03画像、ファイル、音声入力のパターン
  4. 04AI のエラーと拒否応答への対応
  5. 05ツール利用の表示とユーザーフィードバック
  6. 06アクセシビリティとパフォーマンスの指針

活用シーン

  1. 01チャットボットや AI アシスタントの画面構築
  2. 02ストリーミング Markdown 応答の実装
  3. 03画像、ファイル、音声入力への対応
  4. 04ツール利用と応答へのフィードバックの表示

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/ancoleman/ai-design-components --skill building-ai-chat

インストール後、Claude Code で/building-ai-chatを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

outputs.yaml
assets/
error-messages.json
message-templates.json
system-prompts.json
themes.json
examples/
basic-chat.tsx
code-assistant.tsx
multimodal-chat.tsx
streaming-chat.tsx
tool-calling-chat.tsx
references/
accessibility-chat.md
accessibility.md
context-management.md
error-handling.md
feedback-loops.md
library-guide.md
message-components.md
multi-modal.md
multimodal-input.md
performance-optimization.md
streaming-patterns.md
streaming-ux.md
tool-usage.md
scripts/
calculate_tokens.py
format_messages.js
parse_stream.js

詳細

AI チャットインターフェースコンポーネント

目的

2024〜2025年のAI統合ブームにおいて、AIと人間の対話型インターフェースに関する新たな標準を定義します。Claude とともに構築することで得られたメタ知識を活用し、ストリーミング UX、コンテキスト管理、マルチモーダルなやり取りに関する決定版パターンを確立します。業界で確立されたパターンが不足しているため、このリファレンス実装は、他の実装が参考にする指針となります。

使用する場面

以下の場合に、このスキルを有効にします。

  • ChatGPT スタイルの対話型インターフェースを構築する
  • AI アシスタント、コパイロット、チャットボットを作成する
  • Markdown を使ったテキスト応答のストリーミングを実装する
  • 会話のコンテキストとトークン上限を管理する
  • マルチモーダル入力(テキスト、画像、ファイル、音声)を処理する
  • AI 固有のエラー(ハルシネーション、拒否、上限)に対処する
  • フィードバック機能(評価、再生成、編集)を追加する
  • 会話の分岐やスレッド化を実装する
  • ツール/関数呼び出しを可視化する

クイックスタート

50行未満で作成する、最小限のAIチャットインターフェース:

import { useChat } from 'ai/react';

export function MinimalAIChat() {
  const { messages, input, handleInputChange, handleSubmit, isLoading, stop } = useChat();

  return (
    <div className="chat-container">
      <div className="messages">
        {messages.map(m => (
          <div key={m.id} className={`message ${m.role}`}>
            <div className="content">{m.content}</div>
          </div>
        ))}
        {isLoading && <div className="thinking">AI is thinking...</div>}
      </div>

      <form onSubmit={handleSubmit} className="input-form">
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="Ask anything..."
          disabled={isLoading}
        />
        {isLoading ? (
          <button type="button" onClick={stop}>Stop</button>
        ) : (
          <button type="submit">Send</button>
        )}
      </form>
    </div>
  );
}

ストリーミング Markdown を使った完全な実装については、examples/basic-chat.tsx を参照してください。

コアコンポーネント

メッセージ表示

ストリーミングに対応したユーザー、AI、システムのメッセージバブルを作成します。

// User message
<div className="message user">
  <div className="content">{message.content}</div>
  <time className="timestamp">{formatTime(message.timestamp)}</time>
</div>

// AI message with streaming
<div className="message ai">
  <Streamdown className="content">{message.content}</Streamdown>
  {message.isStreaming && <span className="cursor">▊</span>}
</div>

// System message
<div className="message system">
  <Icon type="info" />
  <span>{message.content}</span>
</div>

Markdown のレンダリング、コードブロック、書式設定の詳細については、references/message-components.md を参照してください。

入力コンポーネント

添付ファイルや音声に対応した、使いやすい入力機能を作成します。

<div className="input-container">
  <button onClick={attachFile} aria-label="Attach file">
    <PaperclipIcon />
  </button>

  <textarea
    value={input}
    onChange={handleChange}
    onKeyDown={handleKeyDown}
    placeholder="Type a message..."
    rows={1}
    style={{ height: textareaHeight }}
  />

  <button onClick={toggleVoice} aria-label="Voice input">
    <MicIcon />
  </button>

  <button type="submit" disabled={!input.trim() || isLoading}>
    <SendIcon />
  </button>
</div>
応答コントロール

AI の応答に欠かせないコントロール:

<div className="response-controls">
  {isStreaming && (
    <button onClick={stop} className="stop-btn">
      Stop generating
    </button>
  )}

  {!isStreaming && (
    <>
      <button onClick={regenerate} aria-label="Regenerate response">
        <RefreshIcon /> Regenerate
      </button>
      <button onClick={continueGeneration} aria-label="Continue">
        Continue
      </button>
      <button onClick={editMessage} aria-label="Edit message">
        <EditIcon /> Edit
      </button>
    </>
  )}
</div>
フィードバック機能

AI の応答を改善するために、ユーザーからフィードバックを収集します。

<div className="feedback-controls">
  <button
    onClick={() => sendFeedback('positive')}
    aria-label="Good response"
    className={feedback === 'positive' ? 'selected' : ''}
  >
    <ThumbsUpIcon />
  </button>

  <button
    onClick={() => sendFeedback('negative')}
    aria-label="Bad response"
    className={feedback === 'negative' ? 'selected' : ''}
  >
    <ThumbsDownIcon />
  </button>

  <button onClick={copyToClipboard} aria-label="Copy">
    <CopyIcon />
  </button>

  <button onClick={share} aria-label="Share">
    <ShareIcon />
  </button>
</div>

ストリーミングとリアルタイム UX

AI の応答を段階的にレンダリングするには、特別な処理が必要です。

// Use Streamdown for AI streaming (handles incomplete markdown)
import { Streamdown } from '@vercel/streamdown';

// Auto-scroll management
useEffect(() => {
  if (shouldAutoScroll()) {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  }
}, [messages]);

// Smart auto-scroll heuristic
function shouldAutoScroll() {
  const threshold = 100; // px from bottom
  const isNearBottom =
    container.scrollHeight - container.scrollTop - container.clientHeight < threshold;
  const userNotReading = !hasUserScrolledUp && !isTextSelected;
  return isNearBottom && userNotReading;
}

ストリーミングの完全なパターン、自動スクロールの動作、生成の停止については、references/streaming-ux.md を参照してください。

コンテキスト管理

トークン上限をユーザーに明確に伝えます。

// User-friendly token display
function TokenIndicator({ used, total }) {
  const percentage = (used / total) * 100;
  const remaining = total - used;

  return (
    <div className="token-indicator">
      <div className="progress-bar">
        <div className="progress-fill" style={{ width: `${percentage}%` }} />
      </div>
      <span className="token-text">
        {percentage > 80
          ? `⚠️ About ${Math.floor(remaining / 250)} messages left`
          : `${Math.floor(remaining / 250)} pages of conversation remaining`}
      </span>
    </div>
  );
}

要約の戦略、会話の分岐、整理方法については、references/context-management.md を参照してください。

マルチモーダル対応

画像、ファイル、音声入力を処理します。

// Image upload with preview
function ImageUpload({ onUpload }) {
  return (
    <div
      className="upload-zone"
      onDrop={handleDrop}
      onDragOver={preventDefault}
    >
      <input
        type="file"
        accept="image/*"
        onChange={handleFileSelect}
        multiple
        hidden
        ref={fileInputRef}
      />
      {previews.map(preview => (
        <img key={preview.id} src={preview.url} alt="Upload preview" />
      ))}
    </div>
  );
}

音声や画面共有を含む、マルチモーダル対応の完全なパターンについては、references/multi-modal.md を参照してください。

エラー処理

AI 固有のエラーを適切に処理します。

// Refusal handling
if (response.type === 'refusal') {
  return (
    <div className="error refusal">
      <Icon type="info" />
      <p>I cannot help with that request.</p>
      <details>
        <summary>Why?</summary>
        <p>{response.reason}</p>
      </details>
      <p>Try asking: {response.suggestion}</p>
    </div>
  );
}

// Rate limit communication
if (error.code === 'RATE_LIMIT') {
  return (
    <div className="error rate-limit">
      <p>Please wait {error.retryAfter} seconds</p>
      <CountdownTimer seconds={error.retryAfter} onComplete={retry} />
    </div>
  );
}

エラーパターンの詳細については、references/error-handling.md を参照してください。

ツール使用状況の可視化

AI がツールや関数を使用していることを表示します。

function ToolUsage({ tool }) {
  return (
    <div className="tool-usage">
      <div className="tool-header">
        <Icon type={tool.type} />
        <span>{tool.name}</span>
        {tool.status === 'running' && <Spinner />}
      </div>
      {tool.status === 'complete' && (
        <details>
          <summary>View details</summary>
          <pre>{JSON.stringify(tool.result, null, 2)}</pre>
        </details>
      )}
    </div>
  );
}

関数呼び出し、コード実行、ウェブ検索のパターンについては、references/tool-usage.md を参照してください。

実装ガイド

推奨スタック

主要ライブラリ(2025年11月に検証済み):

# Core AI chat functionality
npm install ai @ai-sdk/react @ai-sdk/openai

# Streaming markdown rendering
npm install @vercel/streamdown

# Syntax highlighting
npm install react-syntax-highlighter

# Security for LLM outputs
npm install dompurify
パフォーマンスの最適化

スムーズなストリーミングには不可欠です。

// Memoize message rendering
const MemoizedMessage = memo(Message, (prev, next) =>
  prev.content === next.content && prev.isStreaming === next.isStreaming
);

// Debounce streaming updates
const debouncedUpdate = useMemo(
  () => debounce(updateMessage, 50),
  []
);

// Virtual scrolling for long conversations
import { VariableSizeList } from 'react-window';

パフォーマンスパターンの詳細については、references/streaming-ux.md を参照してください。

セキュリティに関する考慮事項

AI の出力は必ずサニタイズしてください。

import DOMPurify from 'dompurify';

function SafeAIContent({ content }) {
  const sanitized = DOMPurify.sanitize(content, {
    ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'code', 'pre', 'blockquote', 'ul', 'ol', 'li'],
    ALLOWED_ATTR: ['class']
  });

  return <Streamdown>{sanitized}</Streamdown>;
}
アクセシビリティ

誰もがAIチャットを使えるようにします。

// ARIA live regions for screen readers
<div role="log" aria-live="polite" aria-relevant="additions">
  {messages.map(msg => (
    <article key={msg.id} role="article" aria-label={`${msg.role} message`}>
      {msg.content}
    </article>
  ))}
</div>

// Loading announcements
<div role="status" aria-live="polite" className="sr-only">
  {isLoading ? 'AI is responding' : ''}
</div>

アクセシビリティ対応の完全なパターンについては、references/accessibility.md を参照してください。

同梱リソース

スクリプト(トークンを消費しない実行)
  • scripts/parse_stream.js を実行して、ストリーミング中の未完成な Markdown を解析します
  • scripts/calculate_tokens.py を実行して、トークン使用量とコンテキスト上限を推定します
  • scripts/format_messages.js を実行して、エクスポート用にメッセージ履歴を整形します
リファレンス(段階的な情報開示)
  • references/streaming-patterns.md - ストリーミング UX の完全なパターン
  • references/context-management.md - トークン上限と会話の戦略
  • references/multimodal-input.md - 画像、ファイル、音声の処理
  • references/feedback-loops.md - ユーザーフィードバックと RLHF のパターン
  • references/error-handling.md - AI 固有のエラーシナリオ
  • references/tool-usage.md - 関数呼び出しとツール使用状況の可視化
  • references/accessibility-chat.md - スクリーンリーダーとキーボードのサポート
  • references/library-guide.md - ライブラリの詳細なドキュメント
  • references/performance-optimization.md - ストリーミングのパフォーマンスパターン
例
  • examples/basic-chat.tsx - ChatGPT 風の最小限のインターフェース
  • examples/streaming-chat.tsx - メモ化を活用した高度なストリーミング
  • examples/multimodal-chat.tsx - 画像とファイルのアップロード
  • examples/code-assistant.tsx - IDE 風のコードコパイロット
  • examples/tool-calling-chat.tsx - 関数呼び出しの可視化
アセット
  • assets/system-prompts.json - さまざまなユースケース向けに厳選したプロンプト
  • assets/message-templates.json - すぐに使えるメッセージコンポーネント
  • assets/error-messages.json - ユーザーにわかりやすいエラーメッセージ
  • assets/themes.json - ライト、ダーク、高コントラストのテーマ

デザイントークンとの統合

すべてのビジュアルスタイルにデザイントークンシステムを使用しています。

/* Message bubbles use design tokens */
.message.user {
  background: var(--message-user-bg, var(--color-primary));
  color: var(--message-user-text, var(--color-white));
  padding: var(--message-padding, var(--spacing-md));
  border-radius: var(--message-border-radius, var(--radius-lg));
}

.message.ai {
  background: var(--message-ai-bg, var(--color-gray-100));
  color: var(--message-ai-text, var(--color-text-primary));
}

テーマ設定システムの詳細については、skills/design-tokens/ をご覧ください。

主な革新

このスキルでは、業界初の次のソリューションを提供します。

  • メモ化ストリーミングレンダリング - パフォーマンスを10~50倍向上
  • インテリジェントな自動スクロール - ユーザーのアクティビティに応じたスクロール
  • トークンの比喩表現 - ユーザーにわかりやすいコンテキストの説明
  • 未完成のMarkdownへの対応 - 部分的なレンダリングを適切に処理
  • RLHFパターン - 効果的なフィードバック収集
  • 会話の分岐 - 非線形の会話ツリー
  • マルチモーダル統合 - ファイル、画像、音声をシームレスに処理
  • アクセシビリティ優先 - スクリーンリーダーを標準でサポート

戦略的重要性

これが最も重要なスキルである理由は次のとおりです。

  1. 絶好のタイミング - AIを導入するアプリが急増する時期(2024~2025年)
  2. 標準が存在しない - パターンを定義するチャンス
  3. メタ的な優位性 - Claude と共に構築することで、UXを深く理解
  4. 固有の課題 - ストリーミング、コンテキスト、ハルシネーションはいずれも新しい課題
  5. リファレンス実装 - 他の人が従う標準になる可能性

このスキルを習得して、AIインターフェースの革新をリードしましょう。

コメント