9.6 KiB
9.6 KiB
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_contentrapidfuzzдля точного match по именам, email, документам и ссылкамpython-dateutilилиdateparserдля нормализации датtenacityдля retry вокруг внешних HTTP запросов
Целевой pipeline индексации
1. Подготовка сообщения
На входе каждое сообщение должно раскладываться на сигналы:
- основной текст сообщения
parts[*].text- тип части:
text,quote,forward sender_idmentionsfile_snippetsmember_eventthread_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 текст
- леммы
- mentions
- имена файлов
- ссылки
- названия документов и сервисов
5. Metadata для Qdrant
В metadata стоит стабильно сохранять:
message_idsparticipantsmentionsthread_snstartendcontains_quotecontains_forwardchat_idchat_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
Практическая схема:
- Выполнить несколько dense prefetch по разным вариантам запроса
- Выполнить несколько sparse prefetch по keyword-heavy запросам
- Добавить filters по датам, mentions, participants, если это явно следует из вопроса
- Объединить результаты через fusion
- Забрать расширенный пул кандидатов для 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