3,583 papers
arXiv:2508.18048 82 25 авг. 2025 г. FREE

HyST: двухэтапная фильтрация через разделение жёстких и мягких критериев

КЛЮЧЕВАЯ СУТЬ
Если LLM вместо итальянского ресторана выдаёт французский (но зато очень уютный!), причина проста: семантический поиск не видит разницу между обязательным и желательным. Эмбеддинг превращает запрос в один вектор, где «кухня=итальянская» и «атмосфера уютная» смешиваются в общую кашу — модель ловит смысловую близость, но теряет приоритеты. HyST разделяет запрос на два этапа: сначала LLM вытаскивает жёсткие требования (бренд, категория, цена) и превращает их в точные фильтры. Потом по отфильтрованным кандидатам идёт семантический поиск — ранжирование по субъективным предпочтениям (атмосфера, стиль, тон). Два инструмента, каждый делает своё — и точность взлетает.
Адаптировать под запрос

TL;DR

HyST — техника поиска, которая разделяет запрос на две части: жёсткие требования (бренд, категория, цена) и мягкие предпочтения (атмосфера, стиль, тон). Сначала LLM извлекает из запроса структурированные ограничения и превращает их в фильтры. Потом по оставшимся кандидатам идёт семантический поиск на основе неструктурированных предпочтений. Это как двухступенчатое сито: грубое отсекает явно не подходящее, тонкое ранжирует по нюансам.

Проблема чисто семантического поиска: если просто превратить всё в текст и искать похожее по смыслу, модель путает обязательное и желательное. Запрос "итальянский ресторан в Нью-Йорке с уютной атмосферой" может вернуть французский ресторан с очень уютной атмосферой — семантически похоже, но нарушено жёсткое требование. Причина: эмбеддинги ловят смысловую близость, но не понимают разницу между "must have" (кухня) и "nice to have" (атмосфера). Линеаризация всех полей в один текст стирает эту границу.

Решение HyST: LLM читает запрос и вытаскивает явные ограничения (категория = итальянская, локация = Нью-Йорк), превращая их в точные фильтры. Эти фильтры отсекают всё, что не подходит по обязательным критериям. По тому, что осталось, модель уже ищет семантически близкое к "уютная атмосфера". Два шага вместо одного — но каждый делает своё дело, и точность взлетает.


🔬

Схема метода

ШАГ 1 (LLM): Извлечь из запроса структурированные ограничения → JSON-фильтры

Вход: "Show me Italian restaurants in NYC with cozy atmosphere under $100"
Выход: {"category": "Italian", "location": "NYC", "price": {"$lt": 100}}

ШАГ 2 (LLM): Убрать из запроса уже зафиксированные ограничения → очищенный семантический запрос

Вход: тот же запрос
Выход: "restaurant with cozy atmosphere"

ШАГ 3 (Vector DB): Применить фильтры → найти семантически близкое среди отфильтрованных

Фильтрация: оставить только Italian + NYC + price < $100
Семантический поиск: ранжировать по "cozy atmosphere"

Все три шага можно сделать в одном промпте для LLM, если векторной БД нет — просто попросить модель сначала отфильтровать, потом ранжировать.


🚀

Пример применения

Задача: Ты консультант по переезду в Казахстан. Клиент написал: "Хочу снять квартиру в Астане в районе Есиль или Сарыарка, 2-3 комнаты, до 300к тенге, желательно с видом на реку и рядом с метро".

Тебе нужно найти подходящие варианты из базы объявлений. В базе есть поля: район, количество комнат, цена, описание (там упоминаются вид, инфраструктура).

Промпт (двухэтапный с явным разделением):

Задача: найти квартиры по запросу клиента.

Запрос клиента: "Хочу снять квартиру в Астане в районе Есиль или Сарыарка, 
2-3 комнаты, до 300к тенге, желательно с видом на реку и рядом с метро"

База объявлений: [здесь вставляешь список объявлений в формате: 
ID, район, комнаты, цена, описание]

Шаг 1: ЖЁСТКАЯ ФИЛЬТРАЦИЯ
Извлеки из запроса обязательные критерии:
- Район: ...
- Количество комнат: ...
- Цена: ...

