AIシステムが「特定のキーワード」に戸惑うとき
社内向けのRAGチャットボットを完成させ、自信満々でデモに臨んだとしましょう。上司が「Dell XPS 9315の仕様」という具体的な製品番号を入力しました。しかし、チャットボットはそのモデルを正確に返す代わりに、XPS 13シリーズ全般について語り出したり、最悪の場合は旧モデルの情報を出したりします。結果として、上司はがかがりし、あなたは困惑することになります。
問題はデータにあるのではありません。データはベクトルデータベース(Vector Database)に存在していますが、AIが適切な情報を「拾い出す」ことができなかったのです。エンタープライズAIプロジェクトの実装経験から言えるのは、ベクトル検索(Vector Search)は「意図」を理解するのは得意ですが、SKU番号や固有名詞、専門用語にはしばしば「お手上げ」状態になるということです。ここで救世主として登場するのが、ハイブリッド検索(Hybrid Search)です。
問題の本質:なぜベクトル検索だけでは不十分なのか?
ベクトル検索は、テキストの意味を数値の列(Embedding:埋め込み)に圧縮することで機能します。圧縮する際、モデルは正確な文字の一致よりも、文章全体の「ニュアンス」を保持することを優先します。
例えば、「iPhone 13」と「iPhone 14」のベクトル座標は非常に近くなります。AIの目には、どちらもAppleのハイエンドスマートフォンとして映ります。ユーザーが13シリーズの正確な交換部品を探している場合、意味的な類似度が98%に達するため、システムは14シリーズの結果を返してしまう可能性があります。
対照的に、キーワード検索(BM25アルゴリズムなど)は「文字の照合」に特化しています。「iPhone」が何であるかを知る必要はなく、テキストが1文字ずつ正確に一致するかどうかだけを気にします。弱点は柔軟性のなさです。ユーザーが「リンゴ印のスマホ」と入力しても、一致する文字が見つからないため、全く反応できません。
ハイブリッド検索:二つの強みを融合させる
どちらか一方を諦めるのではなく、ハイブリッド検索はDense Retrieval(ベクトル検索 – 意味理解)とSparse Retrieval(キーワード検索 – キーワード一致)を組み合わせます。
私が以前手掛けた技術文書検索プロジェクトでは、純粋なベクトル検索からハイブリッド検索に切り替えたことで、Top-1の正解率(Accuracy)が62%から89%まで向上しました。Qdrantは、このメカニズムをコア部分でネイティブにサポートしている数少ないエンジンの1つです。
QdrantとPythonによる実装ガイド
まず、qdrant-clientをインストールする必要があります。外部APIを呼び出さずにローカルで埋め込み処理を行えるfastembedの併用をお勧めします。
pip install qdrant-client fastembed
ステップ1:クライアントの初期化
複雑なDockerのセットアップなしで素早くデモを行うために、Qdrantの:memory:モードを使用します。
from qdrant_client import QdrantClient
# テスト用にRAM上で直接実行
client = QdrantClient(":memory:")
ステップ2:ハイブリッド・コレクションの設定
ここが重要なポイントです。Dense(高密度ベクトル)用のvectors_configと、Sparse(低密度ベクトル)用のsparse_vectors_configの両方を定義する必要があります。
from qdrant_client.models import Distance, VectorParams, SparseVectorParams
client.create_collection(
collection_name="hybrid_rag_demo",
vectors_config={
"dense": VectorParams(size=384, distance=Distance.COSINE)
},
sparse_vectors_config={
"sparse": SparseVectorParams()
}
)
ステップ3:スマートなデータの投入
Qdrantにはベクトル生成を自動化する非常に便利な機能があります。生のテキストを入力するだけで、後はシステムが自動的に処理してくれます。
documents = [
"Dell XPS 9315 ノートPC 第12世代 Core i7",
"Macbook Pro M2 14インチ Retinaディスプレイ",
"エレクトロラックス洗濯機 エラーE01の対処方法"
]
# QdrantがDenseベクトルとSparseベクトルの両方を自動生成
client.add(
collection_name="hybrid_rag_demo",
documents=documents
)
ステップ4:ハイブリッド・クエリの実行
システムはRRF(Reciprocal Rank Fusion)アルゴリズムを使用して、2つの検索手法の結果を統合します。
results = client.query(
collection_name="hybrid_rag_demo",
query_text="洗濯機 エラー E01",
limit=3
)
for hit in results:
print(f"結果: {hit.metadata['document']} | スコア: {hit.score:.4f}")
実践における3つの重要な注意点
ハイブリッド検索をプロダクション環境に導入する過程で得た、いくつかの「教訓」を紹介します。
- 重みの調整: すべてのプロジェクトで50:50の比率が最適とは限りません。技術コードやサーバーログを多く含むデータの場合は、キーワード検索の重みを高く設定してください。
- 言語固有の問題: Sparse Vectorは分かち書き(トークナイズ)に大きく依存します。日本語の場合、形態素解析エンジンを使用して適切にテキストを前処理することが、精度の向上に繋がります。
- リソースコスト: 2種類のベクトルを保存するため、ストレージ容量が約20〜30%増加します。しかし、システムの精度向上を考えれば、これは非常に安い代償です。
おわりに
製品番号が見つからないという理由だけで、チャットボットを使い物にならないものにしないでください。ハイブリッド検索にCross-Encoderによるリランキング(Reranking)を組み合わせることは、現在のあらゆるRAGシステムにおいて完璧な組み合わせとなります。標準的なフローは、「ハイブリッド検索 → 上位10件をリランク → LLMに投入」となります。皆さんのAIプロジェクトの成功を祈っています!

