Учебный mini-RAG toolkit на Python для экспериментов с retrieval, rerank и RAG-пайплайнами.
Проект собран как практический набор CLI для работы с небольшим RAG-стеком:
- несколько retriever'ов:
vector,bm25,fusion - rerank поверх retrieval
- retrieval evaluation
- answer evaluation
- сравнение retriever'ов
- сравнение end-to-end pipeline
- chunk experiments
- regression gate
Фокус проекта - не на сложной теории, а на воспроизводимых сценариях: построить индекс, прогнать поиск, посчитать метрики и сравнить варианты пайплайна.
Если нужен самый короткий путь через проект, то обычно хватает такого порядка:
- Построить индексы
python -m src.vector_search --docs .\eval\docs\v1_rus --index-out .\eval\vindex_local.pklpython -m src.rag_cli --docs .\eval\docs\v1_rus --index-type bm25 --index-out .\eval\bm25_index_local.pkl
- Прогнать поиск или RAG
python -m src.rag_cli --index-vector .\eval\vindex_v1_rus.pkl --retriever vector --query "payment invoice" --llm extract
- Прогнать retrieval eval
python -m src.eval_cli --index-vector .\eval\vindex_v1_rus.pkl --dataset .\eval\eval_small.jsonl --retriever vector --top-k 5
- Прогнать answer eval
python -m src.eval_answer_cli --index .\eval\bm25_index_v1_rus.pkl --dataset .\eval\eval_answer_small.jsonl --retriever bm25 --llm extract --top-k 5
- Сравнить стратегии
python -m src.compare_retrievers_cli --index-vector .\eval\vindex_v1_rus.pkl --index-bm25 .\eval\bm25_index_v1_rus.pkl --dataset .\eval\eval_small.jsonl --top-k 5python -m src.compare_pipelines_cli --index-vector .\eval\vindex_v1_rus.pkl --index-bm25 .\eval\bm25_index_v1_rus.pkl --dataset .\eval\eval_answer_small.jsonl --top-k 5
- Прогнать chunk experiments
python -m src.chunk_experiments_cli --docs .\eval\docs\v1_rus --dataset .\eval\eval_small.jsonl --top-k 5 --chunking-config "((200, 40), (400, 80), (800, 120))"
- Прогнать regression gate
python -m src.regress_cli --index-bm25 .\eval\bm25_index_v1_rus.pkl --index-vector .\eval\vindex_v1_rus.pkl --dataset .\eval\eval_small.jsonl --retriever fusion --rerank --rerank-top-n 10 --proximity-window 5 --top-k 5 --min-recall 0.7 --min-mrr 0.5.\scripts\check.ps1
- строить vector index и BM25 index
- искать по vector / BM25 / fusion
- включать rerank поверх результатов поиска
- выводить контекст, источники и ответ в
rag_cli - считать retrieval-метрики
recall@kиmrr@k - считать answer-метрики
contains_rateиno_info_accuracy - сравнивать retriever'ы на одном датасете
- сравнивать end-to-end пайплайны на одном датасете ответов
- прогонять эксперименты по разным chunking config
- запускать regression gate через
scripts/check.ps1
src/vector_search.py- vector search, build/load index, CLI для индексации и поискаsrc/bm25_search.py- BM25 index и BM25 searchsrc/rag_cli.py- основной RAG CLI: build mode и search modesrc/eval_cli.py- retrieval evalsrc/eval_answer_cli.py- answer evalsrc/compare_retrievers_cli.py- сравнение retriever'овsrc/compare_pipelines_cli.py- сравнение end-to-end pipelinesrc/chunk_experiments_cli.py- эксперименты по chunking configsrc/regress_cli.py- regression gate по порогам метрикsrc/retrieval_types.py- общие типы и наборы допустимых значений CLIscripts/check.ps1- основной quality gate для репозитория
В репозитории нет requirements.txt, поэтому зависимости ставятся в локальное окружение вручную.
python -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install -U pip
python -m pip install numpy scikit-learn pytest ruff blackОсновная проверка проекта:
.\scripts\check.ps1Что делает scripts/check.ps1:
ruff check --fix .black --check .pytest -q- regression gate через
src.regress_cli
python -m src.vector_search --docs .\eval\docs\v1_rus --index-out .\eval\vindex_local.pklBM25 индекс строится через rag_cli в режиме build:
python -m src.rag_cli --docs .\eval\docs\v1_rus --index-type bm25 --index-out .\eval\bm25_index_local.pklЕсли нужен тот же build flow через один CLI:
python -m src.rag_cli --docs .\eval\docs\v1_rus --index-type vector --index-out .\eval\vindex_local.pklpython -m src.vector_search --index-in .\eval\vindex_v1_rus.pkl --query "payment invoice" --top-k 5python -m src.rag_cli --index-vector .\eval\vindex_v1_rus.pkl --retriever vector --query "payment invoice" --llm extractpython -m src.rag_cli --index-bm25 .\eval\bm25_index_v1_rus.pkl --retriever bm25 --query "payment invoice" --llm extractpython -m src.rag_cli --index-vector .\eval\vindex_v1_rus.pkl --index-bm25 .\eval\bm25_index_v1_rus.pkl --retriever fusion --fusion-method rrf --fusion-top-n 5 --query "payment invoice" --llm extractpython -m src.rag_cli --index-vector .\eval\vindex_v1_rus.pkl --index-bm25 .\eval\bm25_index_v1_rus.pkl --retriever fusion --rerank --rerank-top-n 10 --proximity-window 5 --query "payment invoice" --llm extract--format text|json--output <path>--show-prompt--context-only--inline-citations--use-synonyms--no-stop-words--filter-source ...--filter-ext ...--filter-source-contains ...--for-eval-jsonl-out
eval_cli.py считает retrieval-метрики:
recall@kmrr@k
python -m src.eval_cli --index-vector .\eval\vindex_v1_rus.pkl --dataset .\eval\eval_small.jsonl --retriever vector --top-k 5python -m src.eval_cli --index-bm25 .\eval\bm25_index_v1_rus.pkl --dataset .\eval\eval_small.jsonl --retriever bm25 --top-k 5python -m src.eval_cli --index-vector .\eval\vindex_v1_rus.pkl --index-bm25 .\eval\bm25_index_v1_rus.pkl --dataset .\eval\eval_small.jsonl --retriever fusion --fusion-method rrf --fusion-top-n 5 --top-k 5python -m src.eval_cli --index-vector .\eval\vindex_v1_rus.pkl --index-bm25 .\eval\bm25_index_v1_rus.pkl --dataset .\eval\eval_small.jsonl --retriever fusion --rerank --rerank-top-n 10 --proximity-window 5 --top-k 5Ожидается JSONL, где каждая строка выглядит так:
{"query":"payment invoice","relevant":[{"source":"a.txt","idx":0}]}Правила:
query- непустая строкаrelevant- непустой список объектов- каждый объект в
relevantдолжен содержатьsourceиidx idxдолжен быть неотрицательнымint
eval_answer_cli.py оценивает качество ответа RAG по двум метрикам:
contains_rateno_info_accuracy
python -m src.eval_answer_cli --index .\eval\bm25_index_v1_rus.pkl --dataset .\eval\eval_answer_small.jsonl --retriever bm25 --llm extract --top-k 5Ожидается JSONL, где каждая строка выглядит так:
{"query":"payment invoice","expected_contains":["invoice","payment"],"expected_mode":"answer"}или так:
{"query":"totally unrelated query","expected_contains":[],"expected_mode":"no_info"}Правила:
expected_modeдолжен бытьanswerилиno_infoqueryдолжна быть непустой- для
expected_mode=answerсписокexpected_containsдолжен быть непустым
compare_retrievers_cli.py сравнивает:
vectorbm25rerank_vectorrerank_bm25fusion
Метрики в отчёте:
recall_meanmrr_meann
python -m src.compare_retrievers_cli --index-vector .\eval\vindex_v1_rus.pkl --index-bm25 .\eval\bm25_index_v1_rus.pkl --dataset .\eval\eval_small.jsonl --top-k 5compare_pipelines_cli.py сравнивает end-to-end пайплайны на answer-eval датасете и отдаёт:
vectorbm25rerank_vectorrerank_bm25fusion
Метрики в отчёте:
contains_rateno_info_accuracyn
python -m src.compare_pipelines_cli --index-vector .\eval\vindex_v1_rus.pkl --index-bm25 .\eval\bm25_index_v1_rus.pkl --dataset .\eval\eval_answer_small.jsonl --top-k 5chunk_experiments_cli.py прогоняет BM25 retrieval на нескольких chunking config и возвращает список отчётов.
python -m src.chunk_experiments_cli --docs .\eval\docs\v1_rus --dataset .\eval\eval_small.jsonl --top-k 5 --chunking-config "((200, 40), (400, 80), (800, 120))"Для каждой конфигурации:
chunk_sizeoverlapkretrieverrecall_meanmrr_meann
regress_cli.py проверяет retrieval-метрики на порог:
min-recallmin-mrr
python -m src.regress_cli --index-bm25 .\eval\bm25_index_v1_rus.pkl --index-vector .\eval\vindex_v1_rus.pkl --dataset .\eval\eval_small.jsonl --retriever fusion --rerank --rerank-top-n 10 --proximity-window 5 --top-k 5 --min-recall 0.7 --min-mrr 0.5scripts/check.ps1 запускает regression gate как часть общей проверки репозитория. Это и есть основной quality gate проекта.
- Построить индекс:
python -m src.vector_search --docs ... --index-out ...- или
python -m src.rag_cli --docs ... --index-type bm25 --index-out ...
- Прогнать поиск / RAG:
python -m src.rag_cli --index-vector ... --query ...
- Прогнать retrieval eval:
python -m src.eval_cli --index-vector ... --dataset ...
- Сравнить стратегии:
python -m src.compare_retrievers_cli ...python -m src.compare_pipelines_cli ...
- Прогнать chunk experiments:
python -m src.chunk_experiments_cli ...
- Прогнать regression gate:
python -m src.regress_cli ...- или весь quality gate через
.\scripts\check.ps1
- Это учебный проект, а не production toolkit.
- Метрики зависят от текущих datasets и chunking config.
- Сравнения здесь инженерные: они помогают быстро смотреть на поведение пайплайнов, а не заменяют академический benchmark.
- В репозитории нет отдельного
requirements.txt, поэтому окружение собирается вручную.