課題
探しているものを自然文で伝えると、カタログの中から候補を検索・比較して薦めるサービスの構想でした。ただし、推薦文をAIに自由に書かせることも、候補をまとめてAIに渡して並べさせることもできない前提がありました。「今どきのやり方」がそのまま使えないうえで、なぜこの順番で薦めたのかを運営側が説明できる必要もあります。加えて、求めているものを商品名で書けない利用者もいます。遠回しな言い方からでも意図を拾える検索が要りました。
- AIに推薦文を自由に書かせる構成が採れない
- 商品名を知らない言い回しでも、意図した商品にたどり着かせたい
- なぜこの順番で薦めたのかを、運営側が説明できる形にしたい
解決策
LLMの担当を、自然文を条件に構造化する入口と、理由を文章にする出口だけに限定し、検索と並べ替えは自前のスコア関数で決定論的に行う構成にしました。出口でも商品説明の原文はLLMに渡さず、検索エンジンが機械的に照合した根拠、つまり一致した条件・価格・評点だけを渡して、その範囲内で文章を組ませます。生成結果には最後に、正規表現で書いたNG表現フィルタを必ず一枚かけています。
- BM25(語彙一致)とベクトル検索を並走させ、RRFで統合。概念辞書でクエリを言い換えごと拡張
- 条件一致・嗜好適合・品質(レビュー評点のベイズ平均)・予算適合などの重み付き和で並べ替え、同じブランドが続いたらペナルティ
- 入口の構造化はドメイン定義に列挙した選択肢から選ばせ、存在しない値は破棄。失敗時はルール実装にフォールバック
結果
並べ替えの根拠がスコアの内訳として数値で残るため、「AIが選びました」で終わらせずに、なぜこの並びなのかを運営側が説明できます。重みは設定ファイルの値なので、変えて比べることもできます。検索と並べ替えは10ミリ秒未満(依存ゼロ構成での実測)で、LLMを呼ぶのは候補件数によらず入口と出口の2回だけなので、扱う商品が増えても応答時間と費用が比例して膨らみません。精度は評価ハーネスで測る形にしてあり、回帰検知用のセットでは、LLMを呼ばずに概念辞書を1回改訂しただけで、nDCG@5が0.907から0.988まで動きました。実力測定用のホールドアウトは別に用意して、そちらの数字も分けて追っています。エンジンは商材ジャンルに依存しない作りで、ドメイン定義ファイルを差し替えるだけで別ジャンルに載せ替えられることも、日本酒のカタログで確認しました。
Beekleだからできたこと
生成AIに任せられない前提から、動く推薦エンジンを設計する
「AIにお任せ」で済ませられない事情があっても、推薦の質と説明責任を両立した検索・推薦を持てます。
LLMの担当を入口と出口に限定し、BM25とベクトル検索のRRF統合+決定論的なスコア関数で並べ替えを自前実装。生成文には機械的なNG表現フィルタを一枚かけ、精度は評価ハーネスで数値化しました。
Beekleでは、LLMに何をさせないかを先に決めてから設計します。この案件でも、並べ替えをLLMに渡さないことで応答速度・費用・説明責任を同時に確保し、AIが書ける範囲を仕組みとして限定しました。精度も感想ではなく評価ハーネスの数値で語れる状態にしてあるので、辞書や重みを触った影響を回帰込みで確認しながら改善できます。