チャットフック
Docsbookのチャットフックは、AIチャットが各回答の前後に呼び出す、皆様が用意したHTTPSエンドポイントです。コンプライアンスチームが策定したルールの適用、皆様のシステムだけが把握している事実のモデルへの提供、すべての質問と回答の独自ストアへのミラーリングなどを、チャットをフォークせずに実行できます。
得られるもの#
それぞれ固有のURLを持ち、個別に設定できる3つのフック:
| フック | 実行されるタイミング | 回答を変更できるか | 用途 |
|---|---|---|---|
| Pre-hook | モデルが呼び出される前(ブロッキング) | はい — リクエストをブロックする、またはプロンプトにコンテキストを注入する | 質問を拒否する、読者のプラン、地域、または機能フラグを追加する |
| Post-hook | 回答の完了後 | いいえ | 質問と回答の組み合わせを独自のストアに記録する |
| Streaming hook | ポストフックと同時 | いいえ | ライブダッシュボードまたはアラート通知チャネルにデータを送る |
変更を加えられるのは、Docsbookが完了を待つ唯一のフックであるため、プレフックだけです。他の2つは読者がすでに回答を受け取った後にディスパッチされ、レスポンスが読み取られることはありません。そのため、表示された内容を伏せ字にしたり、書き換えたり、形式を変更したりすることはできません。
フックはすべてのプランで利用でき、呼び出しても残高は一切消費されません。URLは https:// でなければならず、http:// URLは保存時に拒否されます。
質問はどのようにブロックまたは拡張されますか?#
pre-hook URLを設定します。Docsbookは読者の質問をJSONとしてそのURLにPOSTし、応答を待機してから、返信に含まれる2つの任意フィールドに基づいて処理します。
Docsbookが送信する内容:
{
"question": "What's the price for team@acme.com?",
"session_id": "sess_YOUR_SESSION_ID",
"workspace_id": 42
}Docsbookが受け付ける応答:
{
"block": true,
"reason": "Ask your account manager for account-specific pricing",
"inject_context": "The reader is on the Acme account, locale en-GB."
}block: trueはリクエストを停止します。モデルは呼び出されず、トークンも消費されません。ストリームには、blocked_by_hookのエラーと、設定したreasonが含まれます。ただし、読者に実際に表示される内容については、以下の制限を参照してください。inject_contextは、この質問に限り、追加のシステムメッセージとしてプロンプトに追加されます。追加位置は、独自のシステムプロンプトの後、質問自体の前です。読者のプラン、地域、機能フラグなど、リアルタイムの情報を指定する場所です。- その他すべて — 2xx以外のステータス、解析できないJSON、空の本文、またはタイムアウトまでに返信がない場合 — フックが設定されていない場合とまったく同じようにチャットが続行されます。フックが壊れていてもチャットの機能が低下するだけで、停止することはありません。
3つのフックすべてに5秒のタイムアウトが設定されており、リクエストを中止することで適用されます。pre-hookのタイムアウトでは読者がその5秒を一度待つことになりますが、他の2つでは回答がすでにストリーミングされているため、読者は時間を失いません。
post-hook が受け取るもの#
読者がすでに回答を見た後の、1回のPOST:
{
"question": "How do I rotate an API key?",
"answer": "Rotate an API key in Workspace settings…",
"tool_calls": [{ "tool": "read_page", "path": "guides/keys.md" }],
"latency_ms": 2840,
"workspace_id": 42,
"session_id": "sess_YOUR_SESSION_ID"
}tool_calls は、この質問のためにサーバーが実際に取得したページごとに1つのエントリで構成され、サーバーがページを読み取った順序になっています。つまり、読者が Reading <page> 行として見たものと同じリストです。これはモデル自身のツール使用ではなく、取得の記録です。
ストリーミングフックは、event: "message"、question、answer、refs(フィルタリングを通過した引用)、workspace_id、session_id、latency_ms を受け取ります。tool_calls は含まれません。これを行うのは post-hook です。
どの仕事にどのフックを使うか#
| シナリオ | フック | そのフックを使う理由 |
|---|---|---|
| 別の顧客のアカウントに関する質問を拒否する | プリフック | リクエストを停止できるのはプリフックだけ |
| 読者のプランとロケールをモデルに渡す | プリフック (inject_context) |
モデルは回答する前にそれを必要とする |
| すべてのやり取りを独自の分析ストアにコピーする | ポストフック | 完成した回答が必要だが、何も変更しない |
| 回答に時間がかかりすぎたときにチャンネルに通知する | ストリーミングまたはポストフック | どちらにも latency_ms が含まれる |
| 2つのプロンプト文言をA/Bテストする | プリフック | 一度に1つの質問のプロンプトを変更する |
| ある文字列が決して読者に届かないことを保証する | プリフックまたはシステムプロンプト | ポストフックは読者に渡った後に実行される |
チャットフックには署名がありますか?#
いいえ。Docsbook は Content-Type: application/json を含むプレーンな POST を送信し、HMAC ヘッダーも付けないため、エンドポイントでペイロードを送信元の証明として扱ってはいけません。URL は秘密にし、そのパスまたはクエリ文字列にトークンを含め、Docsbook の送信元に限定し、本文は信頼できない入力として扱ってください。
Docsbook のウェブフックは別の仕組みで、署名されています。sha256=<hex> のとおり、X-Docsbook-Signature-256 における生の本文に対する HMAC-SHA256 です。ウェブフックの検証コードをチャットフックに流用して、何かを検証できると思わないでください。誰でも送信できる本文でも通過してしまいます。
MCP クライアントからのフックの管理#
Claude Code、Cursor、または任意の MCP クライアントからフックを設定する 3 つのツールがあります。
set_chat_hooks # register pre / post / streaming hook URLs
test_chat_hook # send a test ping to one hook and report its status
get_chat_system_prompt # inspect the current system prompt個々のフックをクリアするには、set_chat_hooks に空の文字列を渡します。test_chat_hook は { test: true, hook_type, workspace_id, timestamp, message } を POST し、ステータスコードとラウンドトリップ時間を報告します。ライブパスで使用されるものと同じ 5 秒のタイムアウトが適用されます。管理パネルでも同じフィールドを編集できます。
これが正しい方法である理由(根拠)#
| ルール | 機能する理由 | 出典 |
|---|---|---|
| モデルに想起させるのではなく、プレフックを通じて最新の事実を注入する | 検索拡張生成は、「最先端のパラメトリックのみの」ベースラインよりも「より具体的で、多様かつ事実に基づく言語」を生成する — プロンプトに配置された事実は根拠付けられるが、想起された事実には根拠がない | Lewis et al., 2020 — RAG |
| ポストプロセスではなく、プレフックでブロックする | 指示だけでは、モデルが回答するのを確実には止められない。通常のチューニングでは「モデルがその知識を知っているかどうかにかかわらず、文を完成させるようモデルに強制する」。保証できる拒否とは、そもそもモデルに到達しない拒否である | Zhang et al., 2023 — R-Tuning |
| 署名のないフックペイロードは信頼できないものとして扱う | 署名は送信元を証明するものだ。「サーバーがGitHubから送信されたWebhook配信のみを処理し、配信内容が改ざんされていないことを保証するには、Webhook署名を検証すべきである」。チャットフックには署名がないため、自分で認証する | GitHub — Webhook配信の検証 |
| DocsbookのWebhook署名を一定時間で比較する | 「単純な == 演算子は絶対に使用しないこと。代わりに、secure_compare や crypto.timingSafeEqual のようなメソッドの使用を検討すること」 |
GitHub — Webhook配信の検証 |
制限#
- 読者にはブロック理由が表示されません。
reason文字列はレスポンスストリームで配信されますが、提供される docs-site ウィジェットでは汎用的な「問題が発生しました。もう一度お試しください。」に置き換えられます。つまり、この値は通信上に存在し、カスタムフロントエンドから読み取ることはできますが、標準で提供されるウィジェットには表示されません。reasonはログ用の値として扱い、読者に必ず読ませる必要がある内容は、代わりにシステムプロンプトに記述してください。 - 匿名プレビューのパスではフックは実行されません。 プロジェクト行が作成される前にプレビューされたリポジトリでは、ワークスペースなしで質問に回答するため、プロジェクト単位の他のすべての分岐と同様にプレフックもスキップされます。
- 再試行も配信ログもありません。 Post フックとストリーミングフックは一度だけディスパッチされ、その結果は記録されません。少なくとも1回の配信、再試行、そして確認可能な配信履歴が必要な場合は、これらすべてを備えたwebhookを使用してください。
- 署名はなく、webhook の方式が再利用されるまでは追加する予定もありません。 上記を参照してください。
set_chat_hooksとtest_chat_hookは、依然として Pro が必要だと説明しています。 これらが確認する機能はすべてのプランで利用可能なため、古いのは動作ではなくツールの説明です。これらの文字列が修正されるまでは、未解決の問題として扱ってください。- 遅いプレフックの負担を負うのは読者です。 上限は5秒で、最初のトークンより前に発生します。エンドポイントを高速に保つか、何も返さずにチャットを続行させてください。