OSS · CLI em Python
rag-retriever-bench
Problemas de retrieval se disfarçam de problemas de LLM.
Meça seu retriever antes de culpar seu LLM. Sete bancos vetoriais avaliados com o mesmo corpus, as mesmas queries e as mesmas métricas: recall, nDCG e latência, sem juiz LLM.
Ver no GitHub Relatório da execução de 100 mil →
- Escolha o banco vetorial certo 7 bancos, 9 configurações, um placar só
- Confie no seu recall recall@k, MRR e nDCG contra o gabarito completo
- Pegue a degradação silenciosa o self_check confirma o uso real do índice
- Entregue com latência conhecida p50 / p95 / p99 medidos em 100 mil passagens
- Open Source · MIT
- Sem juiz LLM
- Relatório público de 100 mil passagens
- Criado por Ken Imoto
Três passos
-
rag-retriever-bench prepareBaixe o dataset, amostre o corpus e gere os embeddings uma vez (com cache). -
rag-retriever-bench runFaça benchmark das 9 configurações com as mesmas queries. -
results/*.mdCompare o placar: qualidade, latência, ingestão e evidência de self_check por backend.
Para quem é
- Engenheiros de IA escolhem banco vetorial com números medidos em vez de benchmarks de fornecedor
- Desenvolvedores de RAG e busca confirmam que o índice funciona antes de mexer em qualquer prompt
- Times de plataforma de IA padronizam um único benchmark entre os backends que operam
- Pesquisadores de LLM precisam de baselines de retrieval reproduzíveis com gabarito completo
Quando usar
- Antes de mexer em prompts: descarte o retriever primeiro e pare de depurar a camada errada
- Antes de trocar de banco vetorial: decida com seus próprios números medidos em vez de benchmarks de fornecedor
- Antes do deploy em produção: confirme com o self_check que o índice não está sendo ignorado em silêncio
- Quando a busca parece estranha sem nenhum erro: os três casos de degradação silenciosa abaixo são exatamente isso
Instalação
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) Backends de servidor (pgvector, ClickHouse, Qdrant, Weaviate, Milvus) sobem via docker compose; Chroma e LanceDB são embutidos e dispensam serviços.
O que ele mede
- Qualidade de retrieval: recall@k, hit@k, MRR@k, nDCG@k contra julgamentos de relevância anotados por humanos, sem juiz LLM
- Latência de query: p50 / p95 / p99 / média no lado do cliente, com serialização incluída
- Ingestão: segundos de carga em lote e de construção de índice por backend
- 7 backends, 9 configurações: pgvector, ClickHouse (HNSW ×2 + força bruta), Qdrant, Weaviate, Milvus, Chroma, LanceDB
- Um self_check por backend: sonda de EXPLAIN ou de estatísticas do servidor que confirma o uso real do índice ANN
- Parâmetros HNSW alinhados entre backends (m=16, ef_construction=64, ef_search=100): a diferença reflete o motor, e a diferença de tuning fica de fora
- Dataset MIRACL-ja: o corpus amostrado sempre contém todas as passagens positivas, então o recall é medido contra o gabarito completo
Resultados medidos (100 mil passagens)
Backends de servidor (com salto de rede)
| 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 |
Backends embutidos (in-process; latência incomparável com backends de servidor)
| 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 |
A força bruta define o teto de qualidade com recall 0.952; a configuração ANN mais próxima é o Qdrant com 0.947. Nessa escala, os motores HNSW se diferenciam principalmente em latência: Weaviate e Milvus respondem abaixo de 2.5 ms no p95, e o ClickHouse leva de 13 a 52 ms conforme a granularidade do índice.
Quanto uma única escolha move os números
Mesmo corpus, mesmos embeddings, mesmo orçamento de HNSW. Só a decisão abaixo mudou.
Escolha do índice
recall@10 0.811 → 0.947
LanceDB IVF_HNSW_SQ vs Qdrant HNSW: uma diferença de recall de 0.136 sem nenhum erro levantado em nenhum dos lados.
Um parâmetro de índice
p95 51.5 ms → 13.1 ms
ClickHouse HNSW com granularidade de índice 128: a latência cai para um quarto e o recall fica praticamente igual (0.923 → 0.921).
Uso
# smoke run com 10 mil passagens (MIRACL-ja baixa no primeiro uso)
rag-retriever-bench run -c configs/miracl-ja.yaml --corpus-size 10000
# execução completa com 100 mil
rag-retriever-bench run -c configs/miracl-ja.yaml
# só preparação: baixar dataset, amostrar corpus, gerar embeddings
rag-retriever-bench prepare -c configs/miracl-ja.yaml
O que ele pegou
Três das nove configurações tinham um caminho para degradar em silêncio, sem levantar nenhum erro. A sonda self_check pegou as três durante o desenvolvimento:
- ClickHouse HNSW: pular o passo OPTIMIZE FINAL faz as queries caírem quietamente para força bruta. A sonda de EXPLAIN pegou a degradação antes de ela virar um resultado de "ClickHouse é lento".
- Qdrant: com indexing_threshold_kb acima do tamanho do corpus, o índice nunca é construído; a coleção reporta indexed_vectors_count = 0 e as buscas rodam no segmento bruto.
- Milvus: depois de um flush, podia carregar um snapshot desatualizado sem os segmentos selados e devolver resultados parciais sem erro algum.
Todos esses caminhos de degradação produziam números de aparência plausível. Os relatórios saem em results/ como Markdown + JSONL, uma linha por backend com qualidade, latência, ingestão e a evidência de verificação do índice.
Os números são de MIRACL-ja + text-embedding-3-small em um único nó. Backends embutidos e de servidor aparecem em tabelas separadas porque a latência deles é incomparável de forma direta. Meça seus próprios dados antes de decidir.
Por que esta ferramenta existe
A maioria dos times de RAG otimiza prompts antes de verificar a qualidade do retrieval. Quando a resposta sai errada, o modelo leva a culpa e o prompt é reescrito, enquanto o retriever que devolveu as passagens erradas segue sem ser questionado. Este harness existe porque erros de retrieval são confundidos com falhas do LLM o tempo todo. Três das nove configurações acima podiam degradar sem levantar nenhum erro; nada nas respostas apontaria para o índice. Meça o retrieval primeiro.
Ao lado de RAGAS e DeepEval
São camadas complementares. RAGAS e DeepEval pontuam os contexts e as respostas que o seu pipeline devolve; este harness mede o backend de retrieval por baixo, antes de você se comprometer com um.
| rag-retriever-bench | RAGAS | DeepEval | |
|---|---|---|---|
| O que avalia | O próprio backend de retrieval | Contexts e respostas que seu pipeline devolve | Contexts e respostas que seu pipeline devolve |
| Sobe bancos vetoriais reais | ✓ 7 backends via docker compose | — | — |
| Gabarito | Qrels anotados por humanos, sem juiz LLM | Principalmente juiz LLM; há variantes não LLM e por ID | Baseado em juiz LLM |
| Latência e ingestão | ✓ p50 / p95 / p99 + ingestão | — | — |
| CLI | ✓ | ✓ | ✓ |
| Licença | MIT | Apache-2.0 | Apache-2.0 |
O travessão indica ausência de menção nos docs oficiais em julho de 2026: os dois frameworks foram desenhados para pontuar o que o seu pipeline devolve, e essa é a divisão de trabalho esperada. Escolha o backend aqui e pontue seu pipeline com eles.
FAQ
Preciso de uma chave da API da OpenAI?
Só para gerar embeddings (text-embedding-3-small por padrão). Os embeddings ficam em cache como .npy, então reexecuções não chamam a API, e o benchmark em si nunca chama um LLM.
Posso usar modelos de embedding locais, como sentence-transformers ou Ollama?
Na v0.1, não. Os embeddings vêm apenas da API da OpenAI; trocar entre modelos de embedding da OpenAI funciona via config.
Há suporte a BM25 ou busca híbrida?
Ainda não. A v0.1 é só vetorial; o modo híbrido (vetor + full-text) está no roadmap da v0.2.
Posso comparar modelos de embedding com ele?
Isso fica fora do escopo por design: todos os backends recebem embeddings idênticos, então a diferença de score reflete o motor. Para comparar modelos de embedding, MTEB e JMTEB são as ferramentas certas.
Posso rodar o benchmark no meu próprio corpus?
Ainda não. A v0.1 usa MIRACL-ja fixo, em que o corpus amostrado sempre contém todas as passagens positivas, então o recall é medido contra o gabarito completo. Suporte a corpus próprio está no roadmap.
Por que só o retriever? Por que não avaliar o pipeline RAG inteiro?
Porque retrieval e geração quebram de formas diferentes e pedem consertos diferentes. Separar os dois vem se tornando prática aceita na avaliação de RAG: se as passagens certas nunca saem do banco de dados, nenhuma troca de prompt ou de modelo conserta a resposta. Este harness isola essa camada para você saber qual metade depurar.
Por que não usar só o RAGAS?
Use o RAGAS, só que para outra pergunta. O RAGAS pontua os contexts e as respostas que seu pipeline devolve; ele não sobe bancos vetoriais nem mede a latência deles. Este harness trabalha uma camada antes: qual banco e qual índice, verificados contra qrels anotados por humanos e sem juiz LLM.
Por que não o DeepEval?
A mesma divisão de trabalho. O DeepEval testa sua aplicação LLM em estilo de teste unitário, com métricas majoritariamente de juiz LLM, o que ajuda depois que o pipeline existe. Decidir qual banco vetorial deve ficar embaixo dele, com HNSW igualado e p95 medido, é a parte que este harness cobre.
Sobre o autor
Criado por Ken Imoto: mais de 300 artigos técnicos em Zenn, Qiita, Dev.to e neste site, mais de 40 livros em 4 idiomas, mais de 400 mil pageviews em Zenn e Qiita, 4 artigos de pesquisa no Zenodo e criador do LLMO Framework.
Relacionado
As medições deste harness alimentam o rag-db-advisor, um advisor MCP/CLI que responde perguntas sobre stack de RAG a partir da evidência medida.
Ferramentas relacionadas para devs
- opencut-mcp Servidor MCP que controla o OpenCut classic a partir de qualquer cliente MCP. Playwright mantém a sessão do editor; doze ferramentas expõem timeline, assets e pipeline de export. Roda contra um fork do OpenCut classic.
- mcp-scorecard Pre-flight checks for MCP servers: passive token footprint, use-case scoping, security, and name safety. LLM-facing quality scorecard.
- 404 Games Ten single-file canvas mini games for your 404 page, inspired by famous error pages. Vanilla JS, zero dependencies, theme-aware. Live on this site's 404.
- historymap Turn a YAML file into a corporate-style product-history timeline. Ten layouts, switchable right on the page. Static, self-contained, iframe-embeddable.