Вопрос «без НДС» в RAG: почему поиск возвращает «с НДС»
В базе лежат два пункта договора: «стоимость указана с НДС» и «стоимость указана без НДС». Пользователь спрашивает, как оформлять счёт без НДС, а RAG цитирует первый пункт. Поиск нашёл текст на ту же тему и с теми же главными словами, но пропустил короткое «без», которое меняет решение. Если ответ влияет на документ или платёж, такого совпадения темы недостаточно.
Сначала разделите ошибку поиска и ответа
Сохраните полный список кандидатов до генерации. Если пункт «без НДС» в нём есть, но модель выбрала соседний, проверяйте реранжирование и инструкцию по цитированию. Если нужного пункта нет даже среди широкого набора кандидатов, исправлять промпт ответа рано. Возьмите пары запросов, отличающиеся одним словом: «с НДС» и «без НДС», «разрешено» и «запрещено», «можно вернуть» и «нельзя вернуть». Для каждой пары укажите ID правильного пункта. Такая маленькая контрольная выборка сразу показывает, сохраняет ли поиск границу между противоположными правилами.
Убедитесь, что исходные пункты не слиты в один огромный чанк. Если оба условия находятся в одной строке индекса и отдаются модели без локального заголовка, даже точный поиск не сможет указать, какое из них относится к нужному тарифу. Храните область действия правила: тариф, дату действия, тип клиента. Иначе лексически верное «без НДС» может быть найдено для чужого продукта.
Добавьте проверяемый лексический сигнал
Второй канал поиска может учитывать слова и фразы буквально. Для явного поля «тип цены» особенно полезно извлечь структурный признак при индексации: vat_mode=excluded или vat_mode=included. Тогда запрос «без НДС» превращается в фильтр по этому признаку, а векторный поиск выбирает ближайший пункт внутри допустимых строк. Значение поля нельзя угадывать из одного «НДС»; в процессе подготовки надо различить конструкции «с НДС», «без НДС», «НДС не облагается» и более сложные формулировки. Неоднозначные случаи отправляйте на ручную проверку перед индексацией.
Если такой структуры нет, лексический поиск по точной фразе может дать кандидатов рядом с семантическими. В PostgreSQL полнотекстовый поиск поддерживает операторы AND, NOT и фразовый порядок; но язык, стоп-слова и морфология влияют на результат. Для коротких юридических фраз полезно проверить реальную выдачу на ваших формулировках, а не предполагать, что «без» автоматически сохранится как значимое слово в выбранной конфигурации. Простое правило «нашлось слово НДС — значит верно» повторит исходную ошибку.
Если правило извлекается автоматически, проверяйте его на контрастных примерах, прежде чем применять как жёсткий фильтр. «Цена без НДС» и «НДС не включён» могут означать близкое, а «скидка без учёта НДС» описывает другую величину. Отметьте случаи, где vat_mode нельзя вывести из одного предложения без соседнего пункта. Для таких документов сохраняйте статус «не определён» и возвращайте исходный контекст человеку. Ошибка строгого фильтра особенно неприятна: нужный пункт исчезнет из кандидатов и модель даже не получит шанс его прочитать.
Как оценить изменение
Для контрольных пар измеряйте Recall@K по ID нужного пункта и число случаев, когда в первую позицию попал противоположный пункт. После подключения лексического канала или фильтра повторите те же вопросы без изменения генерации. Если нужный пункт появился в кандидатах, но ответ остаётся неправильным, задача переходит к реранкеру и модели. Если новый фильтр обнулил выдачу по некоторым вопросам, проверьте пропуски или ошибки разметки vat_mode. Если строите лексический и векторный каналы с нуля, последовательность настройки есть в разборе гибридного поиска BM25 и векторов.
В платном курсе Vector DB & RAG Developer вы настраиваете поиск с фильтрами, соединяете BM25 и ANN и измеряете Recall@K и nDCG на своих вопросах. Пары «с/без» дают понятный набор для такой проверки: они показывают, улучшает ли гибридный поиск деловой ответ, а не только среднюю похожесть текста. Откройте программу курса, чтобы собрать и оценить весь путь от индекса до RAG-бота с цитатами.
Продолжить на практике
- Vector DB & RAG Developer ↗
Практический курс по векторным базам данных и семантическому поиску. Вы развернёте Qdrant, Weaviate и FAISS, научитесь индексировать миллионы эмбеддингов, строить k-NN-поиск с фильтрами, объединять его с BM-25 и создавать RAG-ботов, которые отвечают на вопросы на основе ваших данных.
