Зміна в prompt може покращити JSON і зламати зміст. Модель повертає category, але губить примітку клієнта. Тому тестування AI автоматизацій має перевіряти формат і бізнес-правила.

Тестування AI-автоматизацій: контрольні кейси, pass/fail і виявлення регресії
Тестування AI-автоматизацій: контрольні кейси, pass/fail і виявлення регресії

Мінімальний LLM eval — це набір кейсів, версія prompt і моделі, автоматичні перевірки, ручна rubric та regression report. Він доповнює AI-автоматизацію роботи з клієнтом: перед production треба довести, що оновлення не погіршило результат.

Чому один вдалий prompt нічого не доводить

Демонстрація показує, чи може модель виконати задачу. Бізнесу важлива робота на звичайних, граничних і помилкових даних. Замість точного збігу всього тексту перевіряйте JSON, поля, правила, повноту й корисність.

OpenAI evaluation best practices рекомендує прив'язувати evals до конкретної задачі й реальних даних. Для запуску фіксуйте prompt_version, model, версію dataset, pass/fail та причини.

Як зібрати набір контрольних прикладів

Набір звичайних, граничних і помилкових кейсів для перевірки AI-моделі
Набір звичайних, граничних і помилкових кейсів для перевірки AI-моделі

Почніть із 10–30 сценаріїв: звичайний запит, порожній текст, змішані наміри й помилковий input. Production-дані маскуйте за правилами CRM-автоматизації.

Мінімальна структура кейсу:

export const evalCases = [
  {
    case_id: "support-001",
    input: "Не можу увійти в кабінет після зміни пароля",
    expected_fields: ["category", "summary", "needs_human"],
    expected_category: "access_problem",
    forbidden_claims: ["акаунт заблоковано назавжди"],
    critical_rules: { needs_human: false },
    status: "active"
  },
  {
    case_id: "support-002",
    input: "",
    expected_fields: ["category", "summary", "needs_human"],
    expected_category: "invalid_input",
    forbidden_claims: [],
    critical_rules: { needs_human: true }
  }
];

Не копіюйте повні email, телефони й листування. Dataset розділяйте за задачами. Для внутрішнього RAG-бота перевіряють також джерело й відмову без контексту.

Автоматична перевірка JSON

Валідація структури JSON відокремлює коректні відповіді від помилкових
Валідація структури JSON відокремлює коректні відповіді від помилкових

Перший рівень — чи можна розібрати JSON і чи відповідає він контракту. У Node.js для цього зручно використати Ajv.

import Ajv from "ajv";

const ajv = new Ajv({ allErrors: true });
const schema = {
  type: "object",
  additionalProperties: false,
  required: ["category", "summary", "needs_human"],
  properties: {
    category: {
      enum: ["access_problem", "billing", "other", "invalid_input"]
    },
    summary: { type: "string", maxLength: 240 },
    needs_human: { type: "boolean" }
  }
};

const validate = ajv.compile(schema);

export function validateJsonSchema(rawResult) {
  try {
    const result = typeof rawResult === "string" ? JSON.parse(rawResult) : rawResult;

    const valid = validate(result);
    return {
      pass: valid,
      result,
      reasons: valid ? [] : validate.errors.map(error =>
        `${error.instancePath || "/"} ${error.message}`)
    };
  } catch (error) {
    return { pass: false, result: null, reasons: ["invalid_json"] };
  }
}

Schema не доводить правдивість відповіді, а лише гарантує структуру. Поля required та additionalProperties описані в JSON Schema reference.

Як перевірити критичні бізнес-правила

Після схеми перевірте правила процесу: категорію, заборонені твердження й передачу людині.

export function checkCriticalRules(result, testCase) {
  const reasons = [];

  if (result.category !== testCase.expected_category) {
    reasons.push(`category:${result.category}`);
  }

  for (const claim of testCase.forbidden_claims || []) {
    if (result.summary.toLowerCase().includes(claim.toLowerCase())) {
      reasons.push(`forbidden_claim:${claim}`);
    }
  }

  const expected = testCase.critical_rules?.needs_human;
  if (typeof expected === "boolean" && result.needs_human !== expected) {
    reasons.push("needs_human_mismatch");
  }

  return { pass: reasons.length === 0, reasons };
}

