forked from zovos/vk_hackathon
add todo and pipeline
This commit is contained in:
parent
33f8880807
commit
20b401cf01
3 changed files with 255 additions and 0 deletions
0
.codex
Normal file
0
.codex
Normal file
32
doc/todo.md
Normal file
32
doc/todo.md
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
- [ ] P0: Переключить основной query на `question.search_text` с fallback на `question.text`
|
||||||
|
- [ ] P0: Подключить `question.variants` как дополнительные query-варианты
|
||||||
|
- [ ] P0: Подключить `question.hyde` как дополнительные dense-запросы
|
||||||
|
- [ ] P0: Подключить `question.keywords` как основу для sparse-запросов
|
||||||
|
- [ ] P0: Перестать терять retrieval-кандидатов после rerank
|
||||||
|
- [ ] P0: Дедуплицировать `message_ids` перед ответом
|
||||||
|
- [ ] P0: Ограничить финальную выдачу до `top-50`
|
||||||
|
- [ ] P0: Агрегировать score по `message_id`
|
||||||
|
- [ ] P1: Перейти с символьного chunking на chunking по сообщениям
|
||||||
|
- [ ] P1: Учитывать time gap при сборке чанков
|
||||||
|
- [ ] P1: Маркировать в тексте `quote`, `forward`, автора сообщения и автора цитаты
|
||||||
|
- [ ] P1: Развести `page_content`, `dense_content`, `sparse_content`
|
||||||
|
- [ ] P1: Материализовать `sender_id` и `mentions` в индексируемый текст
|
||||||
|
- [ ] P1: Разбирать `file_snippets` и вытаскивать имя файла, mime и url
|
||||||
|
- [ ] P1: Разбирать `member_event` и превращать его в индексируемый текст
|
||||||
|
- [ ] P2: Использовать `entities.people` и `entities.emails` для boost или фильтрации
|
||||||
|
- [ ] P2: Использовать `entities.documents`, `entities.names`, `entities.links` для lexical boost
|
||||||
|
- [ ] P2: Использовать `date_range` для фильтрации по `metadata.start` и `metadata.end`
|
||||||
|
- [ ] P2: Использовать `contains_quote` и `contains_forward` как сигналы ранжирования
|
||||||
|
- [ ] P2: Добавить multi-query fusion в `Qdrant`
|
||||||
|
- [ ] P2: Подобрать `prefetch`, `retrieve_k`, `rerank_limit`
|
||||||
|
- [ ] P3: Привести локальный `docker-compose.yml` к схеме с `API_KEY`
|
||||||
|
- [ ] P3: Добавить `--platform linux/amd64` в сборку образов
|
||||||
|
- [ ] P3: Добавить retry и timeout политику для dense/rerank HTTP вызовов
|
||||||
|
- [ ] P3: Зафиксировать набор локальных тестовых вопросов для проверки регрессий
|
||||||
|
- [ ] P4: Добавить `razdel`
|
||||||
|
- [ ] P4: Добавить `pymorphy3`
|
||||||
|
- [ ] P4: Добавить `rapidfuzz`
|
||||||
|
- [ ] P4: Добавить `python-dateutil` или `dateparser`
|
||||||
|
- [ ] P4: Добавить `tenacity`
|
||||||
223
doc/todo_and_pipeline.md
Normal file
223
doc/todo_and_pipeline.md
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
# 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
|
||||||
Loading…
Reference in a new issue