Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

поиск по статьям справочного центра (RAG)

в этой задаче решается этап поиска: по тексту вопроса пользователя найти статьи справки, которые стоит передать дальше в RAG-пайплайн.

alt text

краткое описание подхода

двухэтапный гибридный пайплайн: на первой стадии кандидаты параллельно извлекаются лексическим (BM25) и векторным (FAISS) поиском, списки объединяются через Reciprocal Rank Fusion (RRF), затем верхушка объединённого пула переранжируется кросс-энкодером. итоговый топ-10 статей на запрос сохраняется в answer.csv.

предобработка данных

тело каждой статьи приходит в HTML. перед индексацией выполняется очистка: блоки <script> и <style> удаляются вместе с содержимым, чтобы их текст не попадал в индекс. оставшаяся разметка конвертируется в Markdown через html2text с сохранением структуры таблиц и списков — заголовки, маркированные и нумерованные списки и строки таблиц остаются отдельными строками, а не склеиваются в один абзац. к телу статьи добавляется заголовок (с повтором), чтобы его слова получали больший вес в term frequency и в эмбеддингах.

технический стек

  • лемматизация: pymorphy3 с мемоизацией через lru_cache — словарь корпуса сильно повторяется, поэтому большинство обращений идёт из кэша;
  • кастомные синонимы и стоп-слова: словарь синонимов (data/synonyms.json) схлопывает доменные синонимы на общий кластерный токен, кастомные стоп-слова (data/stopwords.txt) объединяются со списком NLTK; применяются только в лексической ветке;
  • лексический индекс: BM25Okapi по нормализованным токенам полных статей;
  • векторная база: FAISS (IndexFlatIP) по чанкам статей (окна по 1500 символов с перекрытием 200); эмбеддинги L2-нормализуются, поэтому скалярное произведение равно косинусной близости;
  • би-энкодер: BAAI/bge-m3 — кодирует чанки корпуса и сырой текст запроса;
  • кросс-энкодер: BAAI/bge-reranker-v2-m3 — переранжирует топ-15 объединённого пула по лучшему чанку каждой статьи;
  • гибридное слияние: взвешенный RRF (score = sum(weight / (rrf_k + rank))) по ранжированиям BM25 и векторного поиска;
  • агрегация чанков: выбор стратегии схлопывания скоров чанков в скор статьи — max_p (лучший чанк), avg_p (среднее), sum_p (сумма).

валидация

качество проверялось локально на размеченном датасете calibration.f: пайплайн делает предсказания для каждого калибровочного запроса, после чего считается метрика MAP@10 — та же, по которой оценивается финальное решение. предсказания сохраняются в формате сабмита, поэтому метрика считается на той же структуре данных, что уходит в ответ. фиксированный seed и воспроизводимое сэмплирование позволяют сравнивать значения между итерациями.

подход MAP@10 на calibration.f особенности
baseline 0,5082 гибридный поиск, реранкинг, чанкинг по 1500 символов

анализ ошибок

главная выявленная проблема — асимметрия языка пользователей и базы знаний: пользователи пишут разговорно («посылка не пришла», «кинули на деньги»), а статьи справки — формальным языком («доставка», «безопасная сделка»). из-за расхождения лексики BM25 не находил релевантные статьи, а плотный поиск вытягивал их недостаточно высоко.

решение — нормализация лексической ветки:

  • словарь синонимов: доменные синонимы (товар / заказ / посылка и т. п.) отображаются на один кластерный токен после лемматизации, поэтому BM25 матчит запрос со статьёй по всему кластеру;
  • кастомные стоп-слова: разговорные слова-паразиты запросов (здравствуйте, подскажите, пожалуйста и т. п.) не несут сигнала и выкидываются из токенизации, чтобы не размывать скоринг BM25.

установка

убедитесь, что установлен uv.

uv sync
uv run pre-commit install

запуск

пайплайн полностью автоматизирован и выполняется в main.py: код сам управляет жизненным циклом индексов и стадиями обработки.

export PYTHONUTF8=1  # в Windows cmd: set PYTHONUTF8=1
# запуск решения
uv run main.py

# текстовый отчёт об ошибках на calibration.f
uv run python -m src.analysis

# локальный дашборд phoenix для анализа ошибок
uv run python -m src.launch_dashboard

# текст статьи после этапа обогащения
uv run python -m src.inspect_article <id>

данные

для работы пайплайна необходимы три файла в формате Feather:

  • articles.f — база статей справки: article_id — целочисленный идентификатор статьи; title — заголовок статьи; body — текст статьи в HTML.

  • calibration.f — размеченные запросы для локальной проверки подхода: query_id — идентификатор запроса; query_text — текст вопроса пользователя; ground_truth — правильные article_id, разделённые пробелами.

  • test.f — запросы, для которых нужно подготовить ответ: query_id — идентификатор запроса; query_text — текст вопроса пользователя.

метрика

решения оцениваются по MAP@10: для одного запроса считается AP@10 (чем выше в списке релевантные документы, тем больше их вклад), затем значение усредняется по всем запросам. если для запроса есть несколько правильных статей, учитываются все найденные документы, а не только первый.

примечания

  • при первом старте библиотеки автоматически скачают веса эмбеддера и реранкера с Hugging Face в кэш;
  • пути к данным и параметры пайплайна прописаны в configs/.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages