Оценка эмбеддингов и поиска для RAG-приложений
Claude и Qwen спорят: 16 вопросов — шум или норма для RAG
В десятой части серии о приложениях на базе облачных LLM автор показывает, как оценивать качество поиска в RAG. Вместо пяти случайных вопросов предлагается размеченный датасет в формате JSON Lines: запросы типов exact, paraphrase и unanswerable, где для каждого указаны ID релевантных чанков. Метрики — recall@k, MRR, nDCG@k и доля отказов — вынесены в отдельный модуль, а небольшой харнесс прогоняет их по BM25-поисковику. Такой подход помогает решить, стоит ли добавлять эмбеддинги OpenAI или Voyage. Автор подчёркивает, что метрики измеряют только поиск, а не верность ответов модели.
В десятой части серии о приложениях на базе облачных LLM разбирается, как оценивать качество поиска в системах Retrieval-Augmented Generation. В девятой части выводы делались по пяти вручную подобранным примерам. Автор называет это началом отладки, но не способом принимать решения: по пяти вопросам нельзя понять, стало ли лучше в целом или исправился один конкретный случай. Поэтому здесь строится размеченный датасет и небольшой оценочный харнесс. Датасет — файл JSON Lines, по одной строке на запрос. У каждого запроса есть id, текст, список ID чанков, которые на него отвечают, и тип. Типов три: exact — вопрос повторяет лексику документа, paraphrase — та же мысль выражена другими словами, unanswerable — ответа в корпусе нет и список релевантных чанков пуст. Автор советует начинать с реальных вопросов: обезличенных обращений в поддержку, логов поиска, истории чатов. Придуманные вопросы склонны копировать слова из документации и завышают качество лексического поиска. Типы нужно тегировать и отчитываться по ним отдельно — так видно, где поисковик слаб. Отдельно включаются вопросы без ответа: система, которая всегда что-то возвращает, подталкивает модель отвечать даже тогда, когда в документах ничего нет. Размечать нужно ID чанков, а не текст, и держать датасет в версионном контроле вместе с документами. Ещё одна рекомендация — отложенная часть набора: если подбирать пороги и промпты на тех же вопросах, что попадают в отчёт, цифры будут описывать настройку, а не систему. Автор оговаривает масштаб: 18 пунктов достаточно для поиска слабых мест, но мало для сравнения двух хороших поисковиков — при 16 отвечаемых вопросах изменение одного запроса сдвигает recall на 6,25 процентного пункта. Затем описываются метрики. Recall@k отвечает на главный для RAG вопрос: попал ли нужный чанк в те k результатов, которые мы отдаём модели. Mean reciprocal rank поощряет постановку правильного чанка на первое место — это важно, когда контекста мало или модель лучше читает начало. nDCG@k учитывает позицию результата с логарифмическим дисконтом. Четвёртая метрика — доля отказов: как часто на неотвечаемый запрос поисковик не вернул ничего выше порога. В коде они собраны в модуле metrics.ts, где отдельно обрабатывается пустой список релевантных чанков, а NaN исключаются при усреднении. Автор подчёркивает: метрики измеряют только поиск и ничего не говорят о верности ответов модели. Харнесс runRetrievalEval.ts прогоняет любой поисковик по датасету: интерфейс требует имя и асинхронный поиск, возвращающий ID и score. Для каждого запроса считаются recall, reciprocal rank, nDCG и признак отказа. В примере харнесс запускался на BM25-поисковике из девятой главы, а векторная часть проверялась вручную сделанными трёхмерными тестовыми векторами. Ключей API в окружении нет, поэтому результаты эмбеддингов не приводятся — есть только код вызовов и объяснение, как читать цифры. Отмечается, что у Anthropic нет своей модели эмбеддингов и документация отсылает к Voyage AI, поэтому в примере есть класс VoyageEmbedder на чистом HTTP без отдельного SDK. Практический смысл: перед тем как платить за эмбеддинги OpenAI или Voyage, гибридное ранжирование и векторный индекс, стоит измерить baseline и понять, что именно даёт прирост.