なぜハイブリッドなのか — DenseとSparseの相補性

第3章で見たように、Dense(ニューラル埋め込み)とSparse(BM25等)はそれぞれ別の強みを持ちます。 どちらか一方では必ず取りこぼします。両者を組み合わせることで、両方の弱点を相互に補えるのがハイブリッド検索の発想です。

クエリ例 Denseの強み Sparseの強み
「犬」と「ワンちゃん」 ◎(意味類似) ✕(表記違い)
「GPT-4o」完全一致 △(AI全般に引き寄せ) ◎(語彙一致)
「バグを直す」「欠陥を修正」 ◎(言い換え対応) ✕(別語彙)
「APIメソッド createUser()」 △(概念に引き寄せ) ◎(識別子完全一致)
多言語クエリ(日英混在) ◎(多言語モデル) △(言語分離必要)

実務ベンチマークでは、ハイブリッド検索は単一手法に対してRecall +15〜30%を達成することが報告されています。 2026年時点で主要ベクトルDB(Weaviate、Milvus 2.5+、Qdrant v1.9+、LanceDB、Pinecone)はすべてハイブリッド検索を標準装備しています。

RRF — Reciprocal Rank Fusionの魔法

異なる検索結果をどう融合するかが問題です。生のスコア(コサイン類似度 vs BM25スコア)はスケールが違うので単純加算はできません。 ここで使われるのがRRF(Reciprocal Rank Fusion)です。

def rrf_fusion(*rankings, k=60):
    """複数の順位付き結果リストをRRFで融合"""
    scores = {}
    for ranking in rankings:
        for rank, doc_id in enumerate(ranking):
            scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank)
    return sorted(scores.items(), key=lambda x: -x[1])

# Dense検索とBM25を並走、RRFで融合
dense_ranked = vector_search(query, k=50)
bm25_ranked  = bm25_search(query, k=50)
fused = rrf_fusion(dense_ranked, bm25_ranked, k=60)
top_k = fused[:10]

Linear combination(α × dense + (1-α) × sparse)もありますが、αのチューニングにラベルデータが必要です。 実務ではまずRRFで動かし、ラベルが溜まってからLinear combinationへ移行するのが鉄板フローです。

Bi-encoder vs Cross-encoder — Rerankerの役割

第3章で触れたDense埋め込みは正確にはBi-encoderです。クエリと文書を独立にエンコードしてベクトル化するため、事前計算でき高速です。 一方、Cross-encoderはクエリと文書をペアで同時にTransformerに入力し、関連度スコアを直接出力します。

Bi-encoder(検索用) Cross-encoder(Rerank用)
入力 クエリと文書を独立にエンコード クエリと文書をペアで同時入力
速度 高速(ANNで数ms) 低速(1ペア数十ms)
事前計算 可能(インデックス化) 不可
精度
スケール 数百万〜数十億件 〜数百件(再ランク用途)
代表モデル BGE、E5、Ruri、OpenAI-3 Cohere Rerank、Jina v3、BGE Reranker
graph LR
  Q[クエリ] --> Stage1[Stage 1: Retrieval\n Bi-encoder Hybrid\n Top-50 to 100]
  KB[(知識ベース\n 数百万件)] --> Stage1
  Stage1 --> Stage2[Stage 2: Rerank\n Cross-encoder\n Top-5 to 10]
  Stage2 --> LLM[Stage 3: LLM Generation]

  style Stage1 fill:#8b5cf6,stroke:#6d28d9,color:#fff
  style Stage2 fill:#f97316,stroke:#ea580c,color:#fff
  style LLM fill:#14b8a6,stroke:#0d9488,color:#fff
2段階検索: Bi-encoderで候補を絞り、Cross-encoderで精度を高める。2026年本番RAGの標準構成

2026年の主要Rerankerモデル

モデル ELO/精度 レイテンシ 特徴
Zerank 2 1638 ELO(首位) 2026年の最高精度Reranker
Cohere Rerank v4.0 Pro 1629 ELO ~600ms 多言語・本番定番
Jina Reranker v3 BEIR 61.94 nDCG@10 <200ms(最速級) v2比+5.43%、サブ200ms唯一のトップ層
BGE Reranker v2-m3 実用十分 自社ホスト可 OSS定番・多言語・プライバシー◎
japanese-reranker-base-v2 JQaRA 0.7845 CPU可 日本語特化、19層/512hidden

