中文翻译暂不可用,显示俄语原文。
Настроить query expansion с LLM и BM25
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить query expansion с LLM и BM25
1. Цель задачи
Научиться улучшать recall поиска за счёт генерации синонимов и релевантных терминов к пользовательскому запросу с помощью LLM. Расширенный запрос подаётся в BM25, что позволяет находить документы, не содержащие точных слов исходного запроса. Цель — добиться прироста recall@10 не менее чем на 15% относительно baseline BM25, не ухудшив precision более чем на 5%.
Ключевой результат Рабочий пайплайн query expansion + BM25, измеренный прирост recall на тестовом наборе запросов.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Корпус документов (не менее 1000) | Дамп Wikipedia (первые 1000 статей), собственный набор новостей / инструкций, или любой текстовый датасет |
| Тестовые запросы (20–30 штук) | Случайно сгенерировать из документов (взять заголовки или ключевые фразы) и слегка перефразировать, чтобы слова расходились с текстом |
| Baseline BM25 | Реализовать самостоятельно (или взять Whoosh / Elasticsearch) и прогнать на тестовых запросах |
| LLM для генерации расширений | OpenAI API (GPT-4o) или локальная модель (Mixtral 8x7B, Llama 3 70B) через Ollama / vLLM |
| Разметка релевантности (ground truth) | Для каждого запроса вручную отметить до 10 релевантных документов из корпуса (или автоматически — по точному совпадению слов, но лучше manual) |
Если нет реального инструмента — симулируем:
- Корпус: возьмите 100–200 текстов из проекта
data/rawвашего pet-проекта или датасетms_marco(10 документов на запрос). - Тестовые запросы: используйте 10 вопросов из датасета TREC или Natural Questions.
- LLM: используйте gpt-3.5-turbo (очень дёшево, достаточно 50 запросов). Если нет API — возьмите flan-t5-large через Hugging Face.
- Ground truth: используйте существующие разметки MS MARCO или TREC.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Язык программирования | Python 3.10+ | Весь пайплайн |
| Корпус и поиск | Whoosh или Elasticsearch (on-prem) | BM25 индексация и поиск |
| LLM | OpenAI API / vLLM / Hugging Face Transformers | Генерация синонимов и расширений |
| Измерение метрик | numpy, pandas, scikit-learn | Recall@k, Precision@k, MPR |
| Загрузка данных | datasets (Hugging Face) / requests | Получение корпуса |
| Логирование | logging / wandb | Отслеживание экспериментов |
4. Этапы выполнения
Этап 1: Подготовка корпуса и baseline BM25 (1 час)
Действия
- Скачать корпус из датасета
ms_marco(колонкаpassages) или загрузить свои документы в формате JSONL (каждая строка — {"id": "...", "text": "..."}). - Проиндексировать корпус в Whoosh:
from whoosh.index import create_in from whoosh.fields import Schema, TEXT, ID schema = Schema(id=ID(stored=True), content=TEXT(stored=True)) ix = create_in("indexdir", schema) writer = ix.writer() for doc in corpus: writer.add_document(id=doc['id'], content=doc['text']) writer.commit() - Написать функцию bm25_search(query, k=10), возвращающую список (doc_id, score).
- Подготовить тестовый набор запросов и ground truth:
- Запустить поиск для всех запросов:
results = {} for q in queries: results[q] = [doc_id for doc_id, _ in bm25_search(q, k=10)] - Посчитать baseline recall@10 (
len(set(results[q]) & set(relevant[q])) / len(relevant[q])) и precision@10.
Ожидаемый результат этапа Измеренные baseline метрики (например, recall@10 = 0.45, precision@10 = 0.60). Функции bm25_search и evaluate.
Этап 2: Реализация query expansion через LLM (1.5 часа)
Действия
- Разработать промпт для генерации расширения запроса. Пример:
You are a search query expansion assistant. Given a user query, generate up to 5 alternative formulations, synonyms, or related terms that could help retrieve relevant documents. Output only a comma-separated list, no explanations. Query: {query} - Реализовать функцию expand_query(query, llm_backend):
- Вызвать LLM (через OpenAI API или локально).
- Распарсить ответ (список слов/фраз).
- Склеить исходный запрос и расширения в одну строку (например,
original_query synonym1 synonym2 ...).
- Протестировать на 3–5 запросах вручную: убедиться, что синонимы осмысленные.
- Обработать крайние случаи:
- Если LLM возвращает пустой ответ — использовать только исходный запрос.
- Если ответ слишком длинный (>100 слов) — обрезать до первых 10 токенов.
Ожидаемый результат этапа Функция expand_query, протестированная на выборке. Логи примеров расширений.
Этап 3: Интеграция расширенного запроса с BM25 (30 минут)
Действия
- Создать функцию search_with_expansion(query, k=10):
- Вызвать expand_query(query).
- Вызвать
bm25_search(expanded_query, k=k).
- Запустить её на всех тестовых запросах.
- Посчитать метрики recall@10, precision@10.
Ожидаемый результат этапа Значения метрик после expansion (например, recall@10 = 0.53, precision@10 = 0.55). Сравнение с baseline.
Этап 4: Оптимизация и анализ (1 час)
Действия
- Выяснить, какие запросы выиграли больше всего, а какие проиграли.
- Настроить параметры:
- Количество генерируемых синонимов (попробуйте 3, 7, 10).
- Стратегия объединения:
OR-буст исходных слов, взвешенная сумма. - Фильтрация плохих расширений (n-граммы, stopwords).
- Проверить альтернативный промпт, который просит LLM выделить ключевые понятия, а не синонимы.
- Если precision упал >5% — ввести вес: исходный запрос подаётся с бустом (например,
original^3 synonym1 synonym2), если BM25 поддерживает boosting (Whoosh — нет, Elasticsearch — да). Для Whoosh можно повторять исходные слова несколько раз.
Ожидаемый результат этапа Достигнутый прирост recall ≥15% при падении precision ≤5%. Зафиксированные гиперпараметры.
Этап 5: Документирование и выводы (30 минут)
Действия
- Оформить отчёт: таблица с результатами (baseline vs expanded), примеры успешных и неуспешных запросов.
- Написать краткое описание использованного промпта и настроек.
- Собрать код в единый скрипт
query_expansion.py.
Ожидаемый результат этапа Файл RESULTS.md с метриками, выводами, скриптом.
5. Критерии приемки (Definition of Done)
- Baseline recall@10 и precision@10 зафиксированы.
- Реализована функция
expand_query, вызывающая LLM. - Пайплайн поиска с expansion даёт recall@10 ≥ baseline + 15% (абсолютных процентных пунктов? Лучше относительный прирост: если baseline = 0.45, то target ≥ 0.45*1.15 = 0.5175).
- Precision@10 упал не более чем на 5% (от baseline, например с 0.60 до не ниже 0.57).
- Все тестовые запросы обработаны без ошибок.
- Код и промпт задокументированы в README проекта.
6. Ожидаемый результат
- Основной артефакт Python‑скрипт
query_expansion_pipeline.py, который принимает корпус, индексирует, прогоняет baseline и expansion, выводит метрики. - Дополнительно Файл
RESULTS.mdс таблицей метрик по каждому запросу и общими цифрами. - Пример содержания RESULTS.md
## Результаты query expansion (BM25 + LLM) | Метрика | Baseline | Expanded | Δ | |---------|----------|----------|----| | Recall@10 | 0.45 | 0.53 | +17.8% | | Precision@10 | 0.60 | 0.58 | -3.3% | - Опционально Сравнение разных LLM (GPT-4o vs Mixtral) и разных k.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| LLM генерирует нерелевантные синонимы | Уточнить промпт: «only domain-specific synonyms for {domain}»; добавить few-shot examples; отфильтровать по частотности в корпусе. |
| Увеличение времени ответа из-за вызова LLM | Кешировать результаты расширения для повторяющихся запросов; использовать async вызовы. |
| BM25 не поддерживает boosting отдельных слов (Whoosh) | Повторить несколько раз оригинальные слова в строке запроса. |
| Модель слишком дорогая (OpenAI) | Использовать локальную модель (Mixtral 8x7B, Llama 3 8B) через Ollama; ограничить количество запросов. |
| Precision упал сильно (шумы) | Добавить реранжировку: после BM25 top-100 переранжировать с помощью кросс-энкодера. |
8. Бюджет времени (оценка)
| Этап | Время (часы) |
|---|---|
| 1. Подготовка корпуса и baseline | 1 |
| 2. Реализация query expansion через LLM | 1.5 |
| 3. Интеграция с BM25 | 0.5 |
| 4. Оптимизация и анализ | 1 |
| 5. Документирование | 0.5 |
| Итого | 4.5 |
Примечание: Для первого раза рекомендуется заложить +1 час на отладку LLM запросов и чистку данных.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 17 | BM25 и его варианты |
| 28 | Query expansion (ручные тезаурусы) |
| 44 | Query expansion с LLM (данная задача) |
| 56 | Оценка retrieval: Recall, Precision, MAP |
| 73 | Индексирование текстов (Whoosh / Lucene) |
| 89 | Промпт-инжиниринг для генерации терминов |
| 102 | Реранжировка результатов поиска |
| 115 | Domain adaptation текстовых моделей |
| 134 | Data drift в запросах пользователей |
10. Чек-лист самопроверки
- Я оценил baseline BM25 на тестовых запросах до внедрения расширения.
- Убедился, что LLM даёт осмысленные расширения (визуально проверил 5 примеров).
- Проверил, что итоговый recall@10 действительно ≥ baseline + 15%, а precision упал не более чем на 5%.
- Реализовал обработку ошибок LLM (timeout, пустой ответ).
- Задокументировал все шаги и результаты в едином файле.