OSS · CLI en Python

rag-retriever-bench

Los problemas de retrieval se disfrazan de problemas de LLM.

Mide tu retriever antes de culpar a tu LLM. Siete bases vectoriales evaluadas con el mismo corpus, las mismas queries y las mismas métricas: recall, nDCG y latencia, sin juez LLM.

Ver en GitHub Informe de la ejecución de 100 mil →

  • Elige la base vectorial correcta 7 bases, 9 configuraciones, una sola tabla
  • Confía en tu recall recall@k, MRR y nDCG contra la verdad completa
  • Atrapa la degradación silenciosa el self_check confirma el uso real del índice
  • Entrega con latencia conocida p50 / p95 / p99 medidos en 100 mil pasajes
  • Open Source · MIT
  • Sin juez LLM
  • Informe público de 100 mil pasajes
  • Creado por Ken Imoto
Demo en terminal: salida de ayuda de rag-retriever-bench, seguida del informe de una ejecución real con 100 mil pasajes MIRACL-ja comparando 9 configuraciones de backend en recall, nDCG y latencia

Tres pasos

  1. rag-retriever-bench prepare Descarga el dataset, muestrea el corpus y genera los embeddings una vez (con caché).
  2. rag-retriever-bench run Haz benchmark de las 9 configuraciones con las mismas queries.
  3. results/*.md Compara la tabla: calidad, latencia, ingesta y evidencia de self_check por backend.

Para quién es

  • Ingenieros de IA eligen base vectorial con números medidos en lugar de benchmarks de proveedor
  • Desarrolladores de RAG y búsqueda confirman que el índice funciona antes de tocar un solo prompt
  • Equipos de plataforma de IA estandarizan un solo benchmark entre los backends que operan
  • Investigadores de LLM necesitan baselines de retrieval reproducibles con verdad de referencia completa

Cuándo usarlo

  • Antes de tocar los prompts: descarta el retriever primero y deja de depurar la capa equivocada
  • Antes de cambiar de base vectorial: decide con tus propios números medidos en lugar de benchmarks de proveedor
  • Antes del deploy a producción: confirma con el self_check que el índice no se está ignorando en silencio
  • Cuando la búsqueda se siente rara sin ningún error: los tres casos de degradación silenciosa de abajo son exactamente eso

Instalación

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)

Los backends de servidor (pgvector, ClickHouse, Qdrant, Weaviate, Milvus) se levantan con docker compose; Chroma y LanceDB son embebidos y no necesitan servicios.

Qué mide

  • Calidad de retrieval: recall@k, hit@k, MRR@k, nDCG@k contra juicios de relevancia anotados por humanos, sin juez LLM
  • Latencia de query: p50 / p95 / p99 / media del lado del cliente, con serialización incluida
  • Ingesta: segundos de carga masiva y de construcción de índice por backend
  • 7 backends, 9 configuraciones: pgvector, ClickHouse (HNSW ×2 + fuerza bruta), Qdrant, Weaviate, Milvus, Chroma, LanceDB
  • Un self_check por backend: sonda de EXPLAIN o de estadísticas del servidor que confirma el uso real del índice ANN
  • Parámetros HNSW alineados entre backends (m=16, ef_construction=64, ef_search=100): la diferencia refleja el motor, con el tuning fuera de la ecuación
  • Dataset MIRACL-ja: el corpus muestreado siempre contiene todos los pasajes positivos, así que el recall se mide contra la verdad completa

Resultados medidos (100 mil pasajes)

MIRACL-ja, 100 mil pasajes · 860 queries · text-embedding-3-small · top_k=10 · medido el 2026-07-11, nodo único.

Backends de servidor (con salto de red)

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

Backends embebidos (in-process; latencia no comparable con backends de servidor)

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

La fuerza bruta marca el techo de calidad con recall 0.952; la configuración ANN más cercana es Qdrant con 0.947. A esta escala los motores HNSW se diferencian sobre todo en latencia: Weaviate y Milvus responden bajo 2.5 ms en p95, y ClickHouse tarda de 13 a 52 ms según la granularidad del índice.

Cuánto mueve los números una sola elección

Mismo corpus, mismos embeddings, mismo presupuesto de HNSW. Solo cambió la decisión de abajo.

Elección del índice

recall@10 0.811 → 0.947

LanceDB IVF_HNSW_SQ vs Qdrant HNSW: una brecha de recall de 0.136 sin ningún error levantado en ninguno de los dos lados.

Un parámetro del índice

p95 51.5 ms → 13.1 ms

ClickHouse HNSW con granularidad de índice 128: la latencia cae a la cuarta parte y el recall queda casi igual (0.923 → 0.921).

Uso

# smoke run con 10 mil pasajes (MIRACL-ja se descarga en el primer uso)
rag-retriever-bench run -c configs/miracl-ja.yaml --corpus-size 10000

# ejecución completa con 100 mil
rag-retriever-bench run -c configs/miracl-ja.yaml

# solo preparación: descargar dataset, muestrear corpus, generar embeddings
rag-retriever-bench prepare -c configs/miracl-ja.yaml
Captura de pantalla del terminal al final de una ejecución con 100 mil pasajes: dos tablas que listan cada backend con recall@10, nDCG@10, MRR@10, hit@10, latencia p50/p95/p99, segundos de carga y de construcción de índice
La salida de una ejecución terminada: una fila de tabla por backend, del informe real de 100 mil.

Qué atrapó

Tres de las nueve configuraciones tenían una vía para degradar en silencio, sin levantar ningún error. La sonda self_check atrapó las tres durante el desarrollo:

  • ClickHouse HNSW: si se omite el paso OPTIMIZE FINAL, las queries caen en silencio a fuerza bruta. La sonda de EXPLAIN detectó la degradación antes de que apareciera como un resultado de "ClickHouse es lento".
  • Qdrant: con indexing_threshold_kb por encima del tamaño del corpus, el índice nunca se construye; la colección reporta indexed_vectors_count = 0 y las búsquedas corren sobre el segmento crudo.
  • Milvus: después de un flush podía cargar un snapshot obsoleto sin los segmentos sellados y devolver resultados parciales sin error.

Todas esas vías de degradación producían números de apariencia plausible. Los informes salen en results/ como Markdown + JSONL, una fila por backend con calidad, latencia, ingesta y la evidencia de verificación del índice.

Los números son de MIRACL-ja + text-embedding-3-small en un solo nodo. Los backends embebidos y de servidor aparecen en tablas separadas porque su latencia se mide en condiciones distintas. Mide tus propios datos antes de decidir.

Por qué existe esta herramienta

La mayoría de los equipos de RAG optimiza prompts antes de verificar la calidad del retrieval. Cuando la respuesta sale mal, el modelo carga con la culpa y el prompt se reescribe, mientras el retriever que devolvió los pasajes equivocados nunca es cuestionado. Este harness existe porque los errores de retrieval se confunden con fallas del LLM todo el tiempo. Tres de las nueve configuraciones de arriba podían degradar sin levantar ningún error; nada en las respuestas apuntaría al índice. Mide el retrieval primero.

Junto a RAGAS y DeepEval

Son capas complementarias. RAGAS y DeepEval puntúan los contexts y las respuestas que devuelve tu pipeline; este harness mide el backend de retrieval por debajo, antes de que te comprometas con uno.

rag-retriever-benchRAGASDeepEval
Qué evalúa El propio backend de retrieval Contexts y respuestas que devuelve tu pipeline Contexts y respuestas que devuelve tu pipeline
Levanta bases vectoriales reales ✓ 7 backends vía docker compose
Verdad de referencia Qrels anotados por humanos, sin juez LLM Principalmente juez LLM; hay variantes no LLM y por ID Basado en juez LLM
Latencia e ingesta ✓ p50 / p95 / p99 + ingesta
CLI
Licencia MIT Apache-2.0 Apache-2.0

La raya indica que los docs oficiales no lo mencionan a julio de 2026: ambos frameworks están diseñados para puntuar lo que devuelve tu pipeline, y esa es la división de trabajo esperada. Elige el backend aquí y puntúa tu pipeline con ellos.

FAQ

¿Necesito una clave de la API de OpenAI?

Solo para generar embeddings (text-embedding-3-small por defecto). Los embeddings se guardan en caché como .npy, así que las reejecuciones no llaman a la API, y el benchmark en sí nunca llama a un LLM.

¿Puedo usar modelos de embedding locales, como sentence-transformers u Ollama?

En la v0.1, no. Los embeddings vienen solo de la API de OpenAI; cambiar entre modelos de embedding de OpenAI funciona vía config.

¿Soporta BM25 o búsqueda híbrida?

Todavía no. La v0.1 es solo vectorial; el modo híbrido (vector + full-text) está en el roadmap de la v0.2.

¿Puedo comparar modelos de embedding con esta herramienta?

Queda fuera del alcance por diseño: todos los backends reciben embeddings idénticos, así que la diferencia de score refleja el motor. Para comparar modelos de embedding, MTEB y JMTEB son las herramientas adecuadas.

¿Puedo correr el benchmark con mi propio corpus?

Todavía no. La v0.1 fija MIRACL-ja, donde el corpus muestreado siempre contiene todos los pasajes positivos, así que el recall se mide contra la verdad completa. El soporte para corpus propio está en el roadmap.

¿Por qué solo el retriever? ¿Por qué no evaluar el pipeline RAG completo?

Porque retrieval y generación fallan de formas distintas y piden arreglos distintos. Separar los dos se está volviendo práctica aceptada en la evaluación de RAG: si los pasajes correctos nunca salen de la base de datos, ningún cambio de prompt o de modelo arregla la respuesta. Este harness aísla esa capa para que sepas qué mitad depurar.

¿Por qué no usar solo RAGAS?

Usa RAGAS, solo que para otra pregunta. RAGAS puntúa los contexts y las respuestas que devuelve tu pipeline; no levanta bases vectoriales ni mide su latencia. Este harness trabaja una capa antes: qué base y qué índice, verificados contra qrels anotados por humanos y sin juez LLM.

¿Por qué no DeepEval?

La misma división de trabajo. DeepEval testea tu aplicación LLM al estilo de tests unitarios, con métricas mayormente de juez LLM, lo que ayuda cuando el pipeline ya existe. Decidir qué base vectorial debe ir debajo, con HNSW igualado y p95 medido, es la parte que cubre este harness.

Sobre el autor

Creado por Ken Imoto: más de 300 artículos técnicos en Zenn, Qiita, Dev.to y este sitio, más de 40 libros en 4 idiomas, más de 400 mil páginas vistas en Zenn y Qiita, 4 artículos de investigación en Zenodo y creador del LLMO Framework.

Relacionado

Las mediciones de este harness alimentan a rag-db-advisor, un advisor MCP/CLI que responde preguntas sobre stack de RAG a partir de la evidencia medida.

Herramientas relacionadas para devs

Todos los productos →

← Todos los productos