2026年8月11日
サイトにAIチャットボットを実装した。「知らないことは知らないと言う」設計にこだわった話
ATAU Digital Designは、自社サイトにRAG構成のAIチャットボットを実装しました。ブログ記事に根拠がある場合のみ回答し、なければ正直に「わからない」と伝える——そのための設計判断を、実装の裏側とともに紹介します。
きっかけ:お問い合わせの手前にある「聞きにくさ」
ATAUのサイトには、事業内容やIntaviewについての説明記事を数多く掲載しています。それでも、実際に相談したい方が最初に感じるのは「これって聞いていい内容なのかな」という迷いだと考えています。
お問い合わせフォームは、要件がある程度固まってから使うものです。その手前——「まだ質問レベルの疑問」を持った方が、フォームを開かずにその場で解消できる導線を作りたいと考え、ブログ記事を根拠にしたAIチャットボットを実装しました。
設計原則:「知らないことは知らないと言う」
チャットボットを作るとき、最も避けたかったのはもっともらしい嘘をつくことでした。AIが自社にない実績を答えたり、存在しない記事URLを作り出したりすれば、それは接客ではなく事故です。
そこで最初に決めたのが、次の設計原則です。
LLMはコンテキストとして渡された記事本文以外の知識を使って回答してはならない。URLはLLMに生成させず、検索結果のメタデータから機械的に確定する。
「AIに何でも答えさせる」のではなく、「AIが答えられる範囲を明示的に区切る」ことを起点にしました。
全体アーキテクチャ
仕組みはシンプルなRAG(Retrieval-Augmented Generation)構成です。
- ビルド時:公開中のブログ記事すべてをGemini Embedding APIでベクトル化し、検索インデックスとして書き出す
- 質問時:ユーザーの質問も同じ方法でベクトル化し、コサイン類似度で近い記事を検索
- 閾値判定:十分近い記事が見つからなければ、その時点でAIを呼ばずに「該当なし」を返す
- 生成:見つかった記事本文だけをコンテキストとしてClaude Haikuに渡し、その範囲内でのみ回答させる
「検索してから生成する」という2段構えにすることで、AIが自由に知識を持ち出す余地をなくしています。
こだわったポイント1:AIに「JSONで答えろ」ではなく「JSONしか出せない」ようにする
Claudeへのシステムプロンプトで「JSON形式で出力してください」と指示するだけでは、AIが説明文を混ぜて返してくることがあります。そこでClaude APIのtool use機能を使い、「この形式のツールを必ず呼び出す」という制約をAPIレベルで強制しました。
{ "noContext": true }
{ "noContext": false, "answer": "回答本文" }
この2択以外の出力を構造的にできないようにすることで、プロンプトの言い回しに頼らない、壊れにくい実装になっています。
こだわったポイント2:「わからない」を二重にチェックする
「該当なし」の判定を、検索スコアだけに任せていません。
- 1段目:類似度スコアが閾値未満なら、そもそもAIを呼ばずに「該当なし」
- 2段目:スコアが閾値を超えて記事をAIに渡した後も、AI自身が「この文脈では答えられない」と判断すれば
noContext: trueを返せる
検索の精度とAIの判断、両方が「答えられる」と言って初めて回答を返す仕組みです。どちらか一方に間違いがあっても、もう一方が歯止めになります。
こだわったポイント3:フレームワークを増やさない
チャットのようなインタラクティブなUIは、ReactなどのUIフレームワークで作るのが一般的です。ただ、このサイトはAstroによる静的サイトで、UIフレームワークを持ち込んでいません。今回のためだけに新しい依存を増やすのは、サイト全体の軽さを損なう判断だと考えました。
結果として、チャットウィジェットは素のAstroコンポーネントと素のTypeScriptだけで実装しています。フレームワークのランタイムを1バイトも増やさずに、全ページ右下から使えるチャット機能を追加できました。
こだわったポイント4:ログを取るなら、被害範囲を最小にする
閾値のチューニングには実際の質問ログが欠かせません。とはいえ、ログ基盤を作るからといって過剰な権限を持つ鍵を扱うのは避けたいところです。
そこで、チャットログ専用に新しいSupabaseプロジェクトを分離して立て、書き込み権限もRow Level Securityで「このテーブルへのINSERTのみ」に絞りました。万が一キーが漏れても、被害はこのログテーブルの範囲に閉じます。機能を作ることと、その機能が持つリスクの範囲を狭めることは、同時に考えるべきだと考えています。
実際の動作
たとえば「Intaviewとは何ですか?」と聞くと、該当する記事を根拠に、その記事へのリンク付きで回答が返ってきます。一方で「明日の天気は?」のような無関係な質問には、正直に「該当する情報が見つかりませんでした」と伝えたうえで、質問内容を引き継いだままお問い合わせフォームへ誘導します。
「答えられないことを、答えられないまま終わらせない」——ここも設計でこだわった部分です。
これから
現時点では類似度の閾値は初期値のままです。今後は実際の質問ログを見ながら、「本来答えられたのに該当なしになっていないか」「見当違いの記事で誤答していないか」を確認し、調整していく予定です。(その後の調整についてはこちらの記事で紹介しています)
おわりに
今回のチャットボットは、まず自分たちのサイトで実際に使ってみるところから始めました。ブログ記事を書く→AIに読ませる→ユーザーの質問に答えさせる、という一連の流れを自社で運用してみることで、次はクライアントの現場でのAI活用支援にも活かせる知見が積み上がっています。
サイトの右下からぜひ実際に触ってみてください。IT活用やAI導入のご相談も、チャットボット経由・お問い合わせフォームどちらからでもお気軽にどうぞ。