Інша LLM може бути додатковим grader, але не єдиним суддею для платежів чи передачі заявки менеджеру.

Regression report після зміни prompt

Порівняння baseline і нової версії prompt показує один регресійний кейс
Порівняння baseline і нової версії prompt показує один регресійний кейс

Regression testing LLM — повторний запуск того самого набору після зміни prompt, моделі або input. Результат порівнюють із дозволеним baseline.

export async function runPromptRegression({
  promptVersion,
  model,
  evalCases,
  callModel
}) {
  const rows = [];

  for (const testCase of evalCases.filter(c => c.status === "active")) {
    const raw = await callModel({ promptVersion, model, input: testCase.input });

    const schemaCheck = validateJsonSchema(raw);
    const ruleCheck = schemaCheck.pass
      ? checkCriticalRules(schemaCheck.result, testCase) : { reasons: [] };

    const reasons = [...schemaCheck.reasons, ...ruleCheck.reasons];
    rows.push({
      run_at: new Date().toISOString(),
      case_id: testCase.case_id,
      prompt_version: promptVersion,
      model,
      status: reasons.length ? "failed" : "passed",
      reasons,
      output: schemaCheck.result
    });
  }

  return rows;
}

Показуйте кейси, що погіршилися проти baseline: одна критична помилка важливіша за дев'ять простих успіхів. Regression запускайте окремою задачею через контрольований Apps Script webhook-сервер.

Ручна оцінка змісту

Людина перевіряє сумнівні та невдалі AI-відповіді в review queue
Людина перевіряє сумнівні та невдалі AI-відповіді в review queue

Автотести ловлять зламаний JSON і чіткі порушення. Повноту, корисність та вигадані деталі оцінює людина.

Для ручної перевірки використовуйте rubric від 0 до 2:

Критерій012
Точністьє помилкичастково правильнофакти коректні
Повнотапропущено критичнебракує деталейпотрібне враховано
Вигадані фактиєсумнівне формулюваннянемає
Корисністьне допомагаєпотрібна доробкаможна використати
Форматзламанийдрібні відхиленняконтракт виконано

Failed і borderline потрапляють у review queue. Людина записує score, коментар і рішення: дозволити версію, доопрацювати prompt або розширити dataset.

Як записати pass/fail у Google Sheets

Для невеликої команди Google Sheets достатньо як реєстру. Sheets API додає рядки через spreadsheets.values.append.

import { google } from "googleapis";

export async function appendRegressionReport({
  auth,
  spreadsheetId,
  rows
}) {
  const sheets = google.sheets({ version: "v4", auth });
  const values = rows.map(row => [
    row.run_at,
    row.case_id,
    row.prompt_version,
    row.model,
    row.status,
    row.reasons.join("; "),
    row.status === "failed" ? "review" : ""
  ]);

  return sheets.spreadsheets.values.append({
    spreadsheetId,
    range: "EvalRuns!A:G",
    valueInputOption: "RAW",
    insertDataOption: "INSERT_ROWS",
    requestBody: { values }
  });
}

Не пишіть у лог повний input/output із PII. Зберігайте масковані дані, hash або захищене посилання.

Як десять контрольних кейсів зупинили невдале оновлення prompt

У робочому сценарії модель перетворювала звернення на JSON. Нова інструкція виправила категорії, і на демонстрації версія виглядала кращою. Але у двох із десяти кейсів зникла примітка для передачі людині: JSON був валідним, а needs_human помилково став false.

Critical rules позначили кейси як failed, тому prompt не потрапив у production. Після виправлення ми повторили набір і додали ці сценарії до baseline. Регресію знайшли до обробки всієї таблиці.

Практичний підсумок

AI quality control починається з evaluation dataset і чітких критеріїв. JSON Schema та критичні правила перевіряйте автоматично, зміст — за rubric, а сумнівні відповіді віддавайте людині.

Фіксуйте prompt_version, model і baseline. Regression report перетворює суб'єктивне «подобається» на керований процес.