OSS · Python CLI
rag-retriever-bench
検索の問題は、LLMの問題の顔をしてやってくる。
LLMを疑う前に、まず検索を測りましょう。7つのベクトルデータベースを同一コーパス・同一クエリ・同一メトリクスで実測し、recall・nDCG・レイテンシをLLM判定なしで比較します。
- 最適なベクトルDBを選べる 7 DB・9構成を1つのリーダーボードで比較
- recallを信じられる 完全な正解集合に対するrecall@k・MRR・nDCG
- 無音劣化を捕まえられる self_checkがインデックスの実使用を検証
- レイテンシを把握して出せる 10万件で実測したp50 / p95 / p99
- オープンソース · MIT
- LLM判定なし
- 10万件publicレポート
- 作者: Ken Imoto
3ステップで回る
-
rag-retriever-bench prepareデータセット取得・サンプリング・埋め込み。1回だけ実行、以降はキャッシュ -
rag-retriever-bench run同一クエリで9構成をまとめてベンチマーク -
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万件)
サーバー型バックエンド (ネットワークホップ込み)
| backend | recall@10 | nDCG@10 | p50 (ms) | p95 (ms) |
|---|---|---|---|---|
| pgvector (HNSW) | 0.936 | 0.878 | 4.8 | 6.1 |
| ClickHouse (HNSW) | 0.923 | 0.866 | 43.1 | 51.5 |
| ClickHouse (HNSW, g=128) | 0.921 | 0.866 | 11.5 | 13.1 |
| ClickHouse (brute force) | 0.952 | 0.891 | 65.9 | 86.7 |
| Qdrant (HNSW) | 0.947 | 0.888 | 3.3 | 4.1 |
| Weaviate (HNSW) | 0.929 | 0.873 | 1.8 | 2.1 |
| Milvus (HNSW) | 0.940 | 0.882 | 2.0 | 2.3 |
埋め込み型バックエンド (インプロセス。レイテンシはサーバー型と直接比較不可)
| backend | recall@10 | nDCG@10 | p50 (ms) | p95 (ms) |
|---|---|---|---|---|
| Chroma (HNSW, embedded) | 0.929 | 0.871 | 1.7 | 1.9 |
| LanceDB (IVF_HNSW_SQ, embedded) | 0.811 | 0.777 | 1.8 | 1.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
実際に捕まえたもの
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-bench | RAGAS | DeepEval | |
|---|---|---|---|
| 評価対象 | 検索バックエンドそのもの | パイプラインが返した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アドバイザーです。
関連する開発ツール
- opencut-mcp OpenCut classic を任意の MCP クライアントから操作する MCP サーバー。Playwright がエディタセッションを保持し、12 個のツールでタイムライン・メディアアセット・エクスポートパイプラインを公開。OpenCut classic の fork 向け。
- mcp-scorecard MCPサーバー用のプリフライトチェックCLI。ツールを1つも呼ばずに消費される受動トークン量、ユースケースの絞り込み、セキュリティ、命名衝突の4層でスコアカードを返します。
- 404 Games 404ページに置けるcanvasミニゲーム10本。有名エラーページへのオマージュ集。Vanilla JS・依存ゼロ・テーマ追従。当サイトの404で稼働中。
- historymap YAMLを書くと企業サイト風のプロダクトヒストリー年表を生成。10種類のレイアウトをページ上で切り替え可能。静的・自己完結・iframe埋め込み対応。