THREADQA
    THREADQA
    Главная
    Курсы
    Java QA AutomationNEW
    Новый курс · уже можно купить
    Python QA Automation
    Pytest, Playwright, Docker
    iOS QA Automation
    XCTest, XCUITest, Fastlane
    Все курсы
    Сравнить Java / Python / iOS
    Практика
    Мок собеседование
    Тренировка перед реальным интервью
    XPath Practice Hub
    Тренажёр XPath-запросов
    Roadmap
    Путь QA-инженера
    Тренажёры
    SQL, Git, Docker, Linux, тест-дизайн
    QA игры
    8 мини-игр для тестировщика
    XPath Dinner
    Практика XPath в игровом формате
    Каталог инструментов
    Инструменты тестирования и сравнения
    Глоссарий ИИ-тестирования
    LLM, RAG, метрики, evals
    С чего начать
    Блог
    FAQ
    Для компаний
    1. Домой
    2. ИИ и тренды
    3. Тестирование RAG: как понять, что сломалось — поиск или генерация
    Все статьи
    ИИ и тренды
    19 сентября 2026 г. 14 мин чтения

    Тестирование RAG: как понять, что сломалось — поиск или генерация

    Как тестировать RAG: метрики поиска (hit rate, recall, MRR) и генерации (faithfulness), эксперимент с идеальным контекстом, влияние чанков и top-k. Код на Python.

    Олег Пендрак
    Олег Пендрак
    Tech Lead QA Automation · Ozon, VK

    Как понять, что сломалось в RAG: поиск или генерация? Краткий ответ

    Проверяйте поиск и генерацию по отдельности. Для поиска нужен набор вопросов с известными нужными фрагментами и метрики hit rate@k, recall@k и MRR. Для генерации подставьте в промпт идеальный фрагмент (oracle context) и оцените ответ на фактичность и релевантность. Если с идеальным контекстом ответ хороший, виноват поиск; если плохой, проблема в промпте или модели.

    Как устроен RAG и где он ломается

    RAG (Retrieval-Augmented Generation) — подход, при котором модель отвечает не только по своим знаниям, но и по найденным во внешней базе фрагментам [1]. Схема почти всегда одна: документы режут на чанки, индексируют, на вопрос находят top-k ближайших чанков, подставляют их в промпт и генерируют ответ. Ошибка на любом шаге превращается в плохой ответ, и по самому ответу не видно, на каком.

    Первые три этапа проверяем метриками поиска, последние три метриками генерации. Так плохой ответ не остаётся загадкой.

    Симптомы и вероятные причины

    Что видит пользовательВероятная причинаКуда смотреть в первую очередь
    Бот отвечает «не знаю», хотя документ в базе естьПоиск не нашёл нужный чанкRecall@k, размер чанков, качество эмбеддингов
    Ответ по теме, но устаревший или из другой версииВ индексе старые документы или дублиАктуальность и метаданные индекса
    Бот уверенно называет факт, которого нет в документахМодель выдумывает поверх контекстаFaithfulness, формулировка промпта, temperature
    Ответ верный, но не про то, что спросилиПромпт или поиск приносят соседнюю темуAnswer relevance, context precision
    Хорошо отвечает на короткие вопросы, плохо на длинные и составныеНесколько нужных фактов лежат в разных чанкахRecall по составным вопросам, значение top-k
    Качество упало без изменений в кодеОбновили базу знаний, модель или промптСравнение прогонов, версии артефактов

    Как тестировать поиск отдельно

    Поиск можно проверять вообще без языковой модели: он либо принёс нужный фрагмент, либо нет. Для этого нужен небольшой набор, в котором для каждого вопроса заранее известно, в каком чанке лежит ответ. Собирать его удобно из реальных вопросов пользователей и документов, к которым эксперты привязывают правильный источник.

    • ▸Hit rate@k — доля вопросов, для которых нужный чанк попал в top-k. Самая простая метрика: нашли или нет.
    • ▸Recall@k — доля нужных чанков, найденных в top-k. Важна, когда для ответа требуется несколько фрагментов.
    • ▸Precision@k — доля релевантных среди найденных. Низкая precision означает, что в промпт попадает много мусора.
    • ▸MRR (mean reciprocal rank) — среднее значение 1/позиция первого нужного чанка. Показывает, насколько высоко в выдаче стоит нужное.
    python
    1# evals/test_retrieval.py
    2import json
    3
    4from myapp.rag import retrieve  # retrieve(question, k) -> list[Chunk], у чанка есть .id
    5
    6K = 5
    7
    8# Каждая строка: {"question": "...", "relevant_ids": ["kb-12#3", "kb-40#1"]}
    9with open("evals/retrieval_set.jsonl", encoding="utf-8") as f:
    10    CASES = [json.loads(line) for line in f]
    11
    12
    13def positions(case) -> list[int]:
    14    """Позиции (с 1) нужных чанков в выдаче top-K."""
    15    ids = [chunk.id for chunk in retrieve(case["question"], k=K)]
    16    return [ids.index(rid) + 1 for rid in case["relevant_ids"] if rid in ids]
    17
    18
    19def test_hit_rate_at_k():
    20    hits = sum(1 for case in CASES if positions(case))
    21    assert hits / len(CASES) >= 0.90, f"hit rate@{K} = {hits / len(CASES):.0%}"
    22
    23
    24def test_recall_at_k():
    25    recalls = [len(positions(c)) / len(c["relevant_ids"]) for c in CASES]
    26    assert sum(recalls) / len(recalls) >= 0.80
    27
    28
    29def test_mrr():
    30    rr = []
    31    for case in CASES:
    32        pos = positions(case)
    33        rr.append(1 / min(pos) if pos else 0)
    34    assert sum(rr) / len(rr) >= 0.70

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

    Как тестировать генерацию отдельно: идеальный контекст

    Чтобы проверить, умеет ли модель отвечать по контексту, уберите поиск из уравнения: подставьте в промпт заведомо правильный фрагмент. Этот приём называют oracle context. Если и при идеальном контексте ответ плохой, виноваты промпт, параметры или модель, а не поиск.

    python
    1# evals/test_generation.py
    2import json
    3
    4import pytest
    5
    6from evals.judge import judge            # LLM-судья, см. статью про LLM-as-a-Judge
    7from myapp.rag import generate_answer    # generate_answer(question, chunks: list[str]) -> str
    8
    9# {"id", "question", "oracle_chunks": ["..."], "bucket": "happy_path"}
    10with open("evals/generation_set.jsonl", encoding="utf-8") as f:
    11    CASES = [json.loads(line) for line in f]
    12
    13
    14@pytest.mark.parametrize("case", CASES, ids=lambda c: c["id"])
    15def test_answer_is_grounded_in_oracle_context(case):
    16    answer = generate_answer(case["question"], case["oracle_chunks"])
    17    verdict = judge({**case, "context": "\n".join(case["oracle_chunks"])}, answer)
    18    assert verdict["verdict"] == "pass", verdict["reasoning"]

    Диагностика по шагам: блок-схема

    Соберём два эксперимента в одну последовательность. Она работает и как тест, и как инструкция для разбора плохого фидбека от пользователя.

    Три диагноза: виноват поиск, виноват промпт или модель, ответ верный, но мимо вопроса.
    • ▸Ответ с идеальным контекстом хороший — виноват поиск. Идите в метрики поиска, размер чанков, top-k и индекс.
    • ▸Ответ плохой и не опирается на контекст — проблема в промпте или модели. Проверяйте faithfulness, температуру, версию модели.
    • ▸Ответ опирается на контекст и верен, но не отвечает на вопрос — проверьте answer relevance и то, как промпт формулирует задачу.

    Чанки и top-k: параметры, которые ломают качество

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

    ПараметрСлишком маленькое значениеСлишком большое значение
    Размер чанкаФакт разрезан на части, чанк теряет контекст, поиск находит обрывкиВ чанке много лишнего, эмбеддинг «размывается», релевантность падает
    Overlap между чанкамиСмысл на границах теряетсяМного дублей, поиск выдаёт почти одинаковые чанки
    k (число чанков)Нужный фрагмент не попадает в выдачу, recall низкийВ промпт попадает мусор, растёт цена и задержка, модель отвлекается

    Есть ещё эффект, о котором часто забывают: модели хуже используют информацию из середины длинного контекста и лучше из начала и конца [3]. Значит, порядок чанков в промпте влияет на ответ. Проверить это можно тестом, который двигает нужный чанк по позициям среди отвлекающих.

    python
    1# evals/test_position.py
    2import json
    3
    4import pytest
    5
    6from evals.judge import judge
    7from myapp.rag import generate_answer
    8
    9# {"id", "question", "oracle_chunk": "...", "distractors": ["...", "...", "...", "..."]}
    10with open("evals/position_set.jsonl", encoding="utf-8") as f:
    11    CASES = [json.loads(line) for line in f]
    12
    13
    14@pytest.mark.parametrize("position", [0, 2, 4])
    15@pytest.mark.parametrize("case", CASES, ids=lambda c: c["id"])
    16def test_answer_does_not_depend_on_chunk_position(case, position):
    17    chunks = list(case["distractors"])
    18    chunks.insert(position, case["oracle_chunk"])   # двигаем нужный чанк по выдаче
    19
    20    answer = generate_answer(case["question"], chunks)
    21    verdict = judge({**case, "context": "\n".join(chunks)}, answer)
    22    assert verdict["verdict"] == "pass", f"позиция {position}: {verdict['reasoning']}"

    Метрики RAG: что измерять на каждом шаге

    Названия метрик чаще всего берут из фреймворка RAGAS, который предложил оценивать RAG без ручной разметки эталонных ответов [2]. Для практики достаточно четырёх:

    МетрикаСлойВопрос, на который отвечает
    Context recallПоискНашли ли мы всё, что нужно для ответа?
    Context precisionПоискНет ли среди найденного лишнего, и стоит ли нужное выше?
    FaithfulnessГенерацияКаждое ли утверждение ответа подтверждается контекстом?
    Answer relevanceГенерацияОтвечает ли ответ на заданный вопрос?

    Типичные ошибки

    • Оценивать только итоговый ответ

      Плохой ответ не показывает, сломался поиск или генерация, и вы чините наугад

    • Набор для поиска собран из тех же документов, по которым настраивали поиск

      Метрики завышены. Берите реальные вопросы пользователей и держите часть набора закрытой

    • Менять размер чанка и k без замеров

      Оба параметра дают противоположные эффекты, и оптимум зависит от ваших документов

    • Не пересчитывать метрики после обновления базы знаний

      Новые документы и дубли меняют выдачу при неизменном коде

    • Проверять только вопросы, ответ на которые есть в базе

      Нужна корзина вопросов вне базы: бот должен честно сказать, что не знает

    FAQ

    Как понять, что виноват поиск, а не модель?

    Подставьте в промпт правильный фрагмент вручную (oracle context). Если ответ стал хорошим, поиск не принёс нужное, и чинить надо его: размер чанков, k, эмбеддинги, индекс. Если ответ по-прежнему плохой, проблема в промпте или модели.

    Какие метрики использовать для оценки поиска в RAG?

    Hit rate@k (нашли ли нужный чанк в top-k), recall@k (какую долю нужных чанков нашли), precision@k (сколько релевантного среди найденного) и MRR (как высоко стоит нужный чанк). Для оценки нужен набор вопросов с известными релевантными чанками.

    Что такое faithfulness в RAG?

    Это доля утверждений в ответе, которые подтверждаются найденным контекстом. Низкая faithfulness означает, что модель выдумывает факты поверх контекста. Обычно её считает LLM-судья: разбивает ответ на утверждения и проверяет каждое по контексту.

    Как выбрать размер чанка и значение k?

    Универсального значения нет: слишком мелкие чанки теряют контекст, слишком крупные размывают релевантность, а большое k приносит мусор. Подберите значения экспериментом на своём наборе, измеряя hit rate, recall и precision, и пересматривайте при смене документов или модели эмбеддингов.

    Влияет ли порядок чанков в промпте на ответ?

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

    Источники

    1. Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks — Lewis P., Perez E., Piktus A. и др., NeurIPS 2020 (arXiv:2005.11401)
    2. Ragas: Automated Evaluation of Retrieval Augmented Generation — Es S., James J., Espinosa-Anke L., Schockaert S., arXiv:2309.15217, 2023
    3. Lost in the Middle: How Language Models Use Long Contexts — Liu N. F., Lin K., Hewitt J. и др., TACL, 2023 (arXiv:2307.03172)
    Дальше: как тестировать LLM-чатбота — кейсы, диалоги, golden set
    Начало: что и когда тестировать в LLM-приложении
    Глоссарий тестирования ИИ: определения терминов
    #тестирование rag#rag метрики#faithfulness#recall@k#чанки rag#top-k#тестирование llm#ragas#поиск или генерация

    Хочешь практиковаться, а не только читать?

    Курсы по Java, Python и iOS автоматизации. Первые уроки бесплатно.

    Начать бесплатно

    Читайте также

    ИИ и тренды
    12 мин

    Тестирование ИИ: что и когда тестировать в LLM-приложении и насколько это востребовано

    Тестирование ИИ-приложений: спрос по данным World Quality Report, пять слоёв LLM-системы, моменты запуска проверок и как по плохому фидбеку найти, где сломалось.

    Общие темы:тестирование llmтестирование rag
    ИИ и тренды
    15 мин

    Метрики оценки ответов LLM: BLEU, ROUGE, BERTScore и семантическая близость — что выбрать

    Как оценивать ответы LLM: BLEU, ROUGE, BERTScore и семантическая близость. Чем отличаются, где ошибаются, что выбрать для чат-бота и RAG. Код на Python.

    Общие темы:тестирование llmrag метрики
    ИИ и тренды
    13 мин

    Prompt injection в LLM: как работает атака, как её тестировать и чем защищаться

    Что такое prompt injection: прямая и непрямая инъекция, утечка системного промпта. Как собрать набор атак для red team, автотест на Python, метрика успеха атаки и слои защиты по OWASP.

    Общие темы:тестирование llm
    Все статьи блога

    Содержание

    Как понять, что сломалось в RAG: поиск или генерация? Краткий ответКак устроен RAG и где он ломаетсяСимптомы и вероятные причиныКак тестировать поиск отдельноКак тестировать генерацию отдельно: идеальный контекстДиагностика по шагам: блок-схемаЧанки и top-k: параметры, которые ломают качествоМетрики RAG: что измерять на каждом шагеТипичные ошибкиFAQИсточники

    Автор

    Олег Пендрак
    Олег Пендрак
    Tech Lead QA

    Опыт в Ozon и VK. YouTube-канал 10к+ подписчиков.

    Готов к практике?

    Первые уроки бесплатно

    Начать бесплатно
    THREADQAПлатформа QA Automation

    О платформе

    Обучаем автоматизации тестирования на Java, Python и iOS. Практические курсы, roadmap, тренажёры и персональные мок-интервью.

    Онлайн 24/7

    Курсы

    • Java QA AutomationNEW
    • Python QA Automation
    • iOS QA Automation
    • Про ThreadQA

    Услуги

    • Мок-собеседования

    Инструменты

    • Roadmap QA
    • Тренажёры
    • QA игры
    • Тренажёр XPath
    • XPath Diner
    • Каталог инструментов
    • Глоссарий ИИ-тестирования

    Контакты

    • Email
      info@threadqa.ru
    • Telegram
      @penolegrus
    Публичная офертаПолитика конфиденциальностиУсловия использования
    © 2026·ThreadQA LMS·Все права защищены