ESPN'Fastball Freddy' cranks up velocity, shuts down Guardians as Rays even ALCSThe Jerusalem PostThree seriously injured in suspected gas cylinder explosion at Intel chip plant in southern IsraelESPN Deportes¿Cómo al cumplir 18 años cambian los permisos para Gilberto Mora?RTP DesportoMaria Martins conquista medalha de bronzeBollywood HungamaKriti Sanon to headline out-and-out horror project backed by Maddock Films, marking their NINTH collaborationInquirerSpying not ruled out at suspected Pogo hub near military campZDF heuteEntdecken Sie das ZDF-NachrichtenstudioThe IndependentRoyal Mail on ‘brink of collapse’ as 400 staff quitting each week, union warnsSportstarRanji Trophy 2026/27: Assam determinedly holds off Punjab push for outright winRMF24Kreml: Dostawy rosyjskiego diesla do USA otworzą drogę do kolejnych porozumieńtazNach Starlink-Anschlag in Polen: Brand an Starlink-Antennen auch in BulgarienDeadlineMongolian-German Feature ‘Zogsool’ Wins Big At Busan Film Festival’s Vision Awards
The Daily Newsstand · Free, Always
Wednesday, October 14, 2026

Регрессионное тестирование промптов: ИИ-модель в роли читателя пропустила три из четырёх текстов, которые я правил

Translate

Я правлю промпты агентов, которые пишут и проверяют тексты. Чтобы правка не сломала то, что раньше работало, я собрал набор примеров с известным ответом и прогнал по нему проверку, где ИИ-модель играет читателя. Сильно правленые тексты она чаще пропускала, чем возвращала.

В набор вошли тексты двух видов: одни я потом сильно переписывал руками, другие почти не тронул. Если принять правку промпта по такой проверке, брак уйдёт дальше, а проверка будет гореть зелёным.

Из чего собрать набор для тестирования LLM

Регрессионное тестирование промпта — это прогон одних и тех же примеров до правки и после неё: я смотрю, не стало ли хуже там, где раньше было хорошо. Документация Anthropic советует брать примеры из реальных задач и добавлять пограничные входы: пустые данные, слишком длинный ввод, случаи, где расходятся даже люди. OpenAI предлагает запускать оценку на каждое изменение и брать случаи из логов. Hamel Husain пишет, что тесты растут из найденных отказов.

Эталон у меня — судьба текста: насколько опубликованная версия совпадает с той, что выдал агент. Совпадение — доля одинаковых предложений: SequenceMatcher из модуля difflib сравнивает два списка предложений. Балл модели-судьи в эталон я не беру: эталон должен идти от человека. Совпадение ниже 85% значит, что я правил сильно, это плохой пример. Совпадение от 95% и выше — хороший пример. Всё, что между этими порогами, в набор не попадает: ответ по таким текстам неясен.

Схема: правка промпта, прогон набора до и после, счётчики пропущенного брака и ложных тревог, решение принять или откатить

Набор один и тот же, меняется только версия промпта.

Какие две ошибки считать при тестировании ИИ-агентов

Ошибок две, и я считаю их отдельно. Пропущенный брак: плохой пример прошёл проверку. Ложная тревога: хороший пример проверка остановила. Если считать одну общую долю совпадений с человеком, эти ошибки сливаются. Husain приводит расчёт: судья, который пропускает все тексты подряд, при 95% хороших текстов совпадает с человеком в 95% случаев и не находит ни одной ошибки.

Поэтому после прогона у меня два счётчика, и правку промпта я принимаю, только если не вырос ни один из них.

Что показала сверка читателя с моими правками

Я взял 20 материалов, у которых известно совпадение с опубликованной версией, и сравнил его с оценкой читателя. Читатель у меня — три роли, каждая отвечает на четыре вопроса по шкале от 1 до 10. В зачёт идёт минимальная оценка, порог — 7. Автоматическая сводка называет согласием 15 текстов из 20, но пять из них лежат между порогами и без разметки. Среди размеченных читатель сошёлся со мной в 10 случаях: один пойманный брак и девять верно пропущенных хороших текстов. Разошёлся в пяти: три пропущенных брака и две ложные тревоги.

Раздельный счёт даёт два знаменателя. Сильно правленых текстов четыре, и читатель вернул из них один. Совпадение у этих текстов от 64% до 79%. Почти нетронутых одиннадцать, из них он вернул два. Ещё пять текстов попали между порогами и в счёт не пошли.

Две колонки: из 4 сильно правленых текстов читатель вернул 1, из 11 почти нетронутых вернул 2

Брак читатель пропускает чаще, чем ловит: три из четырёх сильно правленых текстов прошли.

Ещё один пропуск, вне этой сводки, я разобрал отдельно. На первом проходе читатели поставили статье минимум 5 и вернули её, после доработки поставили 7 и пропустили. Я забраковал её целиком и переписал от первого абзаца до финала. Причина нашлась в анкете: четыре вопроса оценивают, как написано, а не о чём. Треть текста ушла на разбор метода, и оценки от этого не упали. Вопроса, ради того ли человек открыл статью, в анкете нет. Теперь, если бриф задаёт пропорцию частей, читатель обязан посчитать долю каждой части и назвать её, даже когда все оценки выше порога.

Тот же прогон я делаю при смене ИИ-модели. Перед тем как перевести читателей с Opus на Sonnet, я прогнал Sonnet на 12 версиях текстов, у которых уже были оценки Opus, с теми же ролями и тем же промптом. Оценки совпали в пределах одного балла в 89% случаев. В среднем Sonnet ставит на 0,66 балла ниже. Решение вернуть или пропустить совпало только в 7 версиях из 12. Все расхождения в одну сторону: 5 версий, которые Opus пропустил, Sonnet вернул бы. Читателей я оставил на Opus: на Sonnet возвратов было бы больше, и экономии бы не вышло. Это не противоречит находке про пропуски: более строгий Sonnet вернул бы и хорошие версии, а кто прав в этих пяти, без разметки неизвестно.

Сама проверка тоже ломается. Моя проверка понятности заголовков за одну ночь остановила 4 статьи из 7 (хорошие ли они были, я не размечал): читатель не в теме на каждый вариант заголовка находил новое уточнение, и проверка перестала сходиться. Я выключил её одной константой, а логику и 13 тестов к ней оставил. Тесты по-прежнему требуют отказа на устаревший результат, пустой ответ и неверный JSON.

Скрипт на Python: сравнить две версии проверки на одном наборе

Набор лежит в cases.json: список объектов вида {"text": "...", "bad": true}. Функции before и after принимают текст и возвращают True, если проверка с этой версией промпта его остановила.

import json

def score(flags, cases):
    bad = [c["text"] for c in cases if c["bad"]]
    good = [c["text"] for c in cases if not c["bad"]]
    missed = sum(not flags(t) for t in bad) / max(len(bad), 1)
    alarms = sum(bool(flags(t)) for t in good) / max(len(good), 1)
    return missed, alarms

def compare(before, after, path="cases.json"):
    with open(path, encoding="utf-8") as f:
        cases = json.load(f)
    m0, a0 = score(before, cases)
    m1, a1 = score(after, cases)
    print(f"пропущенный брак: {m0:.0%} -> {m1:.0%}")
    print(f"ложные тревоги:   {a0:.0%} -> {a1:.0%}")
    return "принять" if m1 <= m0 and a1 <= a0 else "откатить"

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

Набор я держу по четырём правилам:

  1. На каждую найденную ошибку добавляю заведомо плохой пример.

  2. Рядом кладу хороший пример, чтобы после правки проверка не начала останавливать живой текст. Так устроены тесты моего детектора стиля ИИ, всего в них 16 проверок. Восемь из них требуют поймать плохой пример, восемь — пропустить хороший. Плохой пример — служебная фраза чат-бота, протёкшая в начало статьи, хороший — цена «1 000 ₽»: проверка ловит в числах узкий неразрывный пробел и не должна путать с ним обычный.

  3. Набор гоняю до и после каждой правки промпта. Отдельно раз в две недели проверяю саму проверку на работоспособность: заведомо плохой пример она обязана поймать.

  4. Оценку модели-судьи сверяю с правками человека и считаю обе ошибки отдельно.

Насколько надёжны числа калибровки читателя

Выборки маленькие: 4 и 11 текстов в разбивке, 12 версий при смене модели, по ним видно устройство счёта, а точность метода из них не оценить. У 18 из 20 текстов оценки ставили прежние роли читателей: набор ролей потом сменился. Эталон — суждение одного человека, меня.

А что служит эталоном в вашем наборе, если плохие примеры вы никогда не правили руками?

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.