🔍

RAGの検索結果がノイズだらけになる原因——「並べ替え」では解決しない理由

に公開

AIに社内文書を検索させるRAG(検索拡張生成)を使っているが、的外れな結果がまざる。検索ヒット数は十分なのに、LLMが曖昧な回答をする。

「検索結果をスコア順にソートし直せば良いのでは」と思っていた。でもre-rankingは「並べ替え」ではなかった——別のモデルが、検索結果を質問と照らし合わせて評価し直すステップだった。

Anthropic Academy(無料)で学んだ、RAGの検索精度を上げる正しい方法。

re-rankingは「ソートし直す」ではない

RAGパイプラインでre-rankingは「検索結果のスコア順に並べ替えること」だと思っていた。

違った。

re-rankingは、別のモデルが初期検索結果を元のクエリと照合し直すステップ。 初期検索とは別の評価基準で、別のモデルがスコアを付け直す。

ここが重要だ。「並べ替え」ではなく「再評価」。

CC補足: re-rankingの仕組み

RAGパイプラインの全体像:

クエリ → 初期検索(BM25/embedding) → re-ranking → LLMに渡す

各ステップの役割:

  • 初期検索: 速度重視でrecall(網羅性)を優先。候補を広く拾う。50〜100チャンクを返す
  • re-ranking: 精度重視でprecision(適合性)を優先。各チャンクをクエリと照合し直し、上位5〜10件に絞る
  • LLM: 絞り込まれたチャンクをコンテキストとして最終回答を生成

re-rankingに使えるモデル:

  • 専用re-rankerモデル: Cohere Rerank、BGE-rerankerなど。クエリ-ドキュメント対の関連度スコアリングに特化
  • LLMをre-rankerとして使う: Claude自身にチャンクの関連度を評価させる方法もある

トレードオフ: re-rankingはClaudeへの追加API呼び出し(またはre-rankerモデルへの呼び出し)が必要。レイテンシが増加する。だが精度は大幅に向上する。

初期検索とre-rankingは目的が違う

初期検索(BM25やベクトル類似度検索)はrecall重視だ。「関連しそうなものを漏れなく拾う」のが仕事。速度が求められるから、ベクトル空間での距離計算やキーワードマッチングで済ませる。

re-rankingはprecision重視だ。「本当に関連するものだけ残す」のが仕事。速度は犠牲にしてでも、クエリとの意味的な適合度を深く評価する。

初期検索が50チャンク返す。re-rankerが各チャンクをクエリと照合してスコアリングし直し、上位5件だけ残す。別のモデル、別のスコアリング、別の目的。

自分はembedding検索の結果をそのままClaudeに渡していた。ノイズの多い検索結果がそのまま入力になっていた。

CC補足: Claudeをre-rankerとして使う実装パターン

Academyの動画では、Claude自身をre-rankerとして使う実装パターンが紹介されていた。

  1. 初期検索結果をXML構造で整形する
  2. 各チャンクにランダムIDを割り当てる
  3. Claudeに「IDのリストを関連度順に返せ」と指示する
<search_results>
  <chunk id="a7f2">PostgreSQLのインデックス最適化について...</chunk>
  <chunk id="b3c1">MySQLのバックアップ手順...</chunk>
  <chunk id="d9e4">PostgreSQLのクエリ実行計画の読み方...</chunk>
</search_results>

プロンプト例:
「上記の検索結果を、クエリ『PostgreSQLのパフォーマンス改善』との関連度が高い順にIDで並べてください」

ポイント:

  • チャンク全文を返させるのではなく、IDのリストだけを返させる。出力トークンを節約できる
  • prefill + stop sequenceでJSON出力を強制するのが実用的(tool useは過剰)
  • IDをランダムにするのは、位置バイアス(先頭のチャンクを優先する傾向)を防ぐため

embeddingモデルが返すのは「数値のリスト」

embeddingモデルにテキストを渡すと何が返ってくるか。Academyのクイズで問われた。

答えは数値のリスト(ベクトル)。固定長の浮動小数点数の配列だ。

「意味を数値化する」とよく説明されるが、もう少し具体的に言うとこうなる。

テキストを入力すると、たとえば768個や1536個の数値が返ってくる。各数値は-1から+1の範囲だ。これらの数値それぞれが、入力テキストの「ある性質のスコア」を表している。

