AIチャットボットを自作する際、最も重要なアーキテクチャのひとつがRAG(Retrieval-Augmented Generation)です。ユーザーの質問に対して、事前に学習したサイトの情報を参照して回答する仕組みを一から構築したので、その実装を共有します。
この記事で扱う範囲は以下の通りです。テキストの抽出とチャンク分割、ベクトル埋め込みの生成、Supabaseのpgvectorを使った類似度検索、LLMへのコンテキスト組み立てまで。すべて実際のコードベースから抜粋した内容です。
全体のアーキテクチャ
RAGパイプラインは大きく3つのステップで構成されています。1つ目はサイトからテキストを抽出しチャンクに分割する「インジェスト」、2つ目は各チャンクのベクトル埋め込みを生成してDBに保存する「エンベッド」、3つ目はユーザーの質問に対して関連チャンクを検索してLLMに渡す「検索と生成」です。
Step 1:HTMLからテキストを抽出する
まず、ターゲットサイトのHTMLから意味のあるテキストだけを抽出します。単純にHTMLタグを除去するだけでなく、nav、header、footer、style、scriptタグを事前に削除して、本文コンテンツのみを取得するのがポイントです。
さらに、HTML内に埋め込まれたJSON-LD(schema.org)の構造化データも別途抽出します。FAQページやサービス紹介ページには、通常の本文より高品質な情報がJSON-LDに格納されていることが多く、これを活用できるとベクトル検索の精度が上がります。
Step 2:テキストをチャンクに分割する
抽出したテキストをベクトル検索に適したサイズのチャンクに分割します。ここでは文境界ベースのチャンク分割を実装しています。
重要な判断は2つあります。1つ目は分割の区切り文字です。日本語では「。」を区切りに使い、改行区切りも併用します。2つ目は短いチャンクの処理です。100文字未満のチャンクは前のチャンクに統合し、文脈の欠落を防ぎます。最大文字数は2000文字で制限しています。
この「短いチャンクの統合」は実際の運用でかなり効果があります。分割アルゴリズムの都合で1文だけのチャンクが発生すると、その埋め込みベクトルは周囲の文脈を欠くため、検索精度が低下します。
Step 3:ベクトル埋め込みを生成する
各チャンクのベクトル埋め込みを生成します。ここではOpenAI互換の埋め込みAPIを使用しており、Gemini APIにも自動フォールバックするマルチプロバイダ構成にしています。
実運用で特に苦労したのはレート制限の処理です。Gemini APIのバッチ埋め込みでは、100件ずつのバッチに分割し、バッチ間に4.5秒の遅延を挟むことでレート制限に対応しています。指数バックオフのリトライも実装し、429エラーに対しては指数関数的に待機時間を増やすことで安定稼働を実現しています。
Step 4:ベクトル検索で関連チャンクを取得する
ユーザーの質問が来たとき、まずその質問のベクトル埋め込みを生成し、Supabaseのpgvectorで類似度検索を実行します。
検索では類似度スコアの閾値を意図的に低め(0.05)に設定しています。これは、まず広めに関連チャンクを集め、その後で信頼度の低いものを除外するためです。上位10件を取得し、同一URLのチャンクは最もスコアの高いものだけを残して重複排除します。
重複排除は重要です。1つのページから複数のチャンクが検索結果に混在すると、LLMのコンテキストが同じ情報で埋め尽くされ、回答の質が低下します。URLをキーにしてスコア最高的ものだけを残すことで、情報の多様性を保ちます。
Step 5:LLMにコンテキストを渡して回答を生成する
検索結果のチャンクをLLMのシステムプロンプトに組み込みます。ここでの工夫は、信頼度に応じてコンテキストの内容を動的に切り替えることです。
上位結果の類似度スコアが一定以上であれば、検索結果をそのままコンテキストとして渡します。スコアが低い場合は、検索結果を破棄して「情報が見つかりませんでした」と回答するようLLMに指示します。これにより、不正確な情報の出力を防いでいます。
おまけ:FAQの自動生成
サイトのスクレイピングが完了したあと、LLMを使って自動でFAQを生成する仕組みも実装しています。スクレイピングで得られたテキストの要約から質問と回答のペアを作成し、ユーザーの質問に対する参照情報として追加します。
これにより、サイト上のページに明記されていない質問にも、LLMがFAQを元に適切に回答できるようになります。手動でFAQを書く手間が省けるのも大きなメリットです。
まとめ
RAGパイプラインを自作する上で特に苦労したのは、テキストの品質管理です。HTMLからのテキスト抽出、チャンク分割の粒度、検索結果の重複排除、信頼度に応じたコンテキスト切り替え。これらの一連の処理が回答精度を大きく左右します。
今回紹介した実装はHelpy AI ChatというAIチャットボットサービスの技術基盤の一部です。自社サービスとして公開しており、無料トライアルで試せます。 → https://www.helpy-ai-chat.com/