Гайд · TNWS AI
Как измерить recall HNSW в Azure AI Search через exhaustive KNN
Точный baseline exhaustive:true, Recall@k, стабильный набор запросов и диагностика trade-off качества и задержки.
Задача и применимость
Актуальный русскоязычный запрос: «как измерить recall HNSW Azure AI Search exhaustive». Официальная документация Microsoft проверена 19 сентября 2026 года. Azure AI Search REST API 2026-04-01; поле проиндексировано HNSW, один корпус и одна модель для сравнения двух поисковых режимов.
Задача здесь — выполнить и проверить конкретную операцию в Azure AI Search. Образцовые значения вроде ru-kb, p1 и policy-2026-01 принадлежат тестовому корпусу, а не обязательным именам в вашем сервисе. У вас должны быть полномочия на указанную операцию; для теста можно использовать административный ключ на доверенном сервере, но в пользовательском браузере нужен защищённый серверный посредник. Сначала снимите baseline по контрольному запросу и набору документов, затем меняйте только одну настройку за раз.
Что подтверждает документация
Опциональный vectorQueries.exhaustive вызывает exhaustive KNN на этапе запроса даже для HNSW-поля. HNSW предназначен для приближённого поиска; отличие списка ID от exact baseline измеримо. Качеством нельзя считать разницу @search.score между различными алгоритмами без проверки самих релевантных источников.
Это не обещание одинакового ранжирования для любого русского корпуса. Результат embedding зависит от deployment, подготовки текста, chunking, обновлений модели и состава индекса. Доступность предварительных функций и ограничения сверяйте с документацией и настройками собственного сервиса; цена и длительность операций здесь намеренно не указаны, потому что они не следуют из поискового ответа. Отделяйте успешный HTTP-запрос от оценки полезности найденного фрагмента.
Пошаговое выполнение
- Подготовьте хотя бы набор независимых русских вопросов и один embedding на вопрос; не изменяйте корпус между двумя запросами.
- Для каждого вопроса получите top-10 с exhaustive:true; сохраните IDs как точный baseline на заданном наборе данных.
- Выполните тот же запрос без exhaustive, сохраняя k, fields, filter и select.
- Посчитайте пересечение top-10 IDs / 10 для каждого вопроса и среднее по набору; отдельно замерьте p95 задержки.
- Если recall низок, изучите параметры HNSW и фильтрацию, а затем повторите тест на новом индексе вместо тюнинга по одному примеру.
После каждого шага сохраняйте версию схемы, идентификатор тестового документа и ответ сервиса. При ошибке сначала установите, на каком слое она возникла: полномочия, схема, несовместимый vector, индексирование или собственно ранжирование. Не обновляйте рабочую схему, если не умеете вернуться к старому индексу. Для тестов доступа всегда предусмотрите документ другого tenant и отрицательный запрос.
Готовый REST-шаблон
POST /indexes/ru-kb/docs/search?api-version=2026-04-01
{"select":"id,title","vectorQueries":[{"kind":"vector",
"vector":"<полный массив embedding>","fields":"contentVector",
"k":10,"exhaustive":true}]}
# В реальном JSON замените строку <...> массивом чисел;
# повторите запрос с exhaustive:false для HNSW baseline.
Подставьте своё имя сервиса в https://<service>.search.windows.net, передайте Content-Type: application/json и авторизацию выбранным поддерживаемым способом. Демонстрационный массив из трёх чисел или строка <embedding массива> — только описание формы; они не являются реальным embedding для поля с 1536 измерениями. Перед отправкой проверьте JSON, размерность и отсутствие ключа в клиентском коде.
Входные данные и ожидаемый результат
Вход: десять размеченных вопросов, по одному vector из 1536 чисел; для вопроса Q1 точный список A,B,C,D,E,F,G,H,I,J, ANN список A,B,C,D,E,F,G,H,X,Y. Ожидаемый Recall@10 этого вопроса по совпадению IDs — 8/10=0,8. Это показатель совпадения с точным kNN, а не доказательство, что сами документы отвечают человеку.
Ожидаемый ID — проверяемая гипотеза на подготовленном тестовом наборе. При другом корпусе и другом embedding нельзя честно обещать конкретный score и порядок результатов. Сохраняйте как входное содержимое, так и текст возвращённого фрагмента: найденный ID без исходного подтверждения не годится для публикации ответа от имени компании.
Разбор и границы применения
Формула по IDs проста, но интерпретировать её надо аккуратно. Exact nearest neighbors могут быть нерелевантны: если embedding-модель не понимает предметную область, высокий технический recall будет соседствовать с плохим пользовательским ответом. Дополните сравнение размеченными релевантными документами и ручной оценкой ответа. Разделяйте три метрики: ANN-vs-exact Recall@10, долю полезных документов по ручной разметке и latency. Две группы запросов — короткие точные артикулы и длинные разговорные вопросы — часто ведут себя по-разному, поэтому среднее без сегментов скрывает проблему. Если включён preFilter, одинаковое значение filter обязательно в обеих ветках, иначе точный поиск станет другой задачей. Не смешивайте score и rerankerScore, когда к запросу добавлен semantic ranker. Для p95 используйте многократные вызовы и одинаковый сервисный регион; единичный замер зависит от кэша и нагрузки. Механизм exhaustive может быть дорогим на большом корпусе, поэтому используйте его как проверку на контролируемой выборке, а не обещание всегда включать в production. Результаты эксперимента храните с датой, API-версией, ревизией индекса и embeddings.
Практический контроль именно этой задачи
Для честного измерения создайте таблицу из question_id, ожидаемых документов, raw query vector и документов exact top-10. При каждом эксперименте прикрепляйте хеш списка индексированных id: незаметное изменение корпуса делает сравнение недействительным. Пересечение множеств топ-10 не учитывает порядок, поэтому дополните его метрикой, чувствительной к позиции первых релевантных источников, если важна первая цитата. Нельзя сравнивать один exact запуск утром с ANN запуском после добавления документов вечером. Запускайте пары запросов чередованием, иначе разная нагрузка и кэш исказят p95. Высокий overlap на коротких одинаковых фразах не означает удовлетворительного поиска с отрицанием, аббревиатурами и длинными инструкциями. Сегментируйте набор по типу вопроса. Если точный baseline неверен с точки зрения эксперта, сначала меняйте модель или формирование фрагментов; увеличение efSearch в HNSW не решит несовместимое смысловое пространство. Сохраняйте как индивидуальные ошибки, так и агрегаты.
Критерии проверки
- Оба режима получают идентичный vector, k=10 и filter.
- Recall@10 рассчитан по IDs для каждого вопроса.
- Ручная релевантность оценивается отдельно от ANN recall.
- p95 сравнивается на одном размере корпуса.
Если хотя бы один критерий провален, не маскируйте проблему красивым ответом генеративной модели: возвращайте человеку найденные документы или явное сообщение о недостаточности данных. Сравнение версий проводите на одних и тех же контрольных вопросах, фиксируя документные ID и дату наблюдения.
Типичные ошибки и что не делать
- Называть совпадение ID оценкой фактической истинности.
- Сравнивать запросы с разными k или фильтрами.
- Измерять только одну latency.
- Постоянно включать exhaustive без проверки нагрузки.
Не обучайте и не оценивайте систему только на запросах, скопированных из заголовков: нужна и перефразировка, и отрицательные тесты. Не называйте близость векторов гарантом правдивости: источник может устареть, противоречить другому документу или оказаться недоступным данному пользователю. При внедрении RAG передавайте генератору текст, ID и разрешённую ссылку на первоисточник, а неподтверждённые утверждения не включайте в итоговый ответ.
FAQ
Что делает exhaustive:true?
Включает точный перебор соседей при данном запросе.
Как считается Recall@10 здесь?
Доля общих IDs ANN и exact списков top-10.
Может ли exact поиск давать нерелевантный ответ?
Да, качество embedding и корпуса нужно проверять отдельно.
Официальные источники
Частые вопросы
Что делает exhaustive:true?
Включает точный перебор соседей при данном запросе.
Как считается Recall@10 здесь?
Доля общих IDs ANN и exact списков top-10.
Может ли exact поиск давать нерелевантный ответ?
Да, качество embedding и корпуса нужно проверять отдельно.
Читайте также
Как фильтровать векторный поиск Azure AI Search по tenant без утечки данных
OData filter и vectorFilterMode preFilter для tenant, негативный тест изоляции и сравнение с postFilter.
Как искать текстом через vectorizer Azure AI Search без передачи массива чисел
Настройка vectorizer и REST kind:text для русских вопросов: связка profile, модели и проверка результатов.
Как настроить semantic ranker Azure AI Search для RAG с k=50
Вторичное семантическое ранжирование, конфигурация текстовых полей, k=50 и проверка citations без генеративных обещаний.
Комментарии
Пока тихо. Скажите первое слово