ただし、各数値が具体的に何を表しているかは不明。「42番目の数値は"幸福度"を表す」のような対応関係はない。モデルが学習の中で自動的に決めた、人間には解釈できない次元だ。

CC補足: embeddingとベクトル検索の基礎

embedding(埋め込み)とは、テキストを固定長の数値ベクトルに変換する処理のこと。

# 概念的なイメージ
"猫が好き" → [0.23, -0.41, 0.87, ..., 0.15]  # 768次元
"犬が好き" → [0.21, -0.39, 0.85, ..., 0.17]  # 768次元
"量子力学" → [-0.55, 0.72, -0.12, ..., 0.63]  # 768次元

意味的に近いテキストは、ベクトル空間で近い位置に配置される。「猫が好き」と「犬が好き」のベクトルは近く、「量子力学」のベクトルは遠い。

類似度の計算方法:

  • コサイン類似度: ベクトルの角度で類似度を測定。最も一般的
  • ドット積: ベクトルの内積。コサイン類似度の簡易版
  • ユークリッド距離: ベクトル間の直線距離

重要: AnthropicはEmbedding生成APIを提供していない。 推奨はVoyage AI(voyage-3モデル)。別アカウント・別APIキーが必要になる。

hybrid検索という選択肢

Academyでは、初期検索にもベストプラクティスがあることが示されていた。

ベクトル検索だけでは不十分なケースがある。固有名詞やコード名など、意味よりもキーワードの完全一致が重要な場面だ。逆に、BM25(キーワード検索)だけでは、同じ意味の別の表現を拾えない。

hybrid検索(ベクトル検索 + BM25の組み合わせ)→ マージ → re-ranking の3段パイプラインが推奨されていた。

クエリ
├─ ベクトル検索 → 候補A群
├─ BM25検索 → 候補B群

マージ(重複除去・統合)

re-ranking

上位N件をLLMに渡す

ベクトル検索が意味的な類似性で拾い、BM25がキーワードの完全一致で拾い、re-rankingが本当に関連するものだけ残す。3段階のフィルタリングだ。

CC補足: RAGパイプラインの品質向上テクニック

Academyの動画で紹介されていた追加テクニック:

Contextual Chunking: チャンクにメタ情報を付与してembeddingの品質を上げる手法。「このチャンクは○○というドキュメントの第3章に含まれ、△△について述べている」といった文脈情報を各チャンクの先頭に付加してからembeddingする。文脈を失ったチャンクは検索精度が落ちるため、これを補う。

チャンクサイズの設計: 小さすぎると文脈が失われ、大きすぎるとノイズが増える。一般的には200〜500トークン程度が推奨されるが、ドメインによって最適値は異なる。

評価方法: RAGパイプラインの品質は最終的に「LLMの回答の質」で評価する。検索のrecall/precisionだけを見ても、回答品質と直結しないことがある。

自分のRAGに足りなかったもの

整理すると、自分のRAGパイプラインに足りなかったのは:

  1. re-rankingステップ: embedding検索の結果をそのまま渡していた。ノイズが多かった
  2. hybrid検索: ベクトル検索だけで、キーワード検索を併用していなかった
  3. チャンク品質の意識: チャンクの分割方法やメタ情報付与を考慮していなかった

動いてはいた。回答は出ていた。だが「なんとなく的外れな回答が多い」原因がここにあった可能性が高い。

re-rankingは追加のAPI呼び出しが発生するため、レイテンシは増える。だがコンテキストウィンドウに無駄なチャンクを詰め込むコスト(トークン課金 + 回答品質の低下)を考えると、re-rankingのコストのほうが安いケースは多い。

まとめ

RAGで知らなかったこと:

  • re-rankingは「並べ替え」ではなく「別のモデルによる再評価」
  • 初期検索はrecall重視、re-rankingはprecision重視。目的が違う
  • embeddingが返すのは数値のリスト。各次元が何を表すかは不明
  • AnthropicはEmbedding APIを提供していない。Voyage AIが推奨
  • hybrid検索 + re-rankingの3段パイプラインが推奨

次回はMCP(Model Context Protocol)について書く。MCP Inspectorという便利ツールと、ListToolsRequestによるツール発見の仕組みを扱う。

第2章「Safety Guards」まで無料公開中。

🛠 Claude Codeの自律運用に使っている安全装置: cc-safe-setup



GitHubで編集を提案

Discussion