Хватит оценивать AI на глаз. Считайте, сколько за ним правит человек
Большинство AI-фич оценивают по демо и ощущениям. Я смотрю на одно: сколько человек меняет в ответе модели, прежде чем его отправить. Рассказываю, как это собирать, считать и использовать для выбора моделей и prompt.
Pavel Duglas
AI Automation & MVP Architect
Каждая AI-фича, которую я запускал, на демо выглядела отлично. Потом приходили живые пользователи, и вопрос менялся с “хороший ли ответ?” на “сколько времени человек потратил, чтобы его исправить?”. В деньги конвертируется только второй вопрос. Если оператор поддержки переписывает 70% каждого черновика, ваша фича - это просто медленный способ набирать текст. Если после парсера в каждой записи надо поправить два поля, ваша автоматизация - это ручной ввод данных с лишними шагами.
Поэтому во всех системах, где человек проверяет результат AI, я упрямо логирую одну вещь: разницу между тем, что выдала модель, и тем, что человек в итоге отправил. Я называю это correction burden, по-русски пусть будет “нагрузка на правки”. Эта метрика вытеснила у меня почти все остальные метрики качества.
Почему привычные метрики врут
У стандартных способов оценки AI один общий изъян: они меряют что-то рядом с ценностью, но не саму ценность.
- Ручные выборочные проверки показывают то, что вы случайно заметили во вторник после обеда. Они не масштабируются и плавают вместе с вашим настроением.
- LLM-as-judge полезен для регрессионных тестов, но судья спокойно ставит 8 из 10 гладкому ответу, который эксперт в предметной области выбросит за две секунды.
- Кнопки лайк/дизлайк нажимают от силы 2% пользователей, и в основном тогда, когда они злы.
- “Точность” на тестовом наборе застывает во времени. Входные данные на третьем месяце не имеют ничего общего с теми 50 примерами, которые вы написали на первой неделе.
Нагрузка на правки устроена иначе. Это побочный продукт работы, которую люди и так делают. Вы никого не просите ничего оценивать, вы просто смотрите, что они меняют.
Что сохранять
Вся идея держится на том, что вы храните две версии каждого результата: черновик модели и финал от человека. Большинство систем выбрасывают черновик в ту секунду, когда пользователь начинает его редактировать. Вот это и есть ошибка.
Минимальная запись, которую я держу:
CREATE TABLE ai_outputs (
id uuid PRIMARY KEY,
task_type text NOT NULL, -- 'reply_draft', 'invoice_extract', ...
customer_id uuid,
build_id text NOT NULL, -- версия prompt + модели + инструментов
input_hash text NOT NULL,
draft jsonb NOT NULL, -- что выдала модель
final jsonb, -- что отправил человек
outcome text, -- 'accepted', 'edited', 'rejected', 'abandoned'
shown_at timestamptz NOT NULL,
resolved_at timestamptz
);
Четыре детали здесь важнее, чем кажутся:
build_idпривязывает каждый результат к конкретному prompt, модели и набору инструментов. Без него нагрузку посчитать можно, а объяснить нельзя.outcomeотделяет “отредактировал” от “отклонил”. Человек, который стёр черновик и написал всё с нуля, и человек, который поправил опечатку, дают совершенно разный сигнал.shown_atиresolved_atдают время до принятия. Оно ловит ситуации, когда текст почти не изменился, но человек четыре минуты его перепроверял.abandoned- отдельное состояние. Если люди открывают черновик и уходят, это провал, который никакой diff не покажет.
Какие метрики я считаю
Из этой таблицы я вывожу небольшой набор цифр: по типу задачи, по сборке и по сегменту клиентов.
Доля принятых без правок
Это accept-as-is rate: процент результатов, отправленных без существенных изменений. Главная цифра на дашборде. У бота, который готовил черновики ответов для поддержки в Telegram, она стартовала с 18% и за шесть недель выросла до 61%. Почти весь рост дали изменения в prompt, которые я делал, глядя на реальные правки операторов.
Нормализованное расстояние редактирования
Для свободного текста я считаю расстояние между черновиком и финалом на уровне токенов и делю на длину более длинного варианта. Посимвольный diff слишком остро реагирует на переформатирование, поэтому сначала я нормализую пробелы и регистр.
import difflib, re
def normalize(text: str) -> list[str]:
text = re.sub(r"\s+", " ", text.strip().lower())
return re.findall(r"\w+|[^\w\s]", text)
def edit_burden(draft: str, final: str) -> float:
a, b = normalize(draft), normalize(final)
if not a and not b:
return 0.0
ratio = difflib.SequenceMatcher(None, a, b).ratio()
return round(1 - ratio, 3) # 0 = не трогали, 1 = переписали полностью
С академической точки зрения это не идеально. И не нужно. Метрика стабильная, дешёвая и достаточно точная, чтобы сравнивать сборки между собой.
Доля исправлений по полям
Для структурированного вывода текстовое расстояние не подходит. Если парсер вытаскивает данные из счетов в JSON, я сравниваю поле за полем и считаю, какие поля люди исправили.
def field_corrections(draft: dict, final: dict) -> dict[str, bool]:
keys = set(draft) | set(final)
return {k: draft.get(k) != final.get(k) for k in keys}
После агрегации получается картина вроде: vendor_name правят в 3% случаев, due_date в 22%, tax_amount в 9%. Сразу видно, куда тратить силы. По моему опыту, почти всегда проблема в датах, валютах и всём, что связано с часовыми поясами, а вовсе не в “сложных” смысловых полях.
Время до принятия
Медиана секунд между показом результата и его закрытием. Если доля принятых без правок высокая, а время до принятия тоже высокое, значит, пользователи не доверяют модели и читают каждую строчку. Это проблема доверия, и лечится она чаще показом источников или уверенности модели, а не заменой модели.
Как принимать решения по этим цифрам
Собирать метрики бессмысленно, если они не меняют то, что вы выкатываете. Вот где нагрузка на правки себя окупает.
Выбор модели по цене полезного результата
Вечный спор “брать ли дорогую модель?” превращается в арифметику. Допустим, дорогая модель стоит $0.02 за черновик при средней нагрузке 12%, а дешёвая $0.002 при 19%. Проверяющий обходится в $30 в час, и каждый пункт нагрузки добавляет примерно 3 секунды редактирования. Лишние 7 пунктов - это около 21 секунды, то есть $0.17 человеческого времени на каждый черновик. Дорогая модель выигрывает с огромным отрывом.
А теперь обратная ситуация: пакетное извлечение данных, где 95% записей никто не проверяет. Нагрузка важна только на проверяемой части, и выигрывает дешёвая модель. Метрика та же, ответ противоположный, и ни один из них не гадание.
Сравнение версий prompt без споров
Поскольку у каждой строки есть build_id, я раскатываю новый prompt на 20% трафика и через несколько сотен результатов сравниваю нагрузку. Никаких “мне кажется, новый лучше”. Если нагрузка не снизилась, изменение не идёт в прод. Так погибло немало моих собственных хитрых идей для prompt, и именно в этом смысл.
Поиск сегментов, где всё ломается
Средние значения прячут боль. Я всегда режу нагрузку по клиентам, языку и источнику входных данных. На одном проекте общая доля принятых без правок выглядела прилично, 55%. А для сообщений на казахском она была 9%. Никто не жаловался, потому что эти пользователи просто тихо перестали пользоваться фичей.
Правки как бесплатная разметка
Самая недооценённая часть всей схемы: каждая правка человека - это готовый размеченный пример. Черновик - неправильный ответ, финал - правильный, и вы не заплатили за разметку ни копейки.
Что я с этим делаю:
- Пополняю регрессионный набор. Каждую неделю беру 20 результатов с самой высокой нагрузкой и добавляю их вход и финал человека в eval. Тестовый набор растёт в сторону реальных провалов, а не моих фантазий о них.
- Достаю few-shot примеры. Пары “черновик и правка” отлично работают как примеры в prompt, особенно для тона и форматирования, которые сложно описать словами.
- Нахожу новые типы ошибок. Когда целая группа правок делает одно и то же, например убирает приветствие или меняет знак валюты, это правило, которое надо записать в prompt, а не повод менять модель.
Грабли
Метрика не свободна от шума. Вот на что я наступал сам.
Штамповка. Некоторые проверяющие принимают всё подряд, потому что заняты. У них нагрузка нулевая и ничего не значит. Я отслеживаю долю принятия по каждому проверяющему и отношусь с подозрением к любому, у кого 99%. Несколько случайных аудитов в неделю держат цифры честными.
Косметические правки. Люди по привычке меняют “Добрый день” на “Здравствуйте”. Нормализация помогает, а для текста я игнорирую правки ниже небольшого порога, примерно 0.03, когда считаю долю принятых без правок.
Молчаливый отказ. Если интерфейс позволяет проигнорировать черновик и писать в отдельном поле, вы никогда не увидите отказ. Стройте флоу так, чтобы черновик был отправной точкой финала, или хотя бы логируйте, когда его отбрасывают.
Персональные данные. Вы храните тексты, написанные людьми, и в них бывает больше чувствительной информации, чем в черновиках. Применяйте те же правила хранения и доступа, что и к остальным клиентским данным, и не отправляйте финалы в сторонний eval-сервис, не подумав.
Закон Гудхарта. Если команду премируют за низкую нагрузку, рано или поздно кто-то начнёт меньше править. Держите это продуктовой метрикой, а не KPI для оценки сотрудников.
С чего начать на этой неделе
Платформа не нужна. Для любой существующей AI-фичи с шагом проверки:
- Перестаньте перезаписывать черновик. Храните его рядом с финалом.
- Добавьте
build_idиoutcomeв каждую запись. - Возьмите две функции выше и запускайте их по ночам.
- Выведите долю принятых без правок и медианную нагрузку по типам задач на один дашборд.
- Каждую пятницу доставайте 20 худших примеров и читайте их глазами.
В последнем пункте и сидит основная ценность. Дашборд говорит, что что-то не так. Худшие 20 примеров говорят, что именно. Через месяц вы будете знать о своей AI-фиче больше, чем покажет любой бенчмарк, а у каждого решения про модели, prompt и расходы будет цифра вместо ощущения.
Вопросы и ответы
Что делать, если в моей AI-фиче нет шага ручной проверки?
Тогда прямой нагрузки на правки у вас нет, но можно сделать выборочную проверку: отправлять 2-5% результатов человеку на ревью через тот же интерфейс с сохранением черновика и финала. Этого хватает, чтобы сравнивать сборки. Параллельно смотрите на косвенные сигналы: повторные запросы, ручные откаты, обращения в поддержку по конкретным результатам.
Сколько данных нужно, чтобы честно сравнить две версии prompt?
Для одного типа задачи мне обычно хватает 200-400 результатов на каждую версию, если разница заметная, от 5 пунктов нагрузки и выше. Для мелких улучшений нужно больше, и тут полезно смотреть не только на среднее, но и на долю принятых без правок. Главное - сравнивать версии на одном и том же периоде и одном сегменте трафика, а не "старую в прошлом месяце и новую сейчас".
Можно ли заменить нагрузку на правки оценкой через LLM-as-judge?
Нет, это разные инструменты. LLM-as-judge хорош как быстрый регрессионный тест перед деплоем, когда живых правок ещё нет. Но он оценивает правдоподобие ответа, а не то, сколько времени человек потратит на его исправление. Я использую судью как фильтр до выката, а нагрузку на правки как финальную правду после.
Похожие статьи
Сделаю под ключ
Соберу ИИ-агента под реальную задачу
С инструментами, памятью и логами, чтобы он работал в проде, а не только в демо.
от 1 500 $ · 1-2 недели