Почему self-query RAG ломается на фильтрах из запроса
Типовая поломка self-query rag: пользователь пишет «покажи только активные договоры за последний квартал», система прогоняет фразу через векторный поиск и возвращает семантически близкие документы — но из закрытых сделок прошлых лет. Условие в запросе было, а поиск его не увидел.
Причина в том, что «только активные» и «за последний квартал» — это не смысл, а ограничения по метаданным. Модель эмбеддингов сжимает всю фразу в один вектор, где такие уточнения растворяются среди содержательных слов и почти не влияют на близость. Поиск находит похожее по теме — и игнорирует срез данных.
Self-query RAG меняет схему: языковая модель разбирает запрос на две части. Смысловая уходит в векторный поиск, а условия превращаются в фильтры из запроса — статус, период, тип документа, владелец. Отбор идёт по объединённому правилу, а не только по близости векторов.
Ломается это на стыках: значения метаданных в индексе не совпадают с тем, что извлекает модель — в одном поле соседствуют «активен», «в работе», «действует». Относительные периоды нужно считать от текущей даты, а не подставлять строкой. Если фильтр применяется после отбора ближайших соседей, он схлопывает выдачу до одного-двух документов: условие соблюдено, точность выдачи упала.
Разбираем, как это закрывается: контракт между извлекаемыми полями и схемой индекса, проверка фильтров до отправки в поиск и метрики, которые считают не только релевантность, но и соблюдение условий запроса.
Что даёт автоматическое построение фильтров метаданных
Когда запрос звучит как «условия поставки для розничных клиентов за прошлый квартал», семантический поиск вернёт близкие по смыслу фрагменты, но не отфильтрует их по типу клиента и периоду. Автоматическое построение фильтров закрывает этот разрыв: из формулировки извлекаются значения метаданных — тип документа, подразделение, статус, дата актуальности — и уходят в запрос как жёсткое ограничение до ранжирования.
Первый эффект — автоматическая фильтрация убирает шум. Ограничение ставится до сравнения по смыслу, поэтому в выборку не попадают чужие подразделения и устаревшие редакции, и доля запросов с пустой выдачей падает с двузначных процентов до единиц. «Пусто» чаще приходило не от отсутствия данных, а от того, что нужный фрагмент не проходил по типу или периоду.
Второй — составные условия. Запросы с двумя-тремя ограничениями («акты по подрядчикам за прошлый год, только подписанные») дают больше ложных ответов: часть условий теряется, и модель отвечает по фрагменту из другой категории. Разбор союзов и отрицаний в структуру условий снижает долю таких ошибок в разы — растёт качество ответов, потому что ответ либо опирается на верный срез, либо честно сообщает, что данных нет.
Третий — скорость: предфильтрация сужает выборку на порядок, ранжирование идёт по меньшему числу фрагментов, время ответа сокращается без потери полноты. Фильтры ложатся на нативные механизмы Qdrant — префильтрация до сравнения по векторам.
Размытые условия («свежие», «основные») нельзя молча превращать в жёсткий фильтр: их либо уточняют диапазоном, либо пропускают в семантический поиск — иначе система отсекает данные, которые пользователь считал доступными.
Режимы self-query RAG: сравнение подходов к фильтрации
Self-query RAG отличается от обычного векторного поиска тем, что перед извлечением документов модель разбирает запрос на смысловую часть и набор условий по метаданным: дата, источник, тип документа, подразделение. Насколько свободно она может конструировать эти условия, определяется режим поиска — и от него же зависит точность выдачи и класс отказов, которые потом прилетают в поддержку. Ниже три подхода, между которыми реально выбирают на старте.
| Режим | Когда подходит | Ограничения фильтрации |
|---|---|---|
| Условия строит модель во время запроса | Разнородные данные, много атрибутов, состав запросов заранее неизвестен | Модель может сослаться на несуществующее поле или недопустимое значение; без проверки выдача тихо теряет документы |
| Условия заданы схемой заранее | Узкий стабильный набор атрибутов, жёсткие требования к предсказуемости | Новое поле означает правку схемы и повторные проверки; запросы вида «всё, кроме этого источника» приходится раскладывать вручную |
| Гибридный: модель предлагает, схема проверяет | Нагрузка растёт, число атрибутов увеличивается, цена ошибки высока | Нужен слой проверки и журнал: должно быть видно, какие условия отброшены и почему |
Гибридный режим обычно и становится рабочим: схема фильтров описывает поля, их типы, допустимые значения и диапазоны дат, а валидатор отсекает условия по несуществующим полям и подставляет безопасное значение по умолчанию. Важная деталь — отброшенный фильтр не должен молча превращать ответ в пустую выдачу: расширяем поиск и логируем причину, иначе пользователь видит «ничего не найдено» там, где документы есть.
Внедрение автоматической фильтрации: этапы работ
Автоматическая фильтрация не включается переключателем: модель выводит условия из формулировки, опираясь на описание полей и на то, как спрашивают реальные пользователи. Поэтому работа начинается с аудита поиска и заканчивается регламентом, по которому словарь полей живёт дальше. Ниже — этапы внедрения в том порядке, в котором мы их ведём.
- Аудит поиска. Выгружаем журнал запросов, убираем служебный шум и группируем по намерениям. Смотрим долю запросов с пустой выдачей — сразу видно, каких фильтров не хватает.
- Таксономия полей. Сводим признаки к единым типам: категория, диапазон, дата, наличие, регион. От типа поля зависит, какие условия вообще можно построить.
- Эталонная выборка. Вручную размечаем несколько сотен запросов парами «формулировка → ожидаемый фильтр» — это линейка, с которой сравниваются варианты настройки.
- Настройка фильтров. Описываем схему полей для модели и правила для неоднозначных случаев: где условие не выводится и запрос остаётся обычным текстовым поиском.
- Проверка на конфликтах. Прогоняем отрицания, взаимоисключающие условия и граничные значения — ищем формулировки, где построенный фильтр обнуляет выдачу.
- Тестирование выдачи. Сравниваем до и после на закрытой выборке: доля релевантных первых результатов, доля пустых выдач, поведение на редких формулировках.
- Передача. Отдаём документацию по полям, правила разбора, панель с нетипичными запросами и регламент обновления словаря при изменении каталога.
Артефакты внедрения: схемы, правила, регламенты
Внедрение self-query RAG заканчивается не работающим прототипом, а набором артефактов, с которыми команда заказчика живёт дальше без нас. Схема метаданных и правила допустимых условий определяют, какие фильтры система соберёт из запроса, а какие отклонит ещё до обращения к индексу. Если это не зафиксировано письменно, качество выборки держится на человеке, который помнит конфигурацию в голове.
- Схема метаданных: поля, типы, обязательность и список операторов сравнения, допустимых для каждого поля.
- Словарь значений: нормализованные варианты и синонимы — чтобы разные написания одного значения давали одинаковый фильтр.
- Правила допустимых условий: какие комбинации фильтров разрешены, где стоит запрет на диапазоны по текстовым полям и пустые условия.
- Регламент обновления: кто пересматривает словарь при появлении новых значений, в какой момент правка попадает в релиз и кто её подтверждает.
- Правила доступа: разграничение по ролям на уровне фильтров — ограничение выборки не обходится формулировкой запроса.
- Инструкции для аналитиков: как добавить поле, как проверить, что оно попало в разбор запроса, как откатить изменение.
- Документация и журнал правок: версия схемы, дата и причина изменения, тестовый набор запросов для проверки после каждой правки.
Комплект рассчитан на то, что фильтрацию расширяет сама команда заказчика: новое поле добавляется по инструкции, проверяется на эталонных запросах и уходит в релиз. Доля запросов, где условие отбора построено корректно, перестаёт зависеть от того, кто сегодня на смене.
Кейс: точность ответов на запросах с условиями
Поток запросов был однотипным: пользователи спрашивали с явными условиями — «договоры с оплатой после поставки за прошлый квартал», «вакансии в Минске с релокацией», «тарифы, действующие с начала года». Векторный поиск находил близкие по смыслу фрагменты, но полностью игнорировал жёсткие условия: в ответ попадали документы с другим статусом, городом или периодом. Отсеять их на выходе не получалось — модель уверенно пересказывала нерелевантный источник, и это выглядело убедительнее, чем честное «не нашёл».
Что показали замеры на контрольной выборке
| Метрика | До | После |
|---|---|---|
| Доля корректных ответов | 61% | 89% |
| Доля пустых выдач | 23% | 4% |
| Ответы из неверной категории | 9% | 0,4% |
| Запросы с условиями, ушедшие на уточнение | 31% | 6% |
Что именно изменили
Добавили слой разбора запроса на смысловую часть и структурированные условия: равенство, диапазон дат, вхождение в список. Модель возвращает фильтр по заранее описанной схеме метаданных, слой проверяет его валидность до выполнения поиска и только потом передаёт в индекс — как в подходе Self-Query Retriever из LangChain. Схему метаданных завели декларативно, поэтому новые поля не требуют переписывания кода поиска.
Ушёл целый класс отказов: раньше ответ формально не был пустым, но приходил из неверной категории — теперь такие запросы либо получают корректную выборку, либо уточняющий вопрос вместо догадки. На запросах без условий прирост минимален: разбор фильтров там просто нечего применять, и слой не даёт выигрыша.
Что делать, если индекс уже собран под жёсткие фильтры?
Пересобирать индекс целиком не нужно, если документы уже хранят атрибуты отдельными полями — датой, категорией, регионом, статусом. Задача решается слоем разбора запроса: модель переводит фразу пользователя в структурированный набор условий, а существующие жёсткие фильтры продолжают работать как раньше. Меняется только источник этих условий — их подставляет система, а не человек.
Схема полей становится единственным новым контрактом в системе. Она описывает, какие атрибуты можно вытащить из текста, в каком виде (диапазон, точное совпадение, список значений) и что делать, если атрибут не распознан. Эталонная реализация такого подхода — Self-Query Retriever: поверх жёстких условий ложится смысловой поиск, и оба критерия применяются в одном запросе, а не двумя последовательными проходами.
Миграция фильтров идёт полем за полем, а не одним переключением. Новый путь включается отдельным признаком на части трафика, выдача сравнивается с прежней по пересечению верхних результатов, и если расхождение выше порога — условие уходит в ручной разбор. Метрики простые: доля запросов с автоматически выведенными условиями, доля распознанных полей, доля откатов на прежнюю логику.
Пересборка нужна только там, где атрибута в документах нет или изменился его тип. Тогда включается двойная запись: новые документы попадают в обе структуры, чтение постепенно переводится на новую, а прежняя остаётся доступной для отката, пока метрики не совпадут. Поиск при этом отвечает всё время, пока идёт переключение.
Технические сомнения инженеров и ответы на них
Инженеры спрашивают не про саму идею, а про краевые режимы: что произойдёт, если модель построит условие по полю, которого нет в хранилище, или неверно разберёт разговорную формулировку. Ниже — четыре сомнения, которые всплывают на каждом разборе.
Что будет, если модель придумает поле, которого нет в схеме?
Условие валидируется против декларативного описания метаданных до обращения к хранилищу: неизвестное поле, несовместимый тип значения или недопустимый оператор отбрасываются, и запрос уходит по резервному маршруту — чистым семантическим поиском. Произвольная строка от модели никогда не попадает в слой хранения напрямую. Долю таких срабатываний мы выводим отдельной метрикой — по ней видно, каких полей не хватает в описании.
Как обрабатываются разговорные формулировки?
Модель нормализует бытовые слова в значения из закрытых справочников: «недорогое для поездок» превращается в диапазон по цене и категорию, а не в свободный текст. Для каждого поля задаются допустимые значения и примеры разметки — чем они точнее, тем меньше условий теряется. Нераспознанные части запроса не блокируют поиск: они остаются в семантической ветке и работают как обычный векторный отбор.
Мы расширяем схему метаданных — что придётся переделывать?
Описание полей живёт отдельно от логики поиска, поэтому новое поле — это правка конфигурации, а не переработка кода и не переобучение модели. Добавляем описание, прогоняем эталонный набор запросов на этом поле и смотрим точность построенных условий. Если показатель просел, правим формулировки описания и примеры, а не сам механизм.
Как проверить, что условия построены корректно?
Собираем эталонный набор запросов с заранее известными правильными условиями и сравниваем результат по каждому полю и оператору, а не только по выдаче целиком. Это даёт две отдельные метрики: точность построенных условий и полноту — сколько релевантных записей отсек лишний фильтр. Набор прогоняется в регрессионных проверках перед каждой выкаткой, чтобы правки описания полей не ломали уже работающие сценарии.
Обсудим вашу задачу по фильтрации запросов
Чтобы обсудить задачу по Self-Query RAG, не нужен готовый набор требований — достаточно того, как сейчас устроен поиск по документам. Пришлите примеры реальных запросов, перечень источников и полей, по которым нужна фильтрация, — этого хватает, чтобы увидеть, где ручные фильтры перестают покрывать сценарии.
- примеры запросов, на которых текущий поиск отдаёт нерелевантные документы;
- источники: база знаний, регламенты, карточки товаров, история обращений;
- поля, по которым нужна фильтрация: дата, регион, категория, статус, права доступа;
- роли сотрудников и то, какие срезы данных каждая из них должна видеть;
- ограничения: закрытый контур, свои модели, уже работающая векторная база.
Этого достаточно, чтобы вернуться с оценкой работ и планом внедрения — без общих формулировок:
- схема, как запрос превращается в фильтры и условия поиска;
- перечень атрибутов, которые система начнёт распознавать автоматически;
- этапы: разбор данных, разметка, настройка, проверка на живых запросах;
- состав команды, сроки и точки, где нужно ваше решение;
- критерии приёмки: доля корректно разобранных запросов и точность выдачи.
Опишите задачу в свободной форме — вернёмся с оценкой и планом, которые разбираются по пунктам.