Contextual Retrieval — Anthropicの革新

2024年9月、Anthropicが発表したContextual Retrievalは、RAGの精度を根本から引き上げる画期的手法です。 コアアイデアはシンプル:各チャンクに「全体文書の中でそのチャンクが何を意味するか」の文脈(50〜100トークン)を先頭に付与してから埋め込む

なぜ効くのか

「この会社の売上は前四半期比3%増加した」というチャンクは、単体では「どの会社か・いつか」の文脈が失われています。 「ACME社のQ2 2023レポートより。前四半期(Q1 2023)の売上は3.14億ドル」という文脈プレフィックスを加えると、 「ACMEのQ2売上は?」というクエリに確実にヒットするようになります。

公式プロンプト(そのまま使える)

<document>
{{WHOLE_DOCUMENT}}
</document>
Here is the chunk we want to situate within the whole document
<chunk>
{{CHUNK_CONTENT}}
</chunk>
Please give a short succinct context to situate this chunk within the overall
document for the purposes of improving search retrieval of the chunk. Answer
only with the succinct context and nothing else.

このプロンプトをClaude 3 Haikuで各チャンクに実行し、生成された文脈をチャンクの先頭に結合してからEmbeddingとBM25インデックスに投入します。

失敗率削減の実測値

手法 失敗率(top-20) ベースライン比
Naive Embeddings 5.7% -
Contextual Embeddings 3.7% -35%
+ Contextual BM25 2.9% -49%
+ Reranking (Cohere) 1.9% -67%
// TypeScript実装例(@anthropic-ai/sdk)
const response = await client.messages.create({
  model: 'claude-3-haiku-20240307',
  max_tokens: 150,
  system: [
    {
      type: 'text',
      text: `<document>\n${wholeDocument}\n</document>`,
      cache_control: { type: 'ephemeral' }, // 文書をキャッシュ
    },
  ],
  messages: [
    {
      role: 'user',
      content: `Here is the chunk...\n<chunk>${chunkContent}</chunk>\nPlease give a short succinct context...`,
    },
  ],
});

const contextualChunk = `${response.content[0].text}\n\n${chunkContent}`;
// これをembedding・BM25両方に投入

日本語ハイブリッド検索の落とし穴

日本語でBM25を使うには形態素解析によるトークナイズが必須です。 スペース区切りの英語と違い、日本語をそのまま単語分割せずにBM25に投入すると、検索品質が壊滅します。

ツール 速度 特徴 推奨用途
MeCab 高速 枯れた定番 リアルタイム処理
Sudachi 3分割単位・固有表現に強い 検索用トークナイズ(第一候補)
Janome Pure Python プロトタイピング
GiNZA(ja_ginza) spaCyベース・NER エンティティ抽出併用

本番パイプラインの全体構成

graph TD
  Q[クエリ] --> QT[Query Transform\n HyDE/Multi-query]
  QT --> D[Dense検索\n Top-50]
  QT --> S[BM25検索\n Sudachi tokenize\n Top-50]
  D --> RRF[RRF融合\n k=60]
  S --> RRF
  RRF --> RR[Cross-encoder Rerank\n japanese-reranker-v2]
  RR --> F[Filter and Assembly\n 重要chunkを端に]
  F --> LLM[LLM Generation]

  style D fill:#8b5cf6,stroke:#6d28d9,color:#fff
  style S fill:#ec4899,stroke:#be185d,color:#fff
  style RRF fill:#f97316,stroke:#ea580c,color:#fff
  style RR fill:#14b8a6,stroke:#0d9488,color:#fff
2026年の日本語RAG本番パイプライン: Hybrid Retrieval → RRF → Rerank → Context Assembly → LLM

次章への導線

ここまでで検索品質を極限まで引き上げる技術を押さえました。 しかし「評価なしで本番投入」が、2026年時点でもRAG失敗の最大の原因です。 次章ではRagasを中心としたRAG評価フレームワーク、合成データによる評価セット自動生成、LLM-as-Judgeの落とし穴を詳説します。

理解度チェック

問題 0 / 50%
Q1

RRF(Reciprocal Rank Fusion)でハイブリッド検索を行う際、業界標準で使われる定数kの値はいくつですか?

キーボード: 1〜4 で選択、Enter で回答