Создание конвейера непрерывной оценки
Интегрируйте оценивание по принципу «LLM в роли судьи» в конвейер CI/CD, чтобы перед развёртыванием каждое изменение промпта или модели автоматически проверялось на наборе регрессионных тестов.
«Создание конвейера непрерывной оценки» — бесплатный урок AI Engineering Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Engineering Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Engineering Academy содержит 4 уроков всего.
Почему оценивание должно быть непрерывным
Одного оценивания при развёртывании недостаточно. Качество LLM может незаметно ухудшаться: поставщики моделей обновляют свои модели, изменения системного запроса проходят незамеченными, качество поиска меняется по мере роста корпуса документов, а распределение пользовательских запросов со временем изменяется. Непрерывный конвейер оценивания запускает один и тот же набор проверок при каждом изменении и по расписанию, поэтому ухудшения качества обнаруживаются за часы, а не за недели.
Основные компоненты конвейера
Конвейер непрерывной оценки состоит из пяти компонентов: набора тестовых данных (подобранных вопросов с ожидаемыми ответами), средства запуска системы (вызывает ваш конвейер LLM для каждого тестового вопроса), оценщика (оценивает каждый ответ), хранилища результатов (базы данных или хранилища временных рядов для исторических показателей) и слоя формирования отчётов (панелей мониторинга и оповещений). Каждый компонент можно обновлять независимо от остальных.
# Pipeline architecture:
#
# test_dataset.json
# |
# v
# system_runner.py --> calls your LLM pipeline
# |
# v
# judge.py --> scores each (question, answer) pair
# |
# v
# results_db --> stores timestamped metric history
# |
# v
# dashboard + alert --> Grafana / Slack notificationСтруктура набора тестовых данных
Храните набор данных для оценки в виде версионируемого файла JSON или YAML в вашем репозитории. Каждая запись содержит вопрос, категорию (фактическая, процедурная, вне области задач) и, при необходимости, эталонный ответ. Версионируйте набор тестовых данных отдельно от кода: добавление новых тестовых случаев обратно совместимо, а удаление случаев может скрыть регрессии. Стремитесь собрать от 200 до 500 случаев по всем актуальным категориям.
# eval/test_set_v3.json
# {
# 'version': '3.0',
# 'created': '2026-06-01',
# 'cases': [
# {
# 'id': 'faq_001',
# 'category': 'factual',
# 'question': 'What is the cancellation policy?',
# 'reference': 'Cancellations must be made 24 hours in advance.',
# 'min_correctness': 4
# },
# ...
# ]
# }Запуск набора оценок
Средство запуска оценки обращается к вашей рабочей системе (или к её промежуточной версии) для каждого тестового случая и сохраняет ответ и метаданные. Помечайте каждый запуск оценки уникальным идентификатором запуска, SHA коммита, который его инициировал, временной отметкой и версией набора тестовых данных. Это позволяет точно сравнивать запуски и определять, какое изменение кода вызвало регрессию.
import asyncio
import uuid
from datetime import datetime
async def run_eval_suite(system, test_set: list, commit_sha: str) -> dict:
run_id = str(uuid.uuid4())
results = []
for case in test_set:
response = await system.answer(case['question'])
score = await judge(case['question'], response, case.get('reference'))
results.append({
'run_id': run_id,
'commit_sha': commit_sha,
'case_id': case['id'],
'category': case['category'],
'response': response,
'score': score.model_dump(),
'evaluated_at': datetime.utcnow().isoformat()
})
return {'run_id': run_id, 'results': results}Хранение и запрос исторических показателей
Сохраняйте результат каждого запуска оценки в базе данных. Для этого достаточно простой таблицы eval_results с полями run_id, commit_sha, case_id и score. Выполняйте запросы агрегированных оценок по run_id, чтобы вычислять показатели для каждого запуска. Сравнивайте текущий запуск с последним успешным запуском в основной ветке, чтобы обнаруживать регрессии. База данных временных рядов, например InfluxDB, хорошо подходит для непрерывного мониторинга.
-- PostgreSQL schema
CREATE TABLE eval_runs (
run_id UUID PRIMARY KEY,
commit_sha TEXT NOT NULL,
test_set_version TEXT NOT NULL,
triggered_by TEXT, -- 'ci', 'scheduled', 'manual'
started_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE eval_results (
id SERIAL PRIMARY KEY,
run_id UUID REFERENCES eval_runs(run_id),
case_id TEXT NOT NULL,
category TEXT,
correctness INT,
overall INT,
response TEXT
);
CREATE INDEX idx_run_id ON eval_results(run_id);Автоматическое обнаружение регрессий
После каждого запуска оценки сравнивайте агрегированные оценки с базовой линией (последним запуском из основной ветки, одобренным вручную). Регрессия определяется так: любое измерение оценки снизилось более чем на 5% относительно базовой линии или средняя оценка любой категории опустилась ниже установленного минимума. Регрессии должны блокировать развёртывание и отправлять оповещение команде. Улучшения можно одобрять автоматически.
def detect_regression(current: dict, baseline: dict, threshold_pct: float = 5.0) -> dict:
regressions = []
for metric in ['correctness', 'helpfulness', 'clarity']:
delta_pct = (current[metric] - baseline[metric]) / baseline[metric] * 100
if delta_pct < -threshold_pct:
regressions.append({
'metric': metric,
'baseline': baseline[metric],
'current': current[metric],
'delta_pct': round(delta_pct, 1)
})
return {'has_regression': len(regressions) > 0, 'regressions': regressions}Интеграция с CI/CD
Добавьте набор оценок как шаг CI, выполняемый для каждого запроса на слияние. Конвейер CI вызывает вашу промежуточную систему, запускает оценщик, сохраняет результаты и проверяет наличие регрессий. Если обнаружена регрессия, шаг CI завершается с ошибкой и блокирует слияние PR. Добавьте эту проверку как обязательную проверку статуса в GitHub или GitLab, чтобы никто не мог её обойти. Сократите время запуска оценки до менее чем 10 минут, используя для проверок PR подмножество из 50–100 случаев.
# .github/workflows/eval.yml
# name: LLM Quality Evaluation
# on: [pull_request]
# jobs:
# eval:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - name: Run eval suite
# run: python eval/run_suite.py --commit $GITHUB_SHA --mode pr
# env:
# OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
# - name: Check for regressions
# run: python eval/check_regression.py --run-id $EVAL_RUN_IDЗапланированные полные запуски оценки
Помимо проверок PR, ежедневно запускайте полный набор оценок (все 300 и более случаев) в рабочей среде. Это помогает обнаружить постепенное ухудшение качества, которое не вызывается каким-либо отдельным изменением, например если полнота поиска в векторной базе данных снижается по мере добавления документов или поставщик LLM незаметно обновляет свою модель. Ежедневные полные запуски формируют временной ряд качества, благодаря которому становятся видны тенденции.
# Separate eval modes:
EVAL_CONFIGS = {
'pr_check': {
'test_cases': 'eval/test_set_core_100.json',
'target': 'staging',
'max_runtime_min': 8
},
'nightly': {
'test_cases': 'eval/test_set_full_350.json',
'target': 'production',
'max_runtime_min': 30
},
'weekly_deep': {
'test_cases': 'eval/test_set_full_350.json',
'target': 'production',
'include_pairwise': True,
'max_runtime_min': 90
}
}Оповещения об ухудшении качества
Настройте оповещения, когда тенденции показателей пересекают пороги предупреждения и критический порог. Снижение средней корректности на 3% за последние 7 дней должно вызывать предупреждение. Снижение на 10% за один запуск должно немедленно вызывать оповещение. Направляйте предупреждения в командный канал Slack, а критические оповещения — в PagerDuty. В каждое сообщение об оповещении включайте анализ регрессии, ссылку на панель оценки и сведения git blame о последних изменениях.
import httpx
def send_regression_alert(regression_report: dict, webhook_url: str):
regressions = regression_report['regressions']
blocks = [{
'type': 'section',
'text': {'type': 'mrkdwn', 'text': '*LLM Quality Regression Detected*'}
}]
for r in regressions:
blocks.append({
'type': 'section',
'text': {'type': 'mrkdwn',
'text': f'*{r["metric"]}*: {r["baseline"]} -> {r["current"]} ({r["delta_pct"]}%)'}
})
httpx.post(webhook_url, json={'blocks': blocks})Расширение набора тестовых данных
Непрерывно расширяйте набор тестовых данных на основе реальных сбоев в рабочей среде. Когда пользователь сообщает о плохом ответе, добавляйте этот вопрос (при необходимости анонимизированный) в набор тестовых данных вместе с ожидаемым ответом, проверенным человеком. Это позволяет набору оценок отражать реальные потребности пользователей, а не гипотетические случаи. Считайте набор тестовых данных живым документом и ежеквартально пересматривайте его, удаляя устаревшие случаи.
def add_to_test_set(question: str, reference_answer: str, category: str,
source: str, test_set_path: str):
import json, uuid
with open(test_set_path, 'r') as f:
test_set = json.load(f)
test_set['cases'].append({
'id': f'user_report_{uuid.uuid4().hex[:8]}',
'category': category,
'question': question,
'reference': reference_answer,
'source': source, # 'user_report', 'regression', 'manual'
'added': '2026-06-21'
})
with open(test_set_path, 'w') as f:
json.dump(test_set, f, indent=2)Визуализация тенденций качества во времени
Создайте простую панель качества, на которой ключевые показатели отображаются во времени: средняя оценка корректности, доля попаданий в кэш, задержка p95 и стоимость запроса. Используйте недельное скользящее среднее, чтобы сгладить шум, вызванный небольшими объёмами выборки. График тенденций сразу показывает постепенное ухудшение качества: снижение на 3% за шесть недель незаметно в отдельных отчётах о запусках, но очевидно на графике временного ряда. Для этого хорошо подойдут Grafana или даже простой скрипт Python с matplotlib.
import matplotlib.pyplot as plt
import pandas as pd
def plot_quality_trend(eval_history: list):
df = pd.DataFrame(eval_history)
df['date'] = pd.to_datetime(df['evaluated_at'])
df = df.sort_values('date')
# 7-day rolling average
df['score_ma7'] = df['mean_correctness'].rolling(window=7).mean()
plt.figure(figsize=(12, 4))
plt.plot(df['date'], df['mean_correctness'], alpha=0.3, label='Daily')
plt.plot(df['date'], df['score_ma7'], label='7-day avg', linewidth=2)
plt.axhline(y=4.0, color='r', linestyle='--', label='Min threshold')
plt.legend()
plt.title('LLM Answer Quality Over Time')
plt.savefig('quality_trend.png')Быстрая проверка
Проверьте, насколько хорошо вы понимаете конвейеры непрерывной оценки для приложений на основе LLM.
Итоги урока
В этом уроке вы узнали, что конвейеры непрерывной оценки выполняют автоматические проверки качества для каждого PR и ежедневно, чтобы заранее обнаруживать регрессии; обнаружение регрессий сравнивает текущие оценки с базовой линией и блокирует развёртывание при снижении качества; а расширение набора тестовых данных на основе реальных сбоев позволяет набору оценок опираться на реальные потребности пользователей. Далее мы классифицируем режимы сбоев агентов и спроектируем стратегии восстановления.
Изучай Python с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 30
- Уроки
- 120
Часто задаваемые вопросы
Урок «Создание конвейера непрерывной оценки» бесплатный?
Да — полный текст урока «Создание конвейера непрерывной оценки» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Engineering Academy, подпишись на CoddyKit PRO. Курс AI Engineering Academy содержит 4 уроков всего.
Чему я научусь в уроке «Создание конвейера непрерывной оценки»?
Интегрируйте оценивание по принципу «LLM в роли судьи» в конвейер CI/CD, чтобы перед развёртыванием каждое изменение промпта или модели автоматически проверялось на наборе регрессионных тестов. Ты практикуешь AI Engineering Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать AI Engineering Academy?
Предыдущий опыт не требуется. AI Engineering Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Создание конвейера непрерывной оценки»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке AI Engineering Academy?
Да. Каждый урок AI Engineering Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Шаблон «LLM в роли судьи»
- Поточечная и попарная оценка
- Калибровка моделей-судей по оценкам людей
- Создание конвейера непрерывной оценки