このブログの検索ページには、キーワード検索とは別に「AIに聞く」という RAG(Retrieval-Augmented Generation)ベースの自然言語検索を用意しています。 この記事では使い方と、裏側でどう動いているかを簡単にまとめます。

使い方

  1. /search/ を開く

  2. ページ上部の既存キーワード検索(PaperMod標準のfuse.js)とは別に、 「AIに聞く」の質問欄が表示される

  3. 自然文で質問を入力する

    例:「CloudFrontで直下じゃないディレクトリのindex.htmlが403になるのはなぜ?」

  4. 送信するとCloudflare Turnstileによるボット検証が裏で走り、 検証を通過するとバックエンドに問い合わせが飛ぶ

  5. 数秒待つと回答と、根拠にした記事へのリンク(sources)が表示される

質問がこのブログの記事でカバーされていない内容の場合は、 外部知識で答えるのではなく「記事に情報がない」と正直に返す設計になっています。 あくまでこのブログの内容だけを根拠に回答する検索機能です。

裏側の仕組み

インデックス作成(ビルド時)

rag-index/(Java 17 / Maven製CLI)が、content/posts/配下の非draft記事を すべて読み込み、##見出し単位(見出しが無い/長すぎる場合は約1500文字の スライディングウィンドウ)でチャンクに分割します。各チャンクをVoyage AIの 埋め込みAPI(voyage-3-lite)でベクトル化し、{id, slug, title, url, chunkText, embedding} の配列としてindex.jsonにまとめ、専用のS3バケット (www.kanjtomi1967.net-rag-index)へアップロードします。

このインデックス作成はJenkinsのデプロイパイプラインでBuildDeployの間に 毎回実行される(Rebuild RAG Indexステージ)ため、記事を追加・更新して git pushすれば、次のデプロイで自動的に検索対象へ反映されます。

質問応答(実行時)

質問はAPI Gateway経由でLambda(blog-raglambda-rag/、Java 17)の POST /askが受け取ります。

  1. Cloudflare Turnstileトークンをサーバー側で検証
  2. コールドスタート時にindex.jsonをS3からダウンロードし、 ウォーム状態の間はメモリ上に保持
  3. 質問文をVoyage AIで埋め込み、全チャンクとのコサイン類似度で ブルートフォースにランキング(このコーパス規模ならベクトルDBは不要)
  4. 上位4チャンクを取得
  5. 取得したチャンクを根拠としてClaude(claude-haiku-4-5)に渡し、 その内容に基づいて回答を生成
  6. {answer, sources: [{title, url}]}を返す

API Gatewayのステージには控えめなスロットル(burst 5 / rate 2)もかけてあり、 スクリプトによる乱用でClaude APIの課金が跳ね上がらないよう二重に対策しています。

まとめ

  • 記事本文だけを根拠にするので、ハルシネーションのリスクを抑えつつ 「このブログのどこに書いてあったか忘れた」を解消できる
  • 記事を書いてpushすれば自動でインデックスが更新される
  • Turnstile + スロットリングでコストと乱用を両方抑えている

気になる記事を検索キーワードで思い出せないときは、ぜひ「AIに聞く」を 試してみてください。