高性能 RAG のための高度な取得技術: LLM を利用したシステムの最適化

高性能 RAG のための高度な取得技術

検索拡張生成 (RAG) はエンタープライズ AI アプリケーションのバックボーンとなっていますが、システムが拡大し、クエリがより複雑になるにつれて、基本的な検索方法では不十分になってきています。遅くて不正確な RAG システムと高パフォーマンスの RAG システムの違いは、多くの場合、取得戦略にあります。

この包括的なガイドでは、RAG のパフォーマンス、精度、およびスケーラビリティを大幅に向上させる高度な取得テクニックについて説明します。カスタマー サポート ボット、ナレッジ アシスタント、エンタープライズ検索システムのいずれを構築している場合でも、これらの戦略は RAG パイプラインを変革します。


1. 取得のボトルネックを理解する

最適化する前に、RAG システムが通常どこで失敗するかを特定しましょう。

  • 低再現率: ベクトル検索で見つからなかったため、関連するドキュメントがありません。
  • 不適切なランキング: ドキュメントは検索されていますが、無関係なものが最初にランク付けされています。
  • 遅延の問題: 大規模なデータセットに対するベクトル類似性検索が遅い。
  • コンテキストの不一致: 取得されたチャンクには、LLM が正確な応答を生成するのに十分なコンテキストがありません。
  • クエリとドキュメントのセマンティック ギャップ: ユーザーのクエリはドキュメントの埋め込みと適切に一致していません。

これらの問題は規模が大きくなるとさらに悪化します。 5 つのドキュメントを取得する 90% の取得精度を持つシステムは、LLM の応答を完全に変える重要な情報を見逃す可能性があります。


2. ハイブリッド検索: ベクトル検索とキーワード検索の組み合わせ

実稼働 RAG にとって最も影響力のある改善は、以下を組み合わせた ハイブリッド検索 です。

  • ベクトル検索: 意味的類似性 (クエリの 意味)
  • キーワード検索 (BM25): 用語の完全一致 (クエリの内容*)

ハイブリッド検索が機能する理由

「Python 機械学習ライブラリ」を検索することを想像してください。純粋なベクトル検索では、ドキュメントで「Python」という用語が強調されていない場合、「scikit-learn」または「TensorFlow」に関するドキュメントが見つからない可能性があります。逆に、BM25 は完全一致を見つけますが、「Python の ML フレームワーク」などの同義クエリでは失敗します。

実装戦略

[User Query]
    ├──> [Vector Search] ──> [Top K results]
    │                              │
    │                              ▼
    └──> [BM25 Search] ──> [Top K results] ──> [Merge & Rerank]
                                            [Final Ranked Results]

手順:

  1. 埋め込み空間でベクトル検索を実行 → 上位 K 件の結果を取得
  2. 転置インデックスを使用したBM25(キーワード)検索を実行 → 上位K件を取得
  3. 2 つの結果セットをマージし、重複を削除します。
  4. ランク付けアルゴリズム (相互ランク融合など) を適用して、最終的なランク付けされたリストを作成します。

実用的な効果: ハイブリッド検索は、通常、特に事実に基づくクエリやドメイン固有のクエリにおいて、ベクトルのみの検索と比較して再現率を 15 ~ 40% 向上させます。


3. クエリの書き換えと拡張

生のユーザー クエリは、検索するには表現が不十分であることがよくあります。クエリの書き換えおよび拡張技術によりクエリが変換され、検索の精度が向上します。

テクニック 1: LLM を使用したクエリのリライト

軽量 LLM を使用して、ユーザーのクエリを意味的に同等の複数の形式に言い換えます。

元のクエリ: 「非同期コードをデバッグするにはどうすればよいですか?」

書き換えられたバリアント:

  • 「非同期プログラミングのデバッグ」
  • 「非同期/待機の問題のトラブルシューティング」
  • 「同時実行コードのバグを見つける」
  • 「非同期デバッグツールとテクニック」

実装

User Query
    │
    ▼
[LLM Rewriter Prompt]
    "Given this query: '{query}'
     Generate 3 alternative phrasings that capture the same intent."
    │
    ▼
[Multiple Query Variants]
    │
    ▼
[Parallel Vector Searches]
    │
    ▼
[Merge & Deduplicate Results]

テクニック 2: クエリの分解

複雑な複数部分のクエリをより単純なサブクエリに分割します。