Отбери только объявления, которые ТОЧНО соответствуют этим критериям.

Шаг 2: РАНЖИРОВАНИЕ ПО ПРЕДПОЧТЕНИЯМ
Из отобранных на шаге 1, ранжируй по мягким предпочтениям:
- вид на реку
- близость к метро

Выдай топ-3 с обоснованием почему именно они.

Результат: Модель сначала выдаст список объявлений после жёсткой фильтрации (все из Есиль/Сарыарка, 2-3 комнаты, до 300к). Потом — топ-3 с пояснениями типа "№12 — есть вид на Есиль, 5 минут до станции метро" или "№8 — рядом с метро, но вида нет". Ты увидишь прозрачную логику: сначала отсечка несоответствующих, потом оценка по предпочтениям.


🧠

Почему это работает

Слабость LLM: Семантический поиск ловит смысловую близость, но не видит разницы между обязательным и желательным. Если в запросе 10 слов, а 2 из них — жёсткие требования (бренд, категория), а 8 — описание атмосферы, эмбеддинг смешает всё в одну кашу. Результат: модель может проигнорировать требование к бренду ради более похожей семантики в описании.

Сильная сторона LLM: Модель отлично извлекает структурированную информацию из текста — может вычленить "цена до 100", "категория = итальянский" и превратить в точные фильтры. И ещё лучше — может ранжировать по субъективным критериям типа "уютный", "с хорошей атмосферой", если кандидаты уже отфильтрованы.

Как HyST использует это: Вместо того чтобы мешать всё вместе, HyST делегирует задачи. LLM парсит запрос → вытаскивает жёсткие критерии → формирует фильтры → отсекает несоответствующее. Только после этого включается семантический поиск, но уже по узкому пулу кандидатов. Два инструмента, каждый делает своё дело — и точность взлетает.

Рычаги управления:

  • Если запрос простой (1-2 критерия) → можно обойтись без второго шага, сразу искать по полному запросу
  • Если поля в данных дублируют структурированную инфу (например, бренд упоминается и в названии, и в описании) → очистка запроса может навредить, лучше оставить полный текст
  • Если данные плохо структурированы → можно попросить LLM сначала структурировать их (извлечь атрибуты), потом уже фильтровать

📋

Шаблон промпта

Задача: найти {что ищем} по запросу.

Запрос: {текст запроса пользователя}

База данных: {список элементов с полями: название, категория, бренд, описание, отзывы}

ШАГ 1: ИЗВЛЕЧЬ ЖЁСТКИЕ КРИТЕРИИ
Из запроса выдели обязательные требования по структурированным полям:
- Категория: ...
- Бренд: ...
- Цена/диапазон: ...
- Другие точные ограничения: ...

ШАГ 2: ОТФИЛЬТРОВАТЬ
Оставь только элементы, которые ПОЛНОСТЬЮ соответствуют критериям из шага 1.

ШАГ 3: РАНЖИРОВАТЬ ПО ПРЕДПОЧТЕНИЯМ
Из оставшихся после фильтрации ранжируй по неструктурированным предпочтениям из запроса 
(описание, атмосфера, стиль, качество и т.д.).

Выдай топ-{N} с обоснованием.

Подставляй:

  • {что ищем} — тип элементов (рестораны, квартиры, товары)
  • {текст запроса} — запрос пользователя как есть
  • {список элементов} — твои данные в любом формате (таблица, JSON, просто список)
  • {N} — сколько результатов нужно

Важно: Если твои данные НЕ имеют чётких полей (нет явной колонки "бренд" или "категория"), попроси LLM сначала структурировать их:

ШАГ 0: СТРУКТУРИРОВАТЬ БАЗУ
Для каждого элемента извлеки:
- Категория: ...
- Бренд: ...
- Ключевые атрибуты: ...

Потом переходи к шагу 1.

⚠️

Ограничения

⚠️ Зависимость от качества данных: Если структурированные поля (категория, бренд) имеют сотни разных значений с пересекающейся семантикой, LLM может ошибиться в маппинге. Например, пользователь пишет "Nike trainers", а в базе есть и "Nike", и "Nike Running", и "Nike Sport" — модель может выбрать не ту категорию.

