Как мы с Claude Code учились оценивать качество RAG системы
Уверен, на Хабре найдётся немало статей, посвященных оценке качества RAG систем. Тема по-прежнему остаётся актуальной, потому что даже готовые библиотеки вроде RAGAS не очень-то работают из коробки, требуют навыков программирования и некоторой квалификации. При этом сам процесс оценки — повторение достаточно простых операций и мне всегда хотелось переложить его на AI-ассистента.
Повод попробовать появился неожиданно: свободное время и курс по Claude Code на Stepik. Для финала как раз нужен был проект, посвященный автоматизации реальной рутинной задачи, желательно без кода (курс про вайб-воркинг, для непрограммистов). Конечно, я сразу вспомнил про задачу оценки качества. Дальше — честная история со всеми проблемами. Забегая вперёд, скажу, что совсем без программирования не вышло. Но, может, это профессиональная деформация.
Шаг первый и первый фейл
Как начать? Я взял собственный готовый бенчмарк, таблицу с кейсами «вопрос; ответ; контекст» и отдал Клоду. Он быстро понял, что там русский язык UTF-8, но не определил разделитель полей, так как я использую точку с запятой в CSV, привычка. Дал подсказку. На что он сразу предупредил что будет гигантский расход токенов, а ещё ему нужен ключ, чтобы использовать SDK Anthropic. Ключа у меня нет, Клод предложил использовать эвристики на регулярных выражениях. Мы попробовали на одной метрике. Результат — 100% качество, что конечно жёсткая неправда. А ещё была путаница в чанках контекста, которые были склеены в один блок текста в бенчмарке.
Шаг второй. Внешняя модель
Регулярные выражения помогают только в одном случае, если в вопросе, контексте и ответе есть какой-то код, аббревиатура или шаблон, который легко извлечь. В других случаях нужен LLM-судья. И я решил его сделать на внешней модели. Выбрал gpt-4o-mini от прокси-провайдера, она часто используется в примерах для библиотеки RAGAS.
В RAGAS много метрик, не все из них полезны я планировал использовать только три. Они оценивают не качество ответа, а качество контекста, который система передаёт в модель.
Метрики
Точность контекста, Context Precision
оценивает, насколько высоко в выдаче RAG ранжированы чанки, полезные для правильного ответа. Чем выше полезный чанк, тем выше метрика.
Релевантность контекста, Context Relevance
оценивает, насколько высоко ранжированы чанки, релевантные вопросу пользователя. В отличие от Precision, не требует эталонного ответа.
Полнота контекста, Context Recall
оценивает, какая доля значимых фактов из эталонного ответа подтверждается найденным контекстом
Context Precision и Context Recall — метрики RAGAS. Context Relevance, если не ошибаюсь, нет. Она обычно получается выше чем Precision, нужно настраивать промпт, зато «не подсматривает в ответ».
В качестве первой пробной метрики решил взять Context Precision. Провёл пару экспериментов, Клод без проблем запускает скрипты из командной строки (пришлось сделать виртуальное окружение на Python). И главное — он не против внешних моделей для рутины, даже пишет, что это штатный режим, верим.
А вот проблема с парсингом контекста, если все чанки в одной ячейке таблицы, никуда не делась. Я попробовал вставлять в контекст разделители между чанками, оказалось не очень-то и надежно. Тогда появилась идея оставить в бенчмарке только вопрос и ответ, а контекст получать из RAG системы в процессе оценки каждого кейса. Это не только упростило подготовку бенчмарка, теперь я легко мог менять количество чанков в контексте.
Шаг третий. Сервис RAG и танцы вокруг MCP
План: сделать простенькую RAG систему с векторным поиском, добавить Model Context Protocol и далее использовать в субагентах. За пару часов я собрал её на FastAPI, LangChain и ChromaDB, загрузил туда тестовый контекст, всё проверил и решил добавить MCP. С библиотекой fastapi_mcp — пять минут работы.
Оказалось, не всё так просто. Клод упорно отказывался находить MCP сервер. Я прямо указывал на .mcp.json в проектной папке, на что он отвечал, что вероятно RAG система запущена после старта сессии, и что надо всё перезапустить. Ситуация повторялась снова и снова. Решил, что нужен какой-то тестер, нашёл MCP inspector (нужен Node.js).
Инспектор помог понять следующее — ни с каким видом транспорта (SSE, HTTP) моя система на запросы не отвечает, а вот если включить MCP Proxy, всё сразу начинает работать и в консоли появляется заветное 202 Accepted. Значит проблема в транспорте, который я использую. Ещё несколько экспериментов и решение было найдено, спасибо Google!
Решение
1. В блок импорта основного скрипта api.py добавить
from fastapi.middleware.cors import CORSMiddleware
2. Перед инструкциями app.include вставить блок кода
app.add_middleware( CORSMiddleware, allow_origins=[«*»], # Or specify your Web UI’s origin allow_credentials=True, allow_methods=[«GET», «POST», «OPTIONS»], allow_headers=[«*»], )
3. Использовать mcp.mount() вместо mount_sse() или mount_http(), хотя это устаревшая инструкция.
Полагаю, что есть ещё варианты, которые решают проблему. Код сервера со всем необходимым — в репозитории. А README к нему, как и к этому проекту, подготовил Клод. Вот уж точно полезный навык.
Шаг четвертый. «Шумные» субагенты
Сделал два субагента — один для Context Precision, он «видит» из бенчмарка вопрос, ответ и получает контекст из RAG системы, второй — для Context Relevance. Этот, в отличие от первого, не видит ответа и оценивает контекст только по вопросу.
Клод без каких либо проблем справился с этими агентами. Увы, они оказались слишком шумными, контекстное окно засорялось прямо на глазах, по 1-2k на один кейс бенчмарка (у меня 48 кейсов и два варианта вопросов — попроще и посложнее). Клод предложил для субагентов добавить инструкцию «Do not narrate your steps between tool calls», это не очень помогло в плане токенов.
Шаг пятый. Легкий навык и инструменты
Единственное полезное, что я взял из предыдущего шага — формат отчета. По каждому кейсу мне нужна была следующая информация:
{ «case_id»: 0, «question»: «question text», «answer»: «answer text», «context»: [«chunk_1», «chunk_2», «chunk_3», «chunk_4»], «labels»: [1, 0, 1, 1], «explanation»: [«explanation_1», «explanation_2», «explanation_3», «explanation_4»], «score»: 0.875 }
Уточнив у Клода, в каком виде ему удобнее было бы с такой структурой работать, выяснил, что лучше всего подходит JSONL, текст, где каждая строка — отдельный JSON. На том и порешили.
Далее план был следующий — сделать инструмент с командной строкой (eval_context.py), который бы выполнял всю основную работу. Проходил последовательно по кейсам, запускал тесты и записывал результаты в отчёт. А навык всё запускал и управлял параметрами оценки.
Чтобы упростить код я взял свою готовую библиотеку CPCR_lib.py, это тоже обёртка для LLM-судьи, которая умеет выносить вердикт для оценок по всем трём метрикам.

Нужный класс импортируется в eval_context.py, так мы экономим токены на генерации промптов. Они не попадают в контекстное окно.
MCP в этой версии используется только как необязательная проверка доступности RAG системы. Оставил для будущих релизов. Все запросы — через REST API, что нормально для инструмента на Python. Если у кого-то получилось подключить FastAPI через MCP без дополнительных усилий, поделитесь, пожалуйста, рецептом в комментариях.
Объяснил Клоду изменения в архитектуре и попросил три вещи:
1. подготовить навык для работы с инструментом eval_context.py
2. сделать HTML вьювер для отчетов с учетом особенностей Recall (контекст склеен в один кусок,
а вместо чанков оцениваются факты)
3. подготовить дашборд для оценок по всем трём метрикам.
Навык— name: rag-evaluation description: Запускает инструменты оценки качества RAG-системы, когда пользователь просит оценить RAG, запустить метрику, или произносит слова: «оцени», «запусти оценку», «рассчитай метрику», «Context Precision», «Context Relevance», «Context Recall». — # RAG Evaluation Skill Этот skill запускает оценку качества RAG-системы по выбранной метрике. ## Trigger Используй этот skill когда пользователь просит оценить RAG, запустить метрику, или произносит слова: «оцени», «запусти оценку», «рассчитай метрику», «Context Precision», «Context Relevance», «Context Recall». ## Процедура ### 1. Собери параметры Используй инструмент `AskUserQuestion` — задай все четыре вопроса одновременно с вариантами для клика: 1. **Метрика** — `precision` / `relevance` / `recall` 2. **Benchmark файл** — `benchmark_simple.csv` / `benchmark_hard.csv` 3. **max_k** — `3` / `5` / `7` 4. **Количество кейсов** — `5` / `10` / `все` ### 2. Запусти скрипт «`powershell venvScriptspython.exe eval_context.py —scenario <scenario> —benchmark benchmarks/<file> —max-k <max_k> —cases <cases> «` Если пользователь не указал `—cases`, не передавай этот параметр (обработаются все кейсы). ### 3. Сообщи результат После завершения скрипта сообщи пользователю: — Mean метрику — Путь к JSONL файлу — Путь к Markdown отчёту
AskUserQuestion — внутренний инструмент Клод, даёт пользователю выбор из вариантов и превращает это в текстовые инструкции.
Прошу не удивляться PowerShell, проект сделан на windows-машине.
Универсальный вьювер для отчетов: Кейсы детализируются. Есть вердикт по каждому чанку.

Дашборд для трех метрик. Красотища 🙂 Можно посмотреть вклад каждого кейса в общую оценку.

Подвожу итог. Оценка качества для одной метрики в расчёте на 10 кейсов занимает примерно 2-3 минуты (RAG работает на CPU). Расход токенов минимальный, в районе 500-800 на метрику. В качестве судьи можно использовать локальную модель. Рекомендация: модель не хуже 27b.
Оценку по всем трем метрикам и всем кейсам в проекте я делал несколько раз. Суммарно на LLM-судью получилось около 2М токенов (примерно 60 рублей). И ещё около 415k токенов в Claude Code на разработку: в районе 400k на все предыдущие шаги и 15k на финальную часть вместе с тестами. В плане работы, если бы делал то же самое в Python-ноутбуках — написание скриптов, отладку кода, прогон кейсов, подготовка отчетов, анализ результатов — полагаю, это заняло бы неделю на весь бенчмарк.
Ссылки:
Репозиторий проекта
Репозиторий naive-rag-mcp сервера
Документация на fastapi_mcp
Метрики в RAGAS
Откуда взялся мой бенчмарк (статья)
Источник: habr.com
Похожие записи
- Компания Sennheiser представила открытые наушники Accentum Clip с девятью часами автономной работы.
- США утверждают, что основной центр производства микросхем компании ASML может находиться в Китае. ASML заявляет, что это не так.
- Помните некогда популярную нейросеть Midjourney? Они выпустили свой первый физический…
Оцените материал:
Похожие записи
Компания Lilly выплатила AC Immune 12,5 млн долларов за расширение сотрудничества в области лечения болезни Альцгеймера, поскольку препарат приближается к стадии клинических испытаний.
09.04.2026
Внедрение искусственного интеллекта в термоядерную энергетику следующего поколения
28.05.2026
Проработанный у психолога коллега по офису. Почему его хочется сжечь?
23.10.2025Присоединяйтесь и подпишитесь на рассылку самых свежих новостей по Email
Получайте свежие новости и идеи на почту. Без спама — только самое интересное.
Нажимая «Подписаться», вы соглашаетесь с политикой конфиденциальности.
