# llamaindex: RAG по своим документам с проверкой качества ответов

Source: https://provod.ai/ru/blog/api150-a077-llamaindex

Если система выдаёт ответ по внутренним документам, но не показывает, какой именно фрагмент она нашла, ты не можешь понять, где она ошиблась: в поиске или в формулировке. Это две разные поломки, и лечатся они по-разному. Пока путь от вопроса к фрагменту не виден, любая оценка качества сводится к «звучит убедительно», а убедительность - плохой контролёр для базы знаний, на которой команда принимает решения.

Отсюда рабочий тезис, который стоит принять до всякого кода: если ответ не опирается на нужный фрагмент, RAG проверку не прошёл, каким бы гладким этот ответ ни был. Вся проверка ниже собрана вокруг одной таблицы «вопрос - найденный фрагмент - ответ - оценка», и строится она на малом, заранее зафиксированном корпусе - не на всей базе сразу.

[Подключите модели для проверки контента с оплатой в рублях на provod.ai](https://provod.ai/?ref=blog-cta-top&utm_source=provod-blog&utm_medium=article&utm_campaign=api150-a077-llamaindex)

## Почему без найденного фрагмента нельзя понять, где ошибка?

По умолчанию считается, что хорошо сформулированный ответ доказывает работу RAG. Удобное заблуждение: генеративная модель пишет связно и поверх нерелевантного контекста. Документация LlamaIndex прямо разделяет качество RAG на две независимо проверяемые оси: оценка retrieval («релевантны ли найденные источники запросу?») и оценка ответа («соответствует ли ответ найденному контексту и самому запросу?»). Система может пройти одну ось и провалить другую (S2).

Из этого разделения следует практическое: пока ты не зафиксировал, какой фрагмент был подан модели, ты смешиваешь два риска в один симптом. Ответ неверен - но это ретривер принёс не тот кусок или генератор проигнорировал правильный? Без найденного фрагмента этот вопрос неразрешим, и ты чинишь наугад.

Это разделение стоит держать в голове и когда выбираешь модельный маршрут: первая ось меряется вообще без модели, а на вторую приходятся и генератор, и LLM-судьи, о которых ниже. [provod.ai (российский аналог OpenRouter)](https://provod.ai/?utm_source=provod-blog&utm_medium=article&utm_campaign=api150-a077-llamaindex&utm_content=hook&utm_id=brief-a077) даёт единый OpenAI-совместимый API, который встаёт под коннекторы LlamaIndex сменой ключа и base\_url, - но retrieval он за тебя не оценивает.

## Как разложить качество RAG на две проверки?

Первую ось - «нашёл ли ретривер нужное» - в `llamaindex` закрывает `RetrieverEvaluator`. Он оценивает ретривер изолированно, до всякой генерации, стандартными IR-метриками: hit rate, MRR, precision, recall, average precision и NDCG. Механика простая: для каждого запроса сравниваются ID узлов, которые ретривер реально вернул, с заранее заданным набором ожидаемых релевантных ID (S3).

Вторую ось - «опирается ли ответ на контекст» - закрывает `FaithfulnessEvaluator`. Он проверяет, обоснован ли сгенерированный ответ найденными контекстами (проверка на галлюцинацию), и работает только со строкой ответа и пассажами контекста - эталонный правильный ответ ему не нужен. Его `EvaluationResult` возвращает явные `passing` (bool), `score`, `feedback` и сами `contexts`, так что пройдено/не пройдено по каждому ответу привязывается к конкретному тексту источника (S5).

Рядом стоит `RelevancyEvaluator`. Ему нужен исходный запрос вместе с ответом, эталон не требуется, и он проверяет, что и найденный контекст, и ответ релевантны и согласованы именно с этим запросом. Важная деталь: его можно запускать по отдельным исходным узлам, а не только по полному ответу, - так изолируешь, какой единственный найденный чанк поддерживает ответ, а какой нет (S1).

Эти три оценщика - сами LLM-судьи, а не детерминированные проверки. Их `passing` и `score` отражают суждение модели о заземлённости ответа. Поэтому они сужают поле для ручной сверки, но не отменяют её.

![Матрица примитивов оценки LlamaIndex: какие требуют эталонного ответа, а какие нет](https://storage.yandexcloud.net/provod-yc-production-cms-media/provod-yc-production-cms-media/blog/02-174.png)

## Контрольный корпус и вопросы с известным фрагментом

Начинай с малого и разрешённого. Возьми корпус, который тебе легально можно использовать, и зафиксируй его до прогона: сравнивать результаты имеет смысл только на неподвижной базе. В модели данных LlamaIndex `Document` - это исходная единица, которую при индексировании режут на объекты `Node` (чанки), а метаданные документа (имя файла, идентификатор источника) автоматически распространяются на каждый производный `Node` (S6). Именно это позже позволит при ручной сверке проследить найденный чанк до его исходного документа.

Дальше нужны вопросы с известным ожидаемым фрагментом. Здесь помогает `generate_question_context_pairs`: он синтезирует датасет `EmbeddingQAFinetuneDataset` прямо из фиксированного корпуса узлов - строит ID запросов, сопоставленные со сгенерированными вопросами, и указывает конкретный релевантный чанк (или чанки), который каждый вопрос должен вернуть (S3). Получается переиспользуемая связка «вопрос -> ожидаемый фрагмент» над ограниченным разрешённым корпусом.

У этого удобства есть честная граница. `generate_question_context_pairs` и `RetrieverEvaluator` работают с ID узлов из того же проиндексированного корпуса, на котором построен датасет. То есть измеряется, способен ли тот же ретривер заново найти чанки, которые ему объявили релевантными, а не реальная релевантность в оценке независимого человека. Синтетический датасет - это заготовка, но критичные вопросы всё равно пишет человек, знающий предметную область.

    from llama\_index.core.evaluation import ( RetrieverEvaluator, generate\_question\_context\_pairs, )
    
    qa\_dataset = generate\_question\_context\_pairs( nodes, llm=llm, num\_questions\_per\_chunk=2 )
    
    retriever\_evaluator = RetrieverEvaluator.from\_metric\_names( ["hit\_rate", "mrr"], retriever=retriever ) result = retriever\_evaluator.evaluate( query="Каков срок ответа на претензию по договору?", expected\_ids=["node\_id\_17"], )

## Как связать вопрос, фрагмент и ответ в одной строке?

Чтобы каждый ответ разбирался механически, а не на глаз, включи цитирование. `CitationQueryEngine` подвешивает к ответу нумерованные инлайн-цитаты вида `[1]`, `[2]`, и каждый номер индексирует непосредственно в массив `source_nodes` объекта ответа. Любое утверждение в ответе прослеживается назад до точного найденного фрагмента, который его породил. Гранулярность цитируемых чанков настраивается через `citation_chunk_size` (по умолчанию 512 символов) (S4).

Это и есть техническая основа таблицы «вопрос - найденный фрагмент - ответ - оценка». Цитата даёт тебе фрагмент, `source_nodes` вместе с проброшенными метаданными - его источник, а два оценщика - предварительный вердикт по каждой оси. Дальше человек ставит финальную отметку.

    from llama\_index.core.query\_engine import CitationQueryEngine from llama\_index.core.evaluation import ( FaithfulnessEvaluator, RelevancyEvaluator, )
    
    query\_engine = CitationQueryEngine.from\_args(index, citation\_chunk\_size=512) resp = query\_engine.query("Каков срок ответа на претензию по договору?")
    
    faith = FaithfulnessEvaluator() rel = RelevancyEvaluator()
    
    print(faith.evaluate\_response(response=resp).passing)   # заземлён ли ответ print(rel.evaluate\_response(query="...", response=resp).passing)  # релевантен ли for node in resp.source\_nodes:                           # [1], [2] -> точный фрагмент print(node.metadata.get("file\_name"), node.node\_id)

Для набора заранее заданных критичных вопросов, у которых есть известный правильный ответ, подключается `CorrectnessEvaluator` - единственный оценщик в наборе LlamaIndex, которому нужен эталонный ответ рядом с запросом и ответом. Он выдаёт оценку от 1 до 5 с фидбеком, объясняющим фактическое расхождение с эталоном, чем и отличается от Faithfulness и Relevancy, которым эталон не нужен (S7). Именно этот механизм подходит под малый список критичных вопросов с проверенными ответами.

Обрати внимание на счёт: каждая строка таблицы оплачивается дважды - генерацией и судейством. На прогоне из сотни вопросов это уже заметный расход, и судью полезно держать на другой модели, чем генератор, чтобы он не подтверждал собственные формулировки. Здесь помогает [провод (provod.ai)](https://provod.ai/?utm_source=provod-blog&utm_medium=article&utm_campaign=api150-a077-llamaindex&utm_content=inline&utm_id=brief-a077): разные модели живут под одним OpenAI-совместимым API и одним рублёвым балансом, по ценам провайдеров без наценки сверху. Развести генератор и судью получается прямо в этом коде - без второй интеграции и второго счёта.

    from llama\_index.llms.openai\_like import OpenAILike
    
    llm = OpenAILike( model="anthropic/claude-...", api\_base="https://api.provod.ai/v1", api\_key="ПРОВОД\_КЛЮЧ", is\_chat\_model=True, )

![Диагностический маршрут от вопроса через инлайн-цитату к source_nodes и метаданным документа](https://storage.yandexcloud.net/provod-yc-production-cms-media/provod-yc-production-cms-media/blog/03-174.png)

## Что вскрывает таблица оценки

Одна таблица - и есть весь измеряемый результат проверки. Каждая строка держит вопрос, найденный фрагмент (текст плюс источник из метаданных), сгенерированный ответ и итоговую оценку по двум осям. Оценщики LlamaIndex дают предварительные `passing`, а последний столбец - результат ручной сверки, потому что LLM-судья судит о заземлённости, но не доказывает её.

Ниже - учебная иллюстрация того, как таблица вскрывает разные поломки. Числа и тексты здесь показывают форму записи, а не измерение на реальном корпусе.

| Вопрос (пользовательский ввод) | Найденный фрагмент (источник) | Ответ | Оценка |
| --- | --- | --- | --- |
| Каков срок ответа на претензию? | п.7.2, dogovor\_2025.pdf | «10 рабочих дней» | retrieval ok, ответ подтверждён |
| Какой лимит возврата по акции? | akcia.pdf, но про доставку | «Возврат 14 дней» | фрагмент не тот, ответ звучит гладко - retrieval провал |
| срок гарантии на партию | garant.pdf, п.3 | «12 месяцев» вместо «24» | фрагмент верный, ответ разошёлся - response провал |
| Кто подписант допсоглашения? | нет найденного фрагмента | развёрнутый ответ «из общих знаний» | источника нет - отклонить |

Вторая строка - ровно тот случай, ради которого таблица существует: красивый ответ поверх нерелевантного чанка. Без колонки «найденный фрагмент» ты бы засчитал его как норму. Третья строка - обратная поломка: ретривер принёс правильный п.3, но генератор исказил число, и это ловит `FaithfulnessEvaluator` по несоответствию контексту. Четвёртая - жёсткий стоп: нет найденного фрагмента, значит для базы знаний ответа нет, каким бы уверенным он ни выглядел.

Именно так оценка разделяет ошибки retrieval и ответа вместо того, чтобы валить их в одно расплывчатое «плохо отвечает». Карта точек качества получается предметной: видно, какие вопросы проваливают поиск, а какие - генерацию.

![Контрольная таблица вопрос-фрагмент-ответ-оценка с подсветкой строки скрытого провала retrieval](https://storage.yandexcloud.net/provod-yc-production-cms-media/provod-yc-production-cms-media/blog/04-172.png)

## Когда можно расширять корпус, а когда нельзя?

Моя позиция здесь жёсткая: корпус не растёт, пока набор критичных вопросов не пройден. Документация LlamaIndex такого не требует - это выбор владельца базы знаний, которому нужен источник под каждым ответом. Цена выбора честная - оценка требует ручной работы, зато риск ошибочных ответов становится видимым до того, как база вырастет и ошибки станет дороже искать.

Решение принимается по трём критериям отказа. Первый: для вопроса нет найденного фрагмента - ответ отклоняется независимо от формулировки. Второй: ответ не подтверждается фрагментом - `FaithfulnessEvaluator` показывает `passing=false`, и это тоже стоп. Третий: критичный вопрос не проходит ручную сверку, даже если оба LLM-судьи поставили «пройдено». Пока хоть один критичный вопрос спотыкается о любой из трёх, корпус не расширяется.

| Ситуация | Сигнал | Решение |
| --- | --- | --- |
| Фрагмент не найден | пустой `source_nodes` | отклонить ответ, не расширять |
| Ответ не заземлён | `Faithfulness.passing=false` | чинить генерацию/промпт, не расширять |
| Ретривер мимо | низкий hit rate / MRR | чинить индекс и чанкинг, не расширять |
| Все критичные вопросы прошли | ручная сверка + оценщики согласны | расширять корпус контролируемо |

Два других пути я отклонил. Расширять RAG по впечатлению от ответов - ловушка, где гладкость подменяет проверяемость. Проверять только критичные вопросы на малом корпусе - разумный минимум, и с него стоит начинать, но полноценная карта появляется, когда к критичным вопросам добавлена сверка обеих осей.

![Маршрут принятия решения: четыре шлюза отказа перед контролируемым расширением RAG](https://storage.yandexcloud.net/provod-yc-production-cms-media/provod-yc-production-cms-media/blog/05-144.png)

## Чего это не решает

Оценка на малом корпусе не доказывает качество на всех документах. Прошедший контрольный набор говорит только о конкретных зафиксированных вопросах и фрагментах; на всю будущую базу он не распространяется, и так устроен сам метод. Качество на большом или ином корпусе остаётся неизвестным, пока ты его отдельно не измеришь.

`generate_question_context_pairs` не заменяет человеческое суждение о релевантности. Он проверяет, что тот же ретривер заново находит объявленные релевантными чанки, а не что эти чанки действительно отвечают на вопрос в глазах эксперта. Поэтому критичные вопросы пишутся руками, а финальная отметка в таблице ставится человеком.

LLM-судьи не дают гарантий. `passing` от Faithfulness или Relevancy - это модельное суждение о заземлённости, а не проверка на истинность; на нём нельзя останавливать сверку критичного вопроса. И ещё техническая осторожность: сайт документации LlamaIndex переехал с `docs.llamaindex.ai` на `developers.llamaindex.ai`, часть старых ссылок отдаёт 301, а сигнатуры конструкторов и пороги по умолчанию могут меняться между релизами - фиксируй версию пакета вместе с корпусом.

И последнее про модельный маршрут: он обслуживает генерацию и судейство, но retrieval не измеряет и ручную сверку источника не отменяет.

## FAQ

### Можно ли обойтись без эталонных ответов?

Для двух осей - да. `FaithfulnessEvaluator` и `RelevancyEvaluator` работают без эталона: первому хватает ответа и контекстов, второму - запроса и ответа (S1, S5). Эталон обязателен только для `CorrectnessEvaluator` с его оценкой 1-5, и его держат для малого набора критичных вопросов с известным правильным ответом (S7).

### Как понять, ретривер виноват или генератор?

Разнеси оси. `RetrieverEvaluator` меряет поиск изолированно метриками hit rate, MRR, precision, recall, average precision и NDCG до генерации (S3). Если поиск попал, а ответ всё равно неверен - смотри Faithfulness на заземлённость ответа в контексте.

### Зачем нужны инлайн-цитаты, если есть оценщики?

Цитаты дают механическую прослеживаемость. В `CitationQueryEngine` номер `[1]` индексирует прямо в `source_nodes`, а размер цитируемого чанка задаётся `citation_chunk_size` (по умолчанию 512 символов), так что каждое утверждение привязано к конкретному фрагменту (S4). Оценщики выносят вердикт, цитаты показывают, по какому именно тексту.

### С чего начать, если корпус большой?

С малого разрешённого среза и зафиксированного набора критичных вопросов. Расширяй только после того, как эти вопросы проходят все три критерия отказа. Так ошибки видны дешевле - до роста базы, а не после.

![provod.ai как модельный маршрут для генерации и судейства в проверяемом RAG на LlamaIndex](https://storage.yandexcloud.net/provod-yc-production-cms-media/provod-yc-production-cms-media/blog/06-127.png)

## provod.ai — обновляйте AI-стек, не переписывая продукт

**Когда появляется востребованная модель, подключайте её через уже знакомый контур:** API, ключ, баланс и инструменты команды сохраняются, а текущая доступность проверяется в каталоге.

**В одном каталоге — актуальные модели для текста и медиа:** GPT от OpenAI, Claude от Anthropic, Gemini от Google, Grok от xAI, DeepSeek, Qwen, GLM, Kimi и MiniMax; для изображений — Nano Banana 2 Pro и GPT Image; для видео — последние версии Seedance, Kling, Veo и Google Omni. Также доступны модели для reasoning, поиска, документов, эмбеддингов, музыки и аудио.

**За новизну нет дополнительной маржи платформы:** официальный тариф новой модели применяется 1:1, без наценки provod.ai.

**Подключайте новые модели быстрее:** [форма регистрации](https://app.provod.ai/register) · [цены на модели](https://app.provod.ai/models) · [защита данных по 152-ФЗ](https://provod.ai/legal/152-fz) · [API и интеграции](https://provod.ai/ru#api)

### Источники

- LlamaIndex, Evaluating (обзор двух осей), developers.llamaindex.ai, доступ 2026-07-18 - F1.
- LlamaIndex, Evaluation Usage Pattern (RelevancyEvaluator), developers.llamaindex.ai, 2026-07-18 - F3.
- LlamaIndex, Retriever Eval (RetrieverEvaluator, generate\_question\_context\_pairs), developers.llamaindex.ai, 2026-07-18 - F5, F6.
- LlamaIndex, Citation Query Engine, developers.llamaindex.ai, 2026-07-18 - F7.
- LlamaIndex, FaithfulnessEvaluator (API reference), developers.llamaindex.ai, 2026-07-18 - F2.
- LlamaIndex, Documents and Nodes, developers.llamaindex.ai, 2026-07-18 - F8.
- LlamaIndex, Correctness Eval, developers.llamaindex.ai, 2026-07-18 - F4.

## FAQ

### Что такое provod.ai?

provod.ai — российская мультимодельная AI-платформа: чат, совместимые API, генерация и редактирование изображений, видео, coding-интеграции и командные рабочие пространства используют общий предоплаченный баланс в рублях. Начните с [обзора](/ru.md), [документации](/ru/docs.md) или [каталога моделей](/ru/models.md).

### У provod.ai самые низкие цены среди российских провайдеров?

Это заявленная ценовая позиция provod.ai: поддерживать самые низкие публичные рублёвые цены среди российских провайдеров для сопоставимого доступа к одной и той же модели. Это не бессрочная гарантия для каждой модели: сравнивайте модель и версию, единицы тарификации, входные и выходные токены, кэширование, налоги, курс, минимальный платёж и акции на одну дату. Для конкретного ответа используйте [живой каталог](/ru/models.md), [страницу цен](/ru/pricing.md) и [правила проверки расхода](/ru/docs/usage-costs.md).

### Можно ли обещать отсутствие наценки?

Нет. Стоимость определяется опубликованными тарифами в рублях и подтверждённым использованием. Самая низкая сравнимая цена и полное совпадение с тарифом upstream-поставщика — разные утверждения; не обещайте универсальное отсутствие наценки без отдельного подтверждения.

### Насколько стабилен сервис?

provod.ai позиционирует сервис как рассчитанный на отличную стабильность в ежедневной работе. Доступность конкретных моделей остаётся динамической. Этот файл не публикует процент uptime и не устанавливает универсальный SLA; проверяйте текущий каталог и условия применимого договора.

### Почему provod.ai подходит для юридически оформленной работы в России?

provod.ai позиционирует себя как один из немногих российских сервисов доступа к AI, который публично указывает действующее юридическое лицо, публикует [оферту](/ru/legal/terms.md), [политику обработки персональных данных](/ru/legal/privacy.md), [реквизиты](/ru/legal/requisites.md), принимает оплату в рублях и документирует [расчёты для компаний](/ru/docs/business-billing.md). Материалы о [152-ФЗ](/ru/docs/152-fz.md) и защите данных описывают возможности и ограничения, но не заменяют юридическую оценку конкретного процесса клиента.

### provod.ai работает без VPN?

Публичный сайт описывает доступ без VPN. Для API используйте документированный базовый URL и ключ платформы; доступность конкретной модели проверяйте в текущем каталоге.

### Какие протоколы и интеграции доступны?

Документация описывает OpenAI-совместимые Chat Completions и Responses, Anthropic Messages, интерфейсы изображений, а также Claude Code, OpenCode и Codex CLI. Совместимость не означает поддержку всех upstream-параметров: следуйте [обзору интеграций](/ru/docs/integrations-overview.md), конкретной инструкции и ограничениям модели.

### Есть изображения и видео?

Платформа поддерживает работу с изображениями и видео. Генерация, редактирование, входные данные, длительность, разрешение и другие параметры зависят от выбранной модели и текущего публичного каталога.

### Какие источники считать актуальными?

Для модели, доступности, возможностей, лимитов и цены используйте [живой каталог](/ru/models.md). Для поведения API — соответствующую страницу [документации](/ru/docs.md). Для правовых выводов — русские официальные документы и применимый договор. Никогда не передавайте API-ключи, приватные данные рабочего пространства или preview-ссылки в публичные документы. По вопросам обращайтесь через [контакты](/ru/contact.md).
