vk_hackathon/doc/todo_and_pipeline.md
2026-04-18 11:19:27 +03:00

9.6 KiB
Raw Permalink Blame History

To-Do и целевой pipeline

Дата: 2026-04-18

Цель

Поднять Recall@50 и nDCG@50 без смены стэка:

  • оставить Qdrant
  • оставить внешний dense endpoint
  • оставить внешний reranker
  • усиливать только индекс, retrieval, rerank и post-processing

Приоритетный to-do

P0. Быстрые и самые окупаемые правки

  • Переключить основной запрос в search на question.search_text с fallback на question.text
  • Подключить question.variants как дополнительные query-формулировки
  • Подключить question.hyde как дополнительные dense-запросы
  • Подключить question.keywords как основу для sparse-запроса
  • Перестать терять кандидатов после rerank: возвращать не только top-10 rerank, но и хвост retrieval
  • Дедуплицировать message_ids перед ответом
  • Ограничить финальную выдачу осмысленным top-50
  • Агрегировать score по message_id, а не просто конкатенировать ids из чанков

P1. Улучшение индексации

  • Перейти с символьного chunking на chunking по сообщениям
  • Учитывать временные разрывы между сообщениями при сборке чанка
  • Не смешивать в одном чанке слишком далекие по смыслу блоки
  • Отдельно маркировать quote, forward, автора сообщения и автора цитаты
  • Развести page_content, dense_content, sparse_content
  • Материализовать mentions в текст и metadata
  • Материализовать sender_id в индексируемый текст
  • Разбирать file_snippets и вытаскивать имя файла, mime, url
  • Разбирать member_event и превращать его в индексируемый текст

P2. Улучшение retrieval и фильтрации

  • Использовать entities.people и entities.emails для boost или фильтрации по participants и mentions
  • Использовать entities.documents, entities.names, entities.links для lexical boost
  • Использовать date_range для фильтрации по metadata.start и metadata.end
  • Использовать contains_quote и contains_forward как дополнительные сигналы ранжирования
  • Добавить multi-query fusion в Qdrant для dense и sparse запросов
  • Подобрать новые значения prefetch, retrieve_k, rerank_limit

P3. Инфраструктура и надежность

  • Привести локальный docker-compose.yml к схеме с API_KEY, чтобы локальный запуск был ближе к ТЗ
  • Добавить --platform linux/amd64 в сборку образов
  • Добавить retry и timeout политику для dense/rerank HTTP вызовов
  • Зафиксировать набор локальных тестовых запросов для регрессии качества

P4. Библиотеки, которые можно добавить без смены стэка

  • razdel для токенизации русского текста
  • pymorphy3 для лемматизации при подготовке sparse_content
  • rapidfuzz для точного match по именам, email, документам и ссылкам
  • python-dateutil или dateparser для нормализации дат
  • tenacity для retry вокруг внешних HTTP запросов

Целевой pipeline индексации

1. Подготовка сообщения

На входе каждое сообщение должно раскладываться на сигналы:

  • основной текст сообщения
  • parts[*].text
  • тип части: text, quote, forward
  • sender_id
  • mentions
  • file_snippets
  • member_event
  • thread_sn
  • флаги is_system, is_quote, is_forward

2. Нормализация и разметка

Перед chunking сообщение стоит приводить к структурированному виду, например:

  • author: ...
  • mentions: ...
  • quote: ...
  • forwarded: ...
  • file: ...
  • system_event: ...

Смысл не в красивом выводе, а в том, чтобы dense и sparse видели роль каждого куска текста.

3. Chunking

Целевой принцип:

  • базовая единица не символ, а сообщение
  • чанк собирается как окно из нескольких соседних сообщений
  • окно режется по лимиту размера
  • окно закрывается на большом time gap
  • forward и длинные quote не должны ломать соседний контекст
  • overlap должен работать по границам сообщений, а не по хвосту строки

4. Формирование трех видов текста

page_content:

  • человекочитаемый текст чанка для payload

dense_content:

  • нормализованный текст с автором, role-маркерами, quote/forward маркерами

sparse_content:

  • keyword-heavy текст
  • леммы
  • email
  • mentions
  • имена файлов
  • ссылки
  • названия документов и сервисов

5. Metadata для Qdrant

В metadata стоит стабильно сохранять:

  • message_ids
  • participants
  • mentions
  • thread_sn
  • start
  • end
  • contains_quote
  • contains_forward
  • chat_id
  • chat_type

Целевой pipeline поиска

1. Подготовка query

Собирать query не из одного поля, а из набора:

  • основной запрос: search_text или text
  • дополнительные dense-query: variants и hyde
  • дополнительные sparse-query: keywords
  • entity-сигналы: people, emails, documents, names, links
  • time constraints: date_range, date_mentions

2. Query builder

Нужно строить несколько представлений запроса:

  • dense-query для смысла
  • sparse-query для точных слов и терминов
  • filter/boost по metadata

3. Retrieval в Qdrant

Практическая схема:

  1. Выполнить несколько dense prefetch по разным вариантам запроса
  2. Выполнить несколько sparse prefetch по keyword-heavy запросам
  3. Добавить filters по датам, mentions, participants, если это явно следует из вопроса
  4. Объединить результаты через fusion
  5. Забрать расширенный пул кандидатов для rerank

4. Rerank

Rerank должен работать не на слишком маленьком пуле. Целевой принцип:

  • retrieval дает расширенный пул
  • rerank сортирует top-N кандидатов
  • хвост retrieval не теряется полностью

5. Агрегация к message_id

После rerank:

  • собрать message_ids из чанков
  • удалить дубликаты
  • агрегировать лучший score на сообщение
  • собрать финальный top-50

Это особенно важно, потому что метрики в ТЗ считаются именно по message_id, а не по chunk id.

Порядок внедрения

Этап 1. Quick wins

  • использовать search_text, variants, hyde, keywords
  • перестать терять кандидатов после rerank
  • добавить dedup и top-50

Этап 2. Пересборка индекса

  • новый renderer сообщения
  • новый chunking по сообщениям
  • разные page_content, dense_content, sparse_content

Этап 3. Metadata-aware retrieval

  • filters по дате
  • boost по mentions/participants
  • учет contains_quote и contains_forward

Этап 4. Тюнинг

  • подобрать размеры чанков
  • подобрать retrieve_k
  • подобрать rerank_limit
  • прогнать локальный набор контрольных вопросов

Минимальный критерий готовности

Можно считать, что pipeline собран в рабочем виде, если:

  • search использует не только question.text
  • индексация не режет чанки посреди сообщения как основной механизм
  • message_ids дедуплицируются
  • финальная выдача ограничивается top-50
  • retrieval умеет использовать хотя бы часть metadata
  • локальная сборка и запуск не расходятся с ТЗ по критичным env и platform