zudo-doc
GitHub リポジトリ

検索したい単語を入力

いつでも検索バーを開ける

AI Assistant

作成 2026年5月10日更新 2026年7月24日Takeshi Takatsudo
タグ:#ai

ドキュメントに関する質問に答える、組み込みのチャットアシスタント。

概要

AIアシスタントは、ドキュメントサイトにチャットダイアログを追加します。ユーザーはヘッダーのスパークルアイコンをクリックしてダイアログを開き、ドキュメントの内容について質問できます。

アシスタントはllms.txtインテグレーションで生成されたドキュメント全文をコンテキストとして利用するため、サイト上のあらゆるページに関する質問に答えられます。

アシスタントの有効化

zfb.config.tsaiAssistanttrueに設定します:

zfb.config.ts
export default defineConfig(
  zudoDoc({
    aiAssistant: true,
    // ...
  }),
);

有効にすると:

  • ヘッダーバーにスパークルアイコンが表示されます

  • POST /api/ai-chatエンドポイントがCloudflare WorkersのSSRルートとして利用可能になります

ライブバックエンドはhost側の責務です

以下で説明するproduction handler、worker-entry.tsAiChatDailySpendCap classはこの showcase repositoryが所有しており、@takazudo/zudo-docからexportされたりfresh scaffoldへ 追加されたりしません。package-owned SSR routeは安全なseamで、demo modeでは固定応答を返し、 host handlerなしでlive modeを選ぶとHTTP 501を返します。downstream projectはdemo modeを維持するか、 host側の/api/ai-chat handler、source Worker entry、Durable Object class、migrationを実装する必要が あります。bindingを追加するだけではlive AIは有効になりません。

デモモード無効化時のセキュリティ警告

デモモードを無効にする前にセキュリティを強化してください

aiChatDemoMode: false を設定すると、実際のAnthropicのAPIキーを使うエンドポイントが公開されます。 設定を誤ると、認証なしのAPIコールによるコスト悪用のリスクがあります。本番稼働前に以下を確認してください:

  1. CORSオリジンを制限するaiChatAllowedOrigins にデプロイ済みのドキュメントサイトのURL を設定します。デフォルトの空配列はすべてのクロスオリジンブラウザリクエストをブロックします。

  2. 有料呼び出しの正確な上限を設定するaiChatGlobalDailyLimit で、全IPを合算した UTC日ごとのAnthropic fetch試行数を制限します。SQLite Durable Objectが同時判定を直列化するため、 設定値を超過しません。

  3. Cloudflare経由でデプロイする — IPごとのレート制限に使用される cf-connecting-ip は、 Cloudflareのネットワークを経由したリクエストにのみ信頼できます。

aiChatDemoModefalse の場合は両方のガードがフェイルクローズです。IPごとのKV読み取り 障害はHTTP 429を返し、正確な上限のバインディング欠落やRPC障害はAnthropic呼び出し前に HTTP 500を返します。

zfb.config.ts
export default defineConfig(
  zudoDoc({
    aiChatDemoMode: false,
    // Allow only your deployed docs site to make cross-origin requests.
    aiChatAllowedOrigins: ["https://your-docs-site.example.com"],
    // Exact UTC-day paid-call admission cap (false = no exact cap).
    aiChatGlobalDailyLimit: 500,
    // ...
  }),
);

環境設定

このshowcase repositoryでは、チャットエンドポイントはCloudflare WorkersのSSRルート (pages/api/ai-chat.tsx)として動作し、wrangler.tomlのCloudflare環境bindingから設定を 読み込みます。downstream実装はこのgraphを参照できますが、これらhost-owned fileはpackage APIではありません。

必要なCFバインディング

シークレットwrangler secret put ANTHROPIC_API_KEYで設定します:

ANTHROPIC_API_KEY=sk-ant-...

変数wrangler.tomlで設定します:

wrangler.toml
[vars]
DOCS_SITE_URL = "https://your-docs-site.workers.dev"
RATE_LIMIT_PER_MINUTE = "10"
RATE_LIMIT_PER_DAY = "100"

KV名前空間 — ソフトなIPごとのレート制限とprivacy-safeな結果監査record用(prompt、response、 IP、IP hashフィールドは保存しません):

wrangler kv namespace create RATE_LIMIT

返却されたidwrangler.toml[[kv_namespaces]]ブロックに貼り付けます。

Durable Object名前空間 — UTC日ごとの正確な有料呼び出し許可判定:

wrangler.toml
[[durable_objects.bindings]]
name = "AI_CHAT_DAILY_SPEND_CAP"
class_name = "AiChatDailySpendCap"

[[migrations]]
tag = "v1-ai-chat-daily-spend-cap"
new_sqlite_classes = ["AiChatDailySpendCap"]

これらの名前は正確に維持してください。最初のwrangler deployがWorker migrationを適用します。 これはwrangler d1 migrationsではありません。本番のカスタムworker-entry.tsは、生成された dist/_worker.jsのアダプターハンドラー、dist/_zfb_inner.mjsサイドカー、Durable Objectクラスを すべて維持します。Wranglerの前には必ずビルドしてください。

UTC日ごとに新しいオブジェクトへルーティングするため、上限は00:00 UTCにリセットされます。 許可判定はリクエスト検証、よりソフトで結果整合なIPごとのKVガード、ドキュメントコンテキスト 準備の後、ちょうど1回のAnthropic fetch直前に行われます。fetch失敗時も許可枠は返却されず、 プロバイダーが確定した請求数ではありません。aiChatGlobalDailyLimit: falseは正確な上限だけを 無効化し、aiChatDemoMode: trueはKV、Durable Object、Anthropicをすべて迂回します。

Durable Objectsを実装するversionにはプレビューURLが生成されないため、プレビューエイリアスは アダプター専用のサービス/設定を使います。検証対象はSSRアダプターとassets経路で、有料呼び出し 許可判定ではありません。migrationの適用は本番のwrangler deployが担います。Cloudflareの Durable Object migrationsCloudflare WisdomのDurable Objects記事Workers Logsのstructured-objectガイドも参照してください。

応答の高速性とコストを抑えるため、claude-haiku-4-5-20251001を使用しています。

チャットダイアログ

ダイアログはネイティブの<dialog>要素を使ったpackage-ownedのPreactアイランド(@takazudo/zudo-doc/ai-chat-modal)です。このshowcaseではpages/lib/_body-end-islands.tsxBodyEndIslandsのchrome-bindings slot)経由でマウントしています。

レイアウト

  • 狭いビューポートlg/1024px未満):ビューポートの幅と高さいっぱいに表示

  • 広いビューポート(1024px以上):中央配置、90vw/90vhでmax-widthは52.5rem、ボーダー付き

機能

  • 吹き出し風のメッセージバブル(ユーザーは右、アシスタントは左)

  • アシスタント応答内のマークダウンレンダリング(太字、イタリック、コード、リスト、リンク)

  • API呼び出し中の「Thinking...」インジケーター

  • エラーメッセージのインライン表示

  • 背景クリックまたはEscapeキーで閉じる

  • ダイアログを閉じると会話はリセットされる

APIリファレンス

エンドポイントの詳細仕様(リクエスト/レスポンスの型、エラーコード、環境変数)はAI Assistant APIリファレンスを参照してください。

ファイル構成

pages/
└── api/
    ├── ai-chat.tsx               # CF Workers SSR endpoint (prerender = false)
    ├── _ai-chat-admission.ts     # Exact UTC-day paid-call admission cap
    ├── _ai-chat-audit.ts         # Privacy-safe outcome audit logging
    ├── _ai-chat-client.ts        # Claude API client (raw fetch)
    ├── _ai-chat-cors.ts          # CORS origin allowlist
    ├── _ai-chat-observability.ts # Structured operational logging
    ├── _ai-chat-payload.ts       # Request/response payload builders
    ├── _ai-chat-rate-limit.ts    # Per-IP KV rate limiting
    ├── _ai-chat-screening.ts     # Prompt-injection screening
    └── _ai-chat-types.ts         # Shared route types
src/
└── types/
    └── ai-chat.ts                # ChatMessage, AiChatRequest/Response types
worker-entry.ts                   # Production Worker entry (wraps dist/_worker.js)

チャットダイアログのアイランド(@takazudo/zudo-doc/ai-chat-modal)と、チャットメッセージ用の マークダウンレンダラー(@takazudo/zudo-doc/render-markdown)はpackage-ownedであり、 このリポジトリのファイルツリーには含まれません。

Revision History

Takeshi Takatsudo作成: 2026-05-10T21:56:58+09:00更新: 2026-07-25T02:44:39+09:00

AI Assistant

Ask a question about the documentation.

Preview theme

Loading theme previews…