OSS · Python CLI

rag-retriever-bench

検索の問題は、LLMの問題の顔をしてやってくる。

LLMを疑う前に、まず検索を測りましょう。7つのベクトルデータベースを同一コーパス・同一クエリ・同一メトリクスで実測し、recall・nDCG・レイテンシをLLM判定なしで比較します。

GitHubで見る 10万件実測レポート →

  • 最適なベクトルDBを選べる 7 DB・9構成を1つのリーダーボードで比較
  • recallを信じられる 完全な正解集合に対するrecall@k・MRR・nDCG
  • 無音劣化を捕まえられる self_checkがインデックスの実使用を検証
  • レイテンシを把握して出せる 10万件で実測したp50 / p95 / p99
  • オープンソース · MIT
  • LLM判定なし
  • 10万件publicレポート
  • 作者: Ken Imoto
ターミナルデモ: rag-retriever-benchのヘルプ表示に続き、実際の10万件MIRACL-ja実行レポートで9バックエンド構成のrecall・nDCG・レイテンシを比較

3ステップで回る

  1. rag-retriever-bench prepare データセット取得・サンプリング・埋め込み。1回だけ実行、以降はキャッシュ
  2. rag-retriever-bench run 同一クエリで9構成をまとめてベンチマーク
  3. results/*.md レポートで横並び比較。品質・レイテンシ・取り込み・self_check証跡

誰のためのツールか

  • AIエンジニア ベンダー資料ではなく実測値でベクトルデータベースを選ぶ
  • RAG・検索開発者 プロンプトに手を入れる前にインデックスが本当に効いているか確かめる
  • AIプラットフォームチーム 運用する複数バックエンドを1つのベンチマークで横並び評価する
  • LLM研究者 完全な正解集合つきで再現可能な検索ベースラインを取る

どんな時に使うか

  • プロンプトに手を入れる前に。まずretrieverを除外診断して、違う層をデバッグし続けない
  • ベクトルDBを乗り換える前に。ベンダー資料ではなく自分の実測値で決める
  • 本番デプロイ前に。インデックスが無音でバイパスされていないかself_checkで確認する
  • 「エラーは出ないのに検索が怪しい」とき。下の無音劣化3例がまさにそれ

インストール

git clone https://github.com/kenimo49/rag-retriever-bench
cd rag-retriever-bench
pip install -e ".[all]"

docker compose up -d
cp .env.example .env   # OPENAI_API_KEY (embeddings only)

サーバー型バックエンド(pgvector, ClickHouse, Qdrant, Weaviate, Milvus)はdocker composeで起動。ChromaとLanceDBは埋め込み型なのでサービス不要です。

計測するもの

  • 検索品質: recall@k, hit@k, MRR@k, nDCG@k。人手アノテーションの正解データと突合、LLM判定なし
  • クエリレイテンシ: クライアント側のp50 / p95 / p99 / 平均。シリアライズ込み
  • 取り込み: バックエンドごとのバルクロード秒数とインデックス構築秒数
  • 7バックエンド9構成: pgvector, ClickHouse (HNSW ×2 + brute force), Qdrant, Weaviate, Milvus, Chroma, LanceDB
  • バックエンドごとのself_check: EXPLAINまたはサーバー統計でANNインデックスの実使用を検証
  • HNSWパラメータを全バックエンドで統一(m=16, ef_construction=64, ef_search=100)。差が出たらエンジンの差、チューニングの差ではない
  • MIRACL-jaデータセット: サンプルコーパスが正解パッセージを全部含むので、recallは完全な正解集合に対して測れる

実測結果 (10万件)

MIRACL-ja 10万パッセージ · 860クエリ · text-embedding-3-small · top_k=10 · 2026-07-11計測、シングルノード。

サーバー型バックエンド (ネットワークホップ込み)

backendrecall@10nDCG@10p50 (ms)p95 (ms)
pgvector (HNSW)0.9360.8784.86.1
ClickHouse (HNSW)0.9230.86643.151.5
ClickHouse (HNSW, g=128)0.9210.86611.513.1
ClickHouse (brute force)0.9520.89165.986.7
Qdrant (HNSW)0.9470.8883.34.1
Weaviate (HNSW)0.9290.8731.82.1
Milvus (HNSW)0.9400.8822.02.3

埋め込み型バックエンド (インプロセス。レイテンシはサーバー型と直接比較不可)

backendrecall@10nDCG@10p50 (ms)p95 (ms)
Chroma (HNSW, embedded)0.9290.8711.71.9
LanceDB (IVF_HNSW_SQ, embedded)0.8110.7771.81.9

品質の上限はbrute forceのrecall 0.952。ANN構成で最も近いのはQdrantの0.947です。この規模ではHNSWエンジンの差は主にレイテンシに出ます。WeaviateとMilvusはp95で2.5ms未満、ClickHouseはインデックスgranularity次第で13〜52msかかります。

選択1つで数字はこれだけ動く

同一コーパス・同一埋め込み・同一HNSW条件。変えたのは以下の選択だけです。

インデックスの選択

recall@10 0.811 → 0.947

LanceDB IVF_HNSW_SQとQdrant HNSWの差です。どちらもエラーを一切出さないまま、recallが0.136違います。

インデックスパラメータ1つ

p95 51.5 ms → 13.1 ms

ClickHouse HNSWのindex granularityを128にした場合です。recallはほぼ据え置き(0.923→0.921)のまま、レイテンシが4分の1になります。

使い方

# 1万件のスモークラン (MIRACL-jaは初回に自動ダウンロード)
rag-retriever-bench run -c configs/miracl-ja.yaml --corpus-size 10000

# 10万件のフルラン
rag-retriever-bench run -c configs/miracl-ja.yaml

# 準備のみ: データセット取得・サンプリング・埋め込み
rag-retriever-bench prepare -c configs/miracl-ja.yaml
10万件フルラン完了時のターミナルスクリーンショット: 全バックエンドのrecall@10・nDCG@10・MRR@10・hit@10・p50/p95/p99レイテンシ・ロード秒数・インデックス構築秒数を並べた2つの表
実行後の出力です。実際の10万件レポートから、バックエンドごとに1行のリーダーボードが出ます。

実際に捕まえたもの

9構成のうち3つに「エラーゼロのまま無音で劣化する」経路がありました。self_checkプローブは開発中にその3つ全部を検出しています。

  • ClickHouse HNSW: OPTIMIZE FINALを省くと静かにbrute forceへフォールバック。EXPLAINプローブが「ClickHouseは遅い」という誤った結果になる前に検出
  • Qdrant: indexing_threshold_kbがコーパスサイズより大きいとインデックスが構築されず、indexed_vectors_count = 0のまま生セグメントを検索
  • Milvus: flush後にsealed segmentを欠いたstale snapshotをロードし、エラーなしで部分的な結果を返す

どの劣化経路も、それらしい数値を出してきます。レポートはresults/にMarkdown + JSONLで出力され、バックエンドごとに品質・レイテンシ・取り込み・インデックス使用検証の証跡が1行にまとまります。

数値はMIRACL-ja + text-embedding-3-smallをシングルノードで測ったもの。埋め込み型とサーバー型はレイテンシを直接比較できないため別テーブルで報告されます。最終判断の前に自分のデータで測ってください。

なぜ作ったか

多くのRAGチームは、検索品質を確かめる前にプロンプトの調整を始めます。答えがおかしいとモデルが疑われ、プロンプトが書き直され、間違ったパッセージを返したretrieverは問われないままです。このハーネスを作ったのは、検索の不具合が日常的にLLMの不具合と誤診されるからです。上の9構成のうち3つはエラーゼロのまま劣化しえて、回答だけを見てもインデックスにはたどり着けません。まず検索を測りましょう。

RAGAS・DeepEvalとの位置関係

役割は補完関係です。RAGASとDeepEvalはパイプラインが返したcontextsと回答を採点する層、このハーネスはその下にある検索バックエンド自体を採用前に実測する層です。

rag-retriever-benchRAGASDeepEval
評価対象 検索バックエンドそのもの パイプラインが返したcontextsと回答 パイプラインが返したcontextsと回答
実ベクトルDBの起動と実測 ✓ docker composeで7バックエンド
正解データ 人手アノテーションqrels、LLM判定なし 主にLLM判定。非LLM変種とID突合変種あり LLM判定ベース
レイテンシ・取り込み計測 ✓ p50 / p95 / p99 + 取り込み
CLI
ライセンス MIT Apache-2.0 Apache-2.0

表の「—」は2026年7月時点で公式docsに記載がないことを示します。どちらもパイプラインの返り値を採点する設計で、それ自体が役割分担です。バックエンド選定はこのハーネス、パイプラインの採点はRAGAS/DeepEvalが受け持ちます。

よくある質問

OpenAIのAPIキーは必須ですか?

埋め込み生成にだけ使います(デフォルトはtext-embedding-3-small)。埋め込みは.npyにキャッシュされるので再実行ではAPIを呼ばず、ベンチマーク本体はLLMを一切呼びません。

sentence-transformersやOllamaなどローカル埋め込みモデルは使えますか?

v0.1では使えません。埋め込みはOpenAI APIのみです。OpenAIの別embeddingモデルへの切り替えはconfigでできます。

BM25やhybrid検索には対応していますか?

まだです。v0.1はベクトル検索のみで、hybrid(ベクトル+全文)はv0.2のroadmapに載っています。

embeddingモデルの比較に使えますか?

設計上スコープ外です。全バックエンドに同一の埋め込みを渡すので、スコア差はエンジンの差になります。embeddingモデルの比較にはMTEBやJMTEBが適しています。

自分のコーパスでベンチできますか?

まだです。v0.1はMIRACL-ja固定で、サンプルコーパスが正解パッセージを必ず全部含むため、recallを完全な正解集合に対して測れます。独自コーパス対応はroadmapにあります。

なぜretriever単体?RAGパイプライン全体を評価しないのはなぜ?

検索と生成は壊れ方も直し方も別だからです。RAG評価では両者を分離して測る考え方が広く共有されつつあります。正しいパッセージがデータベースから出てこなければ、どんなプロンプトやモデル差し替えでも回答は直りません。このハーネスはその層を切り出して、どちら半分をデバッグすべきかを分かるようにします。

RAGASではだめなんですか?

RAGASも使ってください。ただし答える問いが違います。RAGASはパイプラインが返したcontextsと回答を採点する道具で、ベクトルDBを起動してレイテンシを測る道具ではありません。このハーネスはその1層手前で働きます。どのデータベース・どのインデックスにするかを、人手アノテーションqrelsとLLM判定なしで決めるための道具です。

DeepEvalではだめなんですか?

役割分担は同じです。DeepEvalは主にLLM判定メトリクスでLLMアプリをユニットテストする道具で、パイプラインができた後に効きます。その下にどのベクトルDBを置くべきかを、HNSW条件を揃えた実測p95つきで決める部分をこのハーネスが受け持ちます。

作者について

作者はKen Imoto。Zenn・Qiita・Dev.to・当サイトで技術記事300本以上、4言語で書籍40冊以上、Zenn・Qiitaで累計40万PV超、Zenodoで研究論文4本を公開し、LLMO Frameworkを設計しています。

関連

このハーネスの実測結果はrag-db-advisorに供給されます。RAGスタックの質問に実測エビデンスで答えるMCP/CLIアドバイザーです。

関連する開発ツール

プロダクト一覧 →

← プロダクト一覧へ