Шестнадцать сорок. За окном темно настолько, что двор читается по пятнам фонарей: панельная девятиэтажка напротив, берёзы без листьев, мокрый асфальт. Лампа над столом горит с обеда. В коридоре на табуретке стоит принтер и печатает две страницы: одну мне на стол, вторую в папку — так делают с бумагами, которые собираются хранить.
На странице — сегодняшняя запись о приёмке кадра. Пять полей: стол, попытка, вердикт, идентификатор запуска, отклонения. Сверху время. По ней видно, что произошло в час дня: кадр приняли со второго раза, отклонения перечислены, длинный номер указывает на конкретную картинку.
Чего по ней не видно — чем смотрели. Какая версия листа персонажа лежала перед глазами, какие референсы к нему приложены, каким текстом просили кадр у модели. Ни одного из этих слов на странице нет. Я могла бы сказать, что помню, и это было бы правдой ровно до следующей недели.
Шесть строк, придуманных не нами
Вопрос не мой. Двадцать восьмого октября я читала статью MLflow про стенды оценки, и там вместо принципа — перечень. Чтобы прогон можно было повторить, надо записать шесть вещей: идентификатор задачи, хеш точной версии использованного набора, шаблон промпта дословно, дату оценки, любое зерно случайности и конфигурацию токенизации. Следующая фраза объясняет, зачем: без этих полей «мы прогнали GSM8K и получили 84 %» — не утверждение, которое кто-то может проверить.
Там же — про версии моделей: хранить датированный снимок, а не «GPT-4», потому что провайдеры меняют модель молча. И совет, который читается как правило гигиены: шаблон промпта держать в том же репозитории, что и код, потому что если два шаблона нельзя сравнить, то нельзя объяснить, почему счёт изменился.
Два поля из шести написаны для текстовых прогонов: зерно и токенизация. В кадре на их месте окажутся другие величины, и это отдельный разговор. Остальные четыре применимы буквально. Из этих четырёх у меня есть два: идентификатор запуска и дата.
Номер версии не отвечает за смысл
Дальше начинается то, из-за чего я вообще села это писать. LangSmith версионирует наборы просто: любое добавление, правка или удаление примера создаёт новую версию, версия по умолчанию — время изменения, любую старую можно открыть и увидеть, как набор выглядел тогда. На версию можно повесить метку вроде «прод» и гонять проверку именно по ней.
Langfuse делает то же с элементами набора, и в его документации есть строка, которую я бы поставила в шапку любого шаблона вердикта: «Versioning applies to dataset items only, not dataset schemas». Форму записи можно описать JSON-схемой и отсекать элементы неправильного вида — и при этом смена самой схемы новой версии не создаёт. Меняется форма, номер остаётся.
Вывод, который мне не нравится: номер версии — не доказательство. Доказательство — хеш содержимого вместе с хешем описания проверки. Тогда смена схемы видна как смена хеша, даже если номер не сдвинулся. Номер отвечает на вопрос «когда мы это меняли», хеш — на вопрос «то ли это, что я проверяла».
Что стоит в моей записи
Формат этой записи придумала я, и мне в нём нравилось поле «идентификатор запуска». Оно выглядит как доказательство: длинное, по памяти не наберёшь, и оно указывает на конкретный результат. Но указывает оно на картинку, а не на правило, по которому картинку приняли.
Пересниму кадр завтра с тем же текстом — номер будет другой, вердикт снова скажет «принят», и две записи нельзя будет сравнить между собой. Разница в качестве останется в переписке, а переписка живёт до чистки. Критерии живут у меня в голове — до первого дня, когда я не вспомню, почему вчерашний кадр казался лучше.
Это не упрёк системе, которую строит кто-то другой. Запись веду я, шаблон писала я, и то, что в нём нет версии набора, — моя работа, а не чья-то забывчивость.
Шаблон
Сегодня я перепечатала шаблон. В нём шесть строк: версия набора референсов, хеш этой версии, дословный текст запроса, дата, вердикт и хеш описания проверки. Пять из шести пока пустые, и пустая строка честнее заполненной наугад.
Принтер выдаёт второй экземпляр. В папку пойдёт лист с шестью строками; тот, что с пятью полями, останется на столе.
Второй стакан я поставила, пока печаталось. Он так и стоит пустой.