⚠️ Простые фильтры: Метод показан на простых условиях (равенство, списки). Если нужны сложные условия (диапазоны, вложенные логические выражения, агрегация типа "больше 100 отзывов") — в исследовании не проверяли. Скорее всего сработает, но могут быть косяки в генерации фильтров.

⚠️ Очистка запроса не всегда помогает: Исследователи проверили вариант с удалением структурированных частей из семантического запроса (шаг 2). Оказалось, что иногда полный запрос работает лучше, чем очищенный. Причина: если бренд или категория упоминаются и в названии, и в описании продукта, удаление их из запроса теряет важные сигналы. Поэтому шаг 2 — опциональный, зависит от данных.

⚠️ Семантический поиск остаётся слабым звеном: Большинство ошибок было НЕ в генерации фильтров (LLM справлялась отлично), а в семантическом ранжировании. Если эмбеддинг-модель плохо ловит нюансы (тон, стиль, субъективные качества) — результат будет посредственный, даже при идеальной фильтрации.


🔍

Как исследовали

Взяли STaRK Amazon — датасет с товарами и вопросами пользователей. Изначально он был графовым (связи "также купили", "также смотрели"), но исследователи переделали в табличный формат: оставили 5 полей — название, бренд, категория, описание, отзывы. Из них бренд и категория использовали как структурированные (для фильтров), остальные — как текст для эмбеддингов.

Из датасета вручную отобрали 76 запросов, где нужны и жёсткие критерии, и семантика. Например: "Can you suggest a high-quality fishing line from Sufix that offers good value for money?" (бренд = Sufix — жёсткий фильтр, "quality", "value" — семантика). База сократилась с 1 млн товаров до 3335, чтобы ускорить эксперименты, но сложность сохранили.

Сравнили HyST с классикой: BM25 (лексический поиск), DPR и ColBERTv2 (плотные эмбеддинги), гибриды (BM25 + DPR), и чисто семантический поиск (всё в один текст → эмбеддинг). Метрики: precision@1, @5, @10, recall@20, MRR.

Результат: HyST победил по всем метрикам. Особенно сильно — на precision@5 (+14 пунктов против чисто семантического). Почему? Потому что семантический поиск часто возвращал товары с похожим описанием, но другим брендом — а HyST такое отсекал фильтрами сразу.

Неожиданность: Когда убрали шаг очистки запроса (оставили полный текст для семантики), точность выросла на некоторых метриках. Причина: в названиях и описаниях товаров часто дублируются бренд и категория. Удаляя их из запроса, теряли полезные сигналы для матчинга.

Инсайт для практики: Если твои данные уже содержат структурированную инфу в неструктурированных полях (бренд в названии, категория в описании) — не парься с очисткой запроса, оставь как есть. Фильтры всё равно отработают, а полный контекст поможет семантике.


📋

Оригинал из исследования (промпт для генерации фильтров)

Контекст: Исследователи использовали GPT-4o для генерации метаданных-фильтров. Вот их промпт (упрощённая версия из статьи):

You are an assistant helping to parse user queries into structured filters 
for a product recommendation system.

Given a user query, extract the following structured attributes:
- brand: exact brand name mentioned (if any)
- category: product category mentioned (if any) 
- price range: any price constraints (if mentioned)

Output the result as a JSON object compatible with Pinecone metadata filters.

Use operators:
- "$eq" for exact matches (e.g., brand = "Nike")
- "$in" for list membership (e.g., category in ["Italian", "French"])
- "$lt", "$gt" for numeric comparisons (e.g., price < 100)

If a constraint is not mentioned, omit it from the output.

Example:
Query: "Show me Italian or French restaurants in New York under $100"
Output:
{
 "category": {"$in": ["Italian", "French"]},
 "location": {"$eq": "New York"},
 "price": {"$lt": 100}
}

Now process this query: [USER_QUERY]

Ключевая деталь: Они использовали temperature = 0.3 и top-p = 0.8 для генерации фильтров — это даёт баланс между детерминированностью (нужна для точных фильтров) и гибкостью (если в запросе есть синонимы или неточности).


