Гайд · TNWS AI
Как построить таблицу ошибок AI по меткам без потери неизвестных классов
Группируем ошибки AI-классификации по ожидаемой и фактической метке через Counter и отдельно обнаруживаем неизвестный класс.
Практическая задача
В многоуровневом маршрутизаторе urgent/billing/general узнать не только общий статус, но и какие пары классов чаще путаются на размеченном наборе. В отличие от двоичной confusion matrix здесь хранится конкретная пара expected→actual для каждого несовпадения. Пример содержит три метки и ровно один искусственный конфликт; он демонстрирует структуру отчёта, не заявляет статистику о сервисе. Не превращайте неизвестное значение в general: это нарушение контракта, а не обычная категория. Для содержательного ревью сортируйте реальные пары по частоте и рассматривайте отдельно направления billing→general и general→billing: одинаковая сумма ошибок не означает одинаковые последствия для маршрутизации. В таблицу включайте размер каждого исходного класса, иначе частота ошибки на очень большой категории будет выглядеть более значимой без контекста. Сохраните ID пограничных кейсов для последующего предметного разбора, но не копируйте в отчёт полный текст клиентского сообщения. Этот сценарий применим, когда у команды есть контроль над корпусом AI-приложения и требуется конкретный сигнал о нарушении правила, а не общее впечатление от нескольких ответов. Все входы ниже вымышлены; числовые результаты относятся только к этим примерам.
Документация методов Python и синтаксиса workflow сверена 19.09.2026. Если вы используете другое окружение, проверьте совместимость до копирования команд. Статья не утверждает, что показанный код измеряет качество конкретной модели или заменяет предметную разметку людьми.
Подготовка и проверяемый контракт
Перед запуском запишите, какие данные считаются входом, что является ожидаемым результатом, что именно означает отказ и кому предстоит разбирать расхождение. Для AI-оценки важно отдельно хранить вход, ожидаемую метку и фактический результат: если они смешаны, тест может подтверждать сам себя. Используйте стабильные синтетические ID, чтобы видеть ошибку в журнале, не раскрывая содержимое клиентских обращений.
Сначала прогоните тест на маленьком входе, где правильное поведение известно вручную. Затем внесите одну контролируемую ошибку и убедитесь, что код её замечает. После этого верните корректный набор и только тогда расширяйте проверку до реальных данных. Не переносите демонстрационные численные значения или пороги в производство без отдельного обоснования: они выбраны для наглядности, а не рассчитаны по вашей аудитории.
Вход и ожидаемый результат
Кейс B1 ожидает billing и получает general, U1 остаётся urgent; отчёт содержит пару (billing,general):1 и ID B1. Сконструированный ввод даёт {('billing', 'general'): 1} и список B1. U1 и G1 не входят в таблицу ошибок, поскольку их метки совпали. Перед тем как применять правило к закрытому корпусу, обсудите пограничные случаи, которые могут поменять интерпретацию входа. Запись в документации о границах теста не менее важна, чем зелёный check.
Пошаговые действия
- Создайте
scripts/check.pyв корне репозитория и вставьте код из блока ниже. Он использует названия функций стандартной библиотеки, указанные в официальных ссылках в конце статьи. - Выполните
python scripts/check.pyлокально. Не продолжайте, если уже демонстрационная фикстура даёт иной результат: сначала проверьте копирование кода и кодировку файла. - Запустите скрипт и проверьте пару меток по кейсу B1. Заменяя список rows на выгрузку, сопоставляйте expected и actual по одному стабильному case_id, проверяйте уникальность и наличие всех трёх меток. В итоговом отчёте показывайте сначала размеры по классам, потом пары ошибок и несколько синтетических ID для воспроизведения. Если конфликтов нет, это означает лишь отсутствие обнаруженных ошибок в данном размеченном наборе, не идеальную работу на всех будущих запросах.
- Создайте
.github/workflows/ai-corpus-check.ymlиз YAML-шаблона. Событиеpull_requestполезно для проверки корпуса до слияния; чтение репозитория ограниченоpermissions: contents: read. Скрипт не должен получать ключ внешней модели или реальные секреты. - В разделе Actions откройте job
check, сопоставьте его код завершения с локальным прогоном и зафиксируйте ссылку на проверенный коммит в PR. Не принимайте зелёный результат на старой ревизии за проверку последнего изменения.
# scripts/check.py
from collections import Counter, defaultdict
allowed = {"urgent", "billing", "general"}
rows = [("B1","billing","general"),
("U1","urgent","urgent"),
("G1","general","general")]
counts, examples = Counter(), defaultdict(list)
for case_id, expected, actual in rows:
if expected not in allowed or actual not in allowed:
raise SystemExit("Unknown label: " + case_id)
if expected != actual:
pair = (expected, actual)
counts[pair] += 1
examples[pair].append(case_id)
assert counts[("billing","general")] == 1
print("Demo mismatches:", dict(counts))
print("Case IDs:", dict(examples))
name: AI corpus checks
on:
pull_request:
permissions:
contents: read
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: '3.13'
- run: python scripts/check.py
Ошибки интерпретации и границы
Набор слишком мал для статистического вывода. Если неизвестный actual включить в Counter, может показаться, будто это новый легальный класс; шаблон останавливает расчёт. Проверяйте сам эталон на спорных кейсах. Если вы увеличиваете корпус, добавляйте не только новые примеры, но и отрицательные случаи, на которых тест обязан упасть. Проверяйте, что изменение expected прошло ревью отдельно от изменения кода: иначе можно незаметно изменить правило под текущий ответ системы. Избегайте вывода полного корпуса в CI и не сохраняйте в артефактах ответ закрытой модели без решения о доступе и хранении.
Ошибка выполнения самого Python, нераспознанный формат входа и обнаруженный бизнес-дефект — разные ситуации. В сообщении теста указывайте тип проблемы и безопасный ID. Если тест требует внешний сервис, вынесите его из PR с недоверенным кодом и явно ограничьте доступ к токенам; этот пример намеренно работает локально. Перед публикацией каких-либо результатов опишите методику, размер и происхождение набора, иначе читатель воспримет демонстрационную арифметику как характеристику продукта.
Чек-лист финальной проверки
- Синтетический вход и ожидаемый исход согласованы предметным владельцем.
- Команда
python scripts/check.pyработает локально и в CI на одной версии файлов. - Негативный случай обнаруживается, а не только успешный случай проходит.
- Имена ID и меток уникальны там, где этого требует контракт.
- В репозитории, логах и артефактах нет реальных секретов и приватных текстов.
- Понятно, какой дефект тест находит и каких выводов о качестве AI он не даёт.
- Ссылки на применённые функции и синтаксис workflow перепроверены при переносе.
FAQ
Чем отличается от общей accuracy?
Таблица показывает направление ошибки: какой ожидаемый класс превратился в какой фактический.
Почему неизвестный класс ошибка?
Его нельзя интерпретировать по согласованной схеме маршрутизации.
Зачем ID рядом с парой?
Для воспроизведения и проверки правильности разметки.
Можно ли публиковать эти числа?
Только с описанием реального корпуса и методики; числа в статье относятся к вымышленному примеру.
Что делать после обнаружения сбоя
Сохраните конкретный ID, воспроизведите его на текущей ревизии и отделите ошибку входного корпуса от ошибки функции. Если неверна разметка, исправьте её после предметного ревью; если неверен код, сначала оставьте проваливающийся тест, затем вносите исправление. После зелёного запуска просмотрите соседние случаи с похожими признаками, чтобы локальная правка не изменила другое согласованное поведение. Сохраните версии кода, набора и параметров запуска рядом с выводом: без них сравнивать результаты в будущем нельзя. Не приводите цифру из синтетического примера как измеренный показатель продукта.
Официальные первоисточники
Проверено 19.09.2026: 1, 2, 3, 4. Описание переписано своими словами; изменяемые версии и поля нужно повторно сверять перед дальнейшим использованием.
Читайте также
Как исключить bias из weight decay через Optax
Optax 0.2.6: маска add_decayed_weights применяет decay к kernel и оставляет bias без изменения.
Как использовать Huber loss в Optax для регрессии с выбросами
Optax 0.2.6: Huber loss квадратичен около нуля и линеен после delta; проверяем ошибки 0,5 и 2.
Как использовать sigmoid focal loss в Optax
Optax 0.2.6: focal loss для logits 0 и labels 0/1 при gamma=2; проверка симметричного базового значения.
Комментарии
Пока тихо. Скажите первое слово