元のクエリ: 「高トラフィックのシナリオにおけるマイクロサービスとモノリシック アーキテクチャの遅延の影響は何ですか?」

分解されたクエリ: 1.「マイクロサービスのレイテンシ特性」 2.「モノリシックアーキテクチャのパフォーマンス」 3. 「高トラフィックシステムの設計パターン」

個別に検索してから、LLM の結果を合成します。

テクニック 3: クエリとドキュメントの語彙の調整

ドメイン固有の同義語と別名をナレッジ ベースに埋め込みます。

  • 「ニューラルネットワーク」↔「深層学習モデル」↔「NN」をリンク
  • 「GPU」↔「グラフィックスプロセッシングユニット」↔「NVIDIA CUDAデバイス」をリンク

これにより、用語が異なっていても意味上の類似性が保証されます。


4. 密通路検索 (DPR) とクロスエンコーダー

単純なベクトルの類似性 (コサイン距離を使用) では、多くの場合、ドキュメントが最適にランク付けされません。高度なランキング モデルにより、結果が大幅に向上します。

クロスエンコーダーの再ランキング

ベクトル検索によって候補ドキュメントが取得された後、クロスエンコーダー によって候補ドキュメントが再ランク付けされます。

アーキテクチャの違い:

  • バイエンコーダー (Sentence-BERT など): クエリとドキュメントを別々にエンコードし、類似度を計算します
  • クロスエンコーダー: クエリとドキュメントのペアを結合してエンコードし、関連性スコアを直接出力します。

クロスエンコーダが優れている理由: クロスエンコーダは、バイエンコーダが見逃すクエリとドキュメント間の対話パターンをキャプチャできます。計算コストは​​高くなりますが、再ランキングの精度は非常に高くなります。

実装パイプライン:

[User Query]
    │
    ▼
[Vector Search: Fast, Recall-Optimized]
    ├─> Top 100 candidates (trade-off: some noise)
    │
    ▼
[Cross-Encoder Reranking: Accurate, Precision-Optimized]
    │
    ├─> Score each candidate individually
    │
    ▼
[Return Top 5-10 Reranked Results to LLM]

トレードオフ: ベクトル検索はエンコードでは O(1) ですが、類似度の計算では O(n) です。クロスエンコーダはエンコードに関しては O(n) ですが、優れたランキングを提供します。ベクトル検索を使用して再現し、クロスエンコーダを使用して精度を高めます。

: 100 万のドキュメントを含むデータセットは、ベクトル検索によって 50 の候補にフィルタリングされ、クロスエンコーダーによって ~100 ミリ秒で再ランク付けされます。


5. 階層チャンク化とチャンク管理

ドキュメントをチャンクして整理する方法は、検索と LLM 推論に劇的な影響を与えます。

チャンク問題

固定サイズのチャンク (例: 「500 トークンごとに分割」) では、セマンティック境界が失われます。

  • 600 トークンのチャンクには 2 つの無関係なトピックが含まれる可能性があります
  • 重要なコンテキスト境界が人為的に切断される

解決策: 階層チャンク化

ドキュメントをレイヤーに整理します。

[Document Level: Full context]
    │
    ├─> [Section Level: Logical grouping]
    │   │
    │   └─> [Paragraph Level: Semantic units]
    │       │
    │       └─> [Chunk Level: Retrieval granularity]

取得戦略:

  1. 小さなチャンクを取得して正確なベクトル検索をヒットさせる
  2. 上方向にトラバースして親コンテキスト (セクション、ドキュメント全体) を含めます
  3. 拡張されたコンテキストを LLM に渡す

:

  • 取得: 「機械学習は AI のサブセットです…」 (小さなチャンク、100 トークン)
  • 展開: 親セクション「AI の基礎」とニューラル ネットワークに関するサブセクションを含めます。
  • LLM に渡す: 明確な階層関係を含む完全なコンテキスト (500 以上のトークン)

メタデータが豊富なチャンキング

よりスマートに取得できるように、チャンクにメタデータをタグ付けします。

{
  "chunk_id": "doc_42_section_3_para_5",
  "content": "...",
  "metadata": {
    "document_title": "Machine Learning Fundamentals",
    "section": "Supervised Learning",
    "subsection": "Classification Algorithms",
    "document_type": "tutorial",
    "creation_date": "2026-01-15",
    "author": "Dr. Jane Smith",
    "keywords": ["classification", "supervised learning", "algorithms"],
    "source_url": "https://..."
  }
}

これにより、ベクトル検索の前に メタデータ フィルタリング:「2026 年に書かれたチュートリアル ドキュメントの結果を表示」が有効になり、検索スペースが削減され、関連性が向上します。


6. 適応的なチャンク サイズ設定とセマンティック分割

固定チャンク サイズは非効率的です。アダプティブ戦略は、コンテンツのセマンティクスに基づいてチャンク境界を調整します。

セマンティックチャンクアルゴリズム

  1. 文の埋め込みを計算: 各文をベクトルに変換します
  2. ギャップの測定: 連続する文間の埋め込み類似性を計算します。
  3. 境界の特定: 類似性がしきい値を下回った場合、チャンク境界を作成します。
  4. 可変サイズのチャンク: チャンクは意味上の境界に自然に一致します

利点: チャンクはトピック境界内に留まり、ベクトル検索の精度が 5 ~ 15% 向上します。

実装擬似コード

sentences = split_into_sentences(document)
embeddings = encode_all_sentences(sentences)

chunks = []
current_chunk = [sentences[0]]

for i in range(1, len(sentences)):
    similarity = cosine_similarity(embeddings[i], embeddings[i-1])
    
    if similarity < THRESHOLD:  # Topic boundary
        chunks.append(current_chunk)
        current_chunk = [sentences[i]]
    else:
        current_chunk.append(sentences[i])

chunks.append(current_chunk)

7. 反復改良とフィードバック ループ

高性能 RAG システムは静的に取得するのではなく、フィードバックに基づいて適応します。

テクニック 1: マルチターンクエリの絞り込み

LLM が応答を生成した後、その品質を評価します。

[Initial Query]
    │
    ├─> [Retrieval & Generation]
    │
    ├─> [Evaluate Response Quality]
    │   - Does LLM cite sources?
    │   - Does response match query intent?
    │   - Is confidence high?
    │
    └─> [If quality is low]
        │
        ├─> [Identify failure reason]
        │   - Retrieve missed relevant docs?
        │   - Retrieved wrong docs?
        │   - LLM reasoning error?
        │
        └─> [Refine & Retry]
            - Rewrite query
            - Adjust search parameters
            - Retrieve additional context

テクニック 2: ネガティブ サンプリングとランキング モデルの最適化

関連するドキュメントと無関係なドキュメントを区別するためにランキング モデルをトレーニングします。

  • 良い例: クエリ + 関連ドキュメントのペア (ユーザー フィードバック、クリック ログから)
  • 否定的な例: クエリ + 無関係なドキュメントのペア

これにより、クロスエンコーダーまたはランキングモデルが継続的に改善されます。


8. コンテキスト圧縮と迅速なエンジニアリング

優れた検索が行われたとしても、取得した生のチャンクを LLM に渡すのは非効率的です。高度な圧縮と迅速な設計により、パフォーマンスが最大化されます。

コンテキストの圧縮

取得したドキュメント全体を渡すのではなく、重要な情報に圧縮します。

[Retrieved Documents]
    │
    ▼
[Compression Model]
    (Summarize, extract key facts, remove filler)
    │
    ▼
[Compressed Context: 30% original size, 95% information retained]
    │
    ▼
[Pass to LLM]

利点: プロンプト トークンの削減、推論の高速化、コストの削減。

最適化されたプロンプト テンプレート

LLM 推論を最大限に活用するための構造プロンプト:

You are a knowledgeable assistant. Answer the following question
using ONLY the provided context. If the context doesn't contain
the answer, say "I don't know."

Context:
---
[COMPRESSED RETRIEVED DOCUMENTS]
---

Question: [USER QUERY]

Answer:

明示的な指示を含めます。

  • 「提供されたコンテキストのみを使用する」
  • 「事実については出典を引用する」
  • 「信頼レベルを示す」
  • 「曖昧な点にフラグを立てる」

9. バッチ処理と並列取得

大規模になると、順次取得がボトルネックになります。高度なシステムは取得操作を並列化します。

並列検索の実行

[Query Batch: 1000 queries]
    │
    ├─ [Thread 1] ──> [Vector Search] ──> [Results]
    ├─ [Thread 2] ──> [BM25 Search] ──> [Results]
    ├─ [Thread 3] ──> [Metadata Filter] ──> [Results]
    └─ [Thread 4] ──> [Cross-Encoder Rerank] ──> [Results]
    │
    ▼
[Merge & Deduplicate]
    │
    ▼
[Final Results: 100-1000x faster than sequential]

キャッシュとインデックスの最適化

  • クエリ結果のキャッシュ: 頻繁なクエリ結果を保存します。
  • インデックスの最適化: 正確な最近傍検索の代わりに、HNSW (Hierarchical Navigable Small World) などの近似最近傍 (ANN) アルゴリズムを使用します。
  • インデックスのバッチ更新: ドキュメントの変更を蓄積し、インデックスをバッチ更新します。

10. 埋め込みモデルの選択と微調整

埋め込みモデルはベクトル検索の基礎です。適切なモデルの選択またはトレーニングは、パフォーマンスに劇的な影響を与えます。

埋め込みモデルの比較

モデル 寸法 スピード 品質 使用例
text-embedding-3-small (OpenAI) 512 速い 非常に高い 汎用、バランス型
text-embedding-3-large (OpenAI) 3072 最高 精度が重要なアプリケーション
bge-large-en-v1.5 (BAAI) 1024 速い オープンソース、コスト効率の高い
jina-embeddings-v2 768 速い 多言語、ロングコンテキスト

ドメイン固有の微調整

事前トレーニングされた埋め込みは汎用です。特定のドメインで微調整します。

[Curated Domain Data Pairs]
- (Query, Relevant Document)
- (Query, Irrelevant Document)
    │
    ▼
[Embedding Model Fine-Tuning]
    ├─ Minimize distance: Query ↔ Relevant Docs
    ├─ Maximize distance: Query ↔ Irrelevant Docs
    │
    ▼
[Domain-Specialized Embeddings]

影響: ドメイン固有のタスクの検索精度が 10 ~ 30% 向上しました。


11. 長いコンテキストのクエリとドキュメントの処理

RAG システムは、長いドキュメントや複数の部分からなるクエリに苦戦することがよくあります。高度な技術がこれを適切に処理します。

テクニック 1: スライディング ウィンドウの取得

長い文書の場合は、重複するセグメントを取得します。

[Long Document: 5000 tokens]
    │
    ├─ [Chunk 1: Tokens 0-500] (overlaps with Chunk 2)
    ├─ [Chunk 2: Tokens 400-900] (overlaps with Chunks 1, 3)
    ├─ [Chunk 3: Tokens 800-1300] (overlaps with Chunks 2, 4)
    └─ ...

オーバーラップにより、重要なコンテキストがチャンク境界で失われないようにします。

テクニック 2: マルチインテント クエリのクエリ拡張

複雑なクエリは複数のインテントを表現することがよくあります。それぞれを分解して取得します。

クエリ: 「パフォーマンスと学習曲線を含め、システム プログラミングについて Python と Rust を比較します。」

意図:

  1. システムプログラミングのための Python
  2. システムプログラミングのためのRust
  3. パフォーマンスの比較 (Python vs. Rust)
  4. 学習難易度の比較

インテントごとにドキュメントを取得し、合成します。


12. モニタリングとパフォーマンスのメトリクス

高度な RAG システムでは、パフォーマンスを維持するために厳密な監視が必要です。

主要な指標

メトリック 定義 ターゲット
検索リコール 上位 K 件の結果に含まれる関連ドキュメントの割合 >85%
検索精度 取得された関連ドキュメントの割合 >70%
LLM 応答精度 人間によって正確と評価された回答の割合 >90%
レイテンシ (p99) 99 パーセンタイルの応答時間 <2秒
クエリあたりのコスト 総推論 + 取得コスト <$0.01

可観測性

  • クエリ ログ: 頻繁なクエリと失敗を追跡します。
  • 取得トレース: どのドキュメントが取得、ランク付け、選択されたかを記録します。
  • LLM 出力: 人間による評価とフィードバックのために応答を保存します
  • 埋め込みドリフト: 受信クエリがトレーニング配布から逸脱していないかどうかを監視します

13. 実稼働グレードのアーキテクチャ

高度な検索技術を統合するには、堅牢なアーキテクチャが必要です。

┌─────────────────┐
│  User Interface │
└────────┬────────┘
         │
    ┌────▼─────────────────────┐
    │  Query Router & Parser   │
    │  (Intent Detection)      │
    └────┬────────────┬────────┘
         │            │
    ┌────▼──────┐ ┌───▼─────────┐
    │Query Cache│ │Query Rewriter│
    └────┬──────┘ └───┬─────────┘
         │            │
    ┌────▼──────────────▼───────┐
    │  Hybrid Search Executor   │
    │  ├─ Vector Search (ANN)   │
    │  ├─ BM25 Search           │
    │  └─ Metadata Filter       │
    └────┬──────────────────────┘
         │
    ┌────▼─────────────────────┐
    │ Cross-Encoder Reranker   │
    └────┬─────────────────────┘
         │
    ┌────▼─────────────────────┐
    │  Context Compression     │
    └────┬─────────────────────┘
         │
    ┌────▼──────────────────────┐
    │  LLM Generation Pipeline  │
    │  ├─ Prompt Engineering    │
    │  ├─ LLM Call              │
    │  └─ Post-Processing       │
    └────┬──────────────────────┘
         │
    ┌────▼──────────────────────┐
    │  Response Evaluation      │
    │  & Feedback Collection    │
    └────┬──────────────────────┘
         │
    ┌────▼─────────┐
    │ User Response│
    └──────────────┘

14. よくある落とし穴とその回避方法

落とし穴 1: 取得と生成を分けて評価することを忘れる

多くのチームはエンドツーエンドの精度のみを追跡し、取得パフォーマンスを分離していません。これにより、デバッグが不可能になります。

解決策: 取得段階と生成段階で個別のメトリクスを維持します。

落とし穴 2: レイテンシーに対する過剰な最適化

ミリ秒を節約するために検索品質を手抜きすると、精度が損なわれます。

解決策: 許容可能なレイテンシー SLO (例: p99 < 2s) を確立し、その範囲内で品質を最適化します。

落とし穴 3: 分散外のクエリを処理しない

実稼働クエリはトレーニング クエリとは異なることがよくあります。一般的な埋め込みモデルは、エッジケースでは性能が低下します。

解決策: クエリ分布の埋め込みを微調整します。定期的にモニタリングして再トレーニングしてください。

落とし穴 4: LLM に提供されるコンテキストが不十分

5 つのドキュメントを取得することは、5 つすべてを完全に渡すことを意味するわけではありません。圧縮と選択が重要です。

解決策: コンテキスト圧縮を実装し、LLM が過剰ではなく十分なコンテキストを受信することを検証します。


15. 実際の実装例

以下は、いくつかの手法を組み合わせた簡略化された疑似コードの例です。

def advanced_rag_retrieval(user_query: str) -> List[Document]:
    # 1. Rewrite query
    query_variants = llm_rewrite_query(user_query)
    
    # 2. Hybrid search
    vector_results = vector_search(query_variants, top_k=50)
    bm25_results = bm25_search(query_variants, top_k=50)
    merged_results = merge_and_deduplicate(
        vector_results, bm25_results
    )
    
    # 3. Metadata filtering
    filtered_results = apply_metadata_filters(
        merged_results, 
        date_range="2024-2026",
        doc_type="official_docs"
    )
    
    # 4. Cross-encoder reranking
    reranked_results = cross_encoder_rerank(
        user_query, 
        filtered_results, 
        top_k=10
    )
    
    # 5. Hierarchical context expansion
    expanded_results = expand_with_parent_context(
        reranked_results
    )
    
    # 6. Context compression
    compressed_context = compress_context(
        expanded_results, 
        max_tokens=2000
    )
    
    return compressed_context

## 結論

高性能 RAG システムは、複数の高度な技術を組み合わせています。つまり、再現率を高めるハイブリッド検索、精度を高めるクロスエンコーダ、堅牢性を高めるクエリ書き換え、豊富なコンテキストを実現する階層チャンクです。単一のテクニックが優勢になることはありません。むしろ、それらは相乗的に連携して機能します。

ROI は大きく、基本的な RAG から高度な取得に移行すると、多くの場合、精度が 20 ~ 40% 向上し、待ち時間が 50 ~ 80% 削減され、コストが 30 ~ 50% 削減されます。

ハイブリッド検索とクロスエンコーダーの再ランキングから始めます (最大の効果、中程度の複雑さ)。次に、システムの規模に応じて、クエリの書き換え、コンテキストに応じた圧縮、埋め込みの微調整を重ねていきます。継続的に監視し、改善を厳密に検証し、絶え間なく反復します。

エンタープライズ AI の将来は、言語モデルの改善だけではありません。適切な情報を適切なタイミングで提供する、よりスマートな検索システムが重要です。


Ghaznix ブログで AI に関する詳細をご覧ください →