💡

Адаптации и экстраполяции

📌

💡 Адаптация для поиска вакансий

Вместо товаров — вакансии. Клиент пишет: "Хочу работу Python-разработчиком в Алматы, удалёнка или гибрид, зарплата от 500к тенге, желательно с ДМС и в продуктовой компании".

ШАГ 1: ЖЁСТКИЕ КРИТЕРИИ
- Специализация: Python
- Город: Алматы
- Формат: удалёнка ИЛИ гибрид
- Зарплата: от 500 000 тенге

ШАГ 2: ФИЛЬТРАЦИЯ
[Оставить только вакансии, соответствующие шагу 1]

ШАГ 3: РАНЖИРОВАНИЕ
Среди оставшихся ранжируй по:
- Наличие ДМС (приоритет)
- Тип компании: продуктовая vs аутсорс/аутстаф

Топ-5 вакансий с обоснованием.
📌

🔧 Техника: Прозрачность через промежуточный вывод

Добавь в промпт: "После каждого шага выводи, сколько элементов осталось и почему отсеяли остальные".

ШАГ 1: ФИЛЬТРАЦИЯ
[Применить критерии]
Результат: осталось {N} элементов из {M}.
Отсеяно {M-N} по причинам:
- {X} не подошли по бренду
- {Y} не подошли по категории
- ...

ШАГ 2: РАНЖИРОВАНИЕ
[...]

Эффект: Видишь где теряются кандидаты — можешь скорректировать критерии, если фильтр слишком жёсткий.

⚖️

🔧 Техника: Мягкая vs жёсткая фильтрация

Если критерий допускает гибкость, укажи это явно:

ШАГ 1: ЖЁСТКИЕ (строгое соответствие)
- Бренд: Nike (точное совпадение)

ШАГ 2: МЯГКИЕ (могут быть исключения)
- Цена: предпочтительно до 100$, но можно до 120$ если качество очень высокое

Модель будет учитывать нюансы, а не отсекать всё подряд.


🔗

Ресурсы

Статья: HyST: LLM-Powered Hybrid Retrieval over Semi-Structured Tabular Data

Авторы: Jiyoon Myung, Jihyeon Park, Joohyung Han (PrompTart LAB, MODULABS, Seoul, South Korea)

Конференция: EARL '25 (2nd EARL Workshop on Evaluating and Applying Recommender Systems with LLMs), October 2025

Датасет: STaRK Amazon benchmark (https://arxiv.org/abs/2404.13207)

Векторная БД: Pinecone

Embedding модель: OpenAI text-embedding-3-small


📋 Дайджест исследования

Ключевая суть

Если LLM вместо итальянского ресторана выдаёт французский (но зато очень уютный!), причина проста: семантический поиск не видит разницу между обязательным и желательным. Эмбеддинг превращает запрос в один вектор, где «кухня=итальянская» и «атмосфера уютная» смешиваются в общую кашу — модель ловит смысловую близость, но теряет приоритеты. HyST разделяет запрос на два этапа: сначала LLM вытаскивает жёсткие требования (бренд, категория, цена) и превращает их в точные фильтры. Потом по отфильтрованным кандидатам идёт семантический поиск — ранжирование по субъективным предпочтениям (атмосфера, стиль, тон). Два инструмента, каждый делает своё — и точность взлетает.

Принцип работы

Не мешай всё в один запрос — раздели на фильтрацию и ранжирование. Шаг 1: LLM читает запрос и извлекает структурированные ограничения. Пользователь пишет «итальянский ресторан в Нью-Йорке до $100 с уютной атмосферой» — модель выдаёт фильтры: категория=итальянский, локация=NYC, цена<100. Шаг 2: Применяешь фильтры к базе данных → остаются только кандидаты, которые точно соответствуют обязательным критериям. Шаг 3: По оставшимся кандидатам запускаешь семантический поиск на основе неструктурированной части запроса — «уютная атмосфера». Модель ранжирует по смысловой близости, но уже не может выдать французский ресторан — он отсечён на шаге 1. Как двухступенчатое сито: грубое отсекает явно не подходящее (не та категория, не тот город), тонкое ранжирует по нюансам (атмосфера, стиль, детали).

Почему работает

Слабость чистого семантического поиска: эмбеддинг ловит смысловую близость, но не понимает разницу между «обязательно» и «желательно». Если в запросе 10 слов, а 2 из них жёсткие требования (бренд, цена), а 8 — описание атмосферы, вектор смешает всё в одну кучу. Результат: модель может проигнорировать требование к бренду ради более похожей семантики в описании. Сильная сторона LLM: модель отлично извлекает структурированную информацию из текста — вычленяет «цена до 100», «категория=итальянский» и превращает в точные фильтры. И ещё лучше ранжирует по субъективным критериям типа «уютный», если кандидаты уже отфильтрованы. HyST делегирует задачи: LLM парсит запрос → вытаскивает жёсткие критерии → формирует фильтры. Только после этого включается семантический поиск, но уже по узкому пулу. Каждый инструмент делает своё дело — точность растёт.

Когда применять

Поиск по полуструктурированным данным → когда запрос содержит и точные требования (категория, бренд, цена), и субъективные предпочтения (атмосфера, стиль, тон). Особенно эффективно для задач типа поиска товаров, ресторанов, объявлений о жилье — там, где часть критериев живёт в структурированных полях (бренд, цена), а часть — в описаниях и отзывах. НЕ подходит для данных без чётких полей: если у тебя просто свалка текста без явных категорий и атрибутов, придётся сначала попросить LLM структурировать базу (шаг 0: извлечь категории, бренды, атрибуты из каждого элемента).

Мини-рецепт

1. Извлечь жёсткие критерии: Промпт для LLM — Из запроса "{запрос пользователя}" извлеки обязательные требования по структурированным полям: категория, бренд, цена, локация. Выдай в формате JSON. Модель вернёт что-то вроде {"категория": "итальянский", "локация": "Нью-Йорк", "цена": {"макс": 100}}.

2. Отфильтровать базу: Примени полученные фильтры к твоей базе данных. Если используешь векторную БД (Pinecone, Weaviate) — передай фильтры как metadata constraints. Если просто список в промпте — попроси LLM: Из списка [{элементы}] оставь только те, что соответствуют фильтрам {JSON из шага 1}.

3. Ранжировать по предпочтениям: Очисти запрос от жёстких критериев (опционально) или используй полный. Промпт: Из отфильтрованных кандидатов [{результат шага 2}] ранжируй по неструктурированным предпочтениям из запроса: "{атмосфера, стиль}". Выдай топ-5 с обоснованием.

4. Проверь нужна ли очистка запроса: Если бренд/категория упоминаются и в названии, и в описании продукта — лучше оставить полный запрос на шаге 3. Очистка может потерять важные сигналы.

Примеры

[ПЛОХО] : Найди итальянский ресторан в Нью-Йорке с уютной атмосферой до $100 — отдаёшь весь запрос семантическому поиску. Модель может вернуть французский ресторан с очень уютной атмосферой (семантически похоже на «уютный»), но нарушено требование к кухне.
[ХОРОШО] : Шаг 1: Извлеки из запроса "итальянский ресторан в Нью-Йорке с уютной атмосферой до $100" обязательные критерии: категория, локация, цена. Выдай JSON. Шаг 2: Из базы [{список ресторанов}] оставь только те, что соответствуют фильтрам из шага 1. Шаг 3: Из оставшихся ранжируй по "уютная атмосфера". Топ-3 с обоснованием. — Модель сначала отсечёт всё кроме итальянских ресторанов в NYC до $100. Потом среди них найдёт самые уютные. Прозрачная логика: жёсткие требования выполнены, предпочтения учтены.
Источник: HyST: LLM-Powered Hybrid Retrieval over Semi-Structured Tabular Data
ArXiv ID: 2508.18048 | Сгенерировано: 2026-01-12 01:51

Работа с исследованием

Адаптируйте исследование под ваши задачи или создайте готовый промпт на основе техник из исследования.

0 / 2000
~0.5-2 N-токенов ~10-30с
~0.3-1 N-токенов ~5-15с