SOBHard измеряет структурированный вывод между машинными нотациями. Модель получает настоящий документ — иногда два — и должна выдать документ в другой нотации, упакованный ровно так, как требует промпт.
825 вопросов на русском языке: 11 семейств работ × 3 уровня сложности × 25 вопросов в клетке. Эта сетка — единственная ось, выровненная точно; нотации, длины и корпус не выровнены намеренно, см. «Где баланс есть, а где нет». Пятнадцать нотаций-источников (, csv, fwf, html, ini, json, jsonc, jsonl, logline, mdtable, properties, scsv, toml, tsv, xml) и шесть целевых (yaml, json, jsonl, yaml, toml, SQL properties).
INSERT
| Семейство | Что требуется |
|---|---|
| convert | тот же документ в другой нотации, данные без изменений |
| extract | собрать значения по перечисленным путям в один объект |
| repair | починить сломанный документ, затем переписать его по правилу |
| transform | переписать документ по правилу из нескольких шагов подряд |
| schema_gen | схема в стиле draft-07 для того, во что документ превратится после правила |
| patch | применить нумерованный список операций set / delete / insert |
| diff | различия двух версий объектом added / removed / changed |
| apply_diff | применить такой объект изменений к версии 1 |
| merge | соединить два источника по заданному ключу |
| template | развернуть по строке на запись по текстовому шаблону |
| session | цепочка шагов, растянутая на несколько ходов разговора |
Сложность — это длина плюс композиция: лёгкий вопрос — одна операция над примерно 7 000 символов, тяжёлый — цепочка шагов над 16 500. Почти половина исходников переваливает за 12 000 символов, самый длинный — за 62 741; чуть больше чем в четверти вопросов ответ длиннее исходника.
Ни одна проверка не выполняется моделью-судьёй. Каждое требование промпта проверяется отдельным детерминированным верификатором — 31 ограничение в четырёх слоях: упаковка (4), разбор целевой нотации (1), сверка значений (3), семантика самого семейства (23). Конвенция чтения каждой нотации написана в промпте, поэтому знание чужих стандартов не требуется, а прогон воспроизводится точно.
У девяти вопросов из 825 эталонный ответ дословно содержится во входном документе: это вопросы, где корректное действие — вернуть уже правильный фрагмент без изменений. Такие вопросы намеренно оставлены в наборе: они проверяют, что модель не ломает валидные данные.
Проверяемые навыки: Structured output, Format conversion, Format control, Instruction following, Long-form exact generation
Авторы: Артем Червяков
Для кого. Для инструктивных моделей, которые ставят в конвейер обработки данных, и для тех, кто решает, можно ли поставить модель между двумя системами, где формат нарушать нельзя. Такой читатель понимает как долю документов, которые пройдут дальше по конвейеру без ручной правки, а sample_pass_rate — как ответ на другой вопрос: есть ли класс работ, который модель не умеет совсем. Базовым моделям и моделям с коротким контекстом набор не подходит.
balance_score
Что оценивает. Не понимание текста, а удержание структуры при переписывании: прочитать документ по объявленной конвенции, применить объявленную операцию, выписать результат в другой нотации целиком и без единого расхождения. Композиция и удержание промежуточного состояния между ходами оцениваются отдельно. Поскольку ответ — целый документ, оценка не сводится к угадыванию: ошибка в одном значении из тысячи видна и названа, а обходные пути набирают ровно ноль — вернуть вход, выдать пустой документ, бросить цепочку на полпути.
Почему головных метрик две. Первая бинарна по вопросу: документ, нарушающий хотя бы одно правило, дальше не годится, поэтому частичный зачёт вводил бы в заблуждение. Но арифметическое среднее не отличает ровную модель от неровной, а для конвейера это разные вещи — отсюда геометрическое среднее по клеткам, которое штрафует за провал целого класса работ.
Сплитов два, и делятся они по роли, а не по размеру. В лежат 825 оцениваемых вопросов. В test — 203 строки, которые можно показывать вместе с ответами: десять демонстраций и 193 ранних хода 75 разговоров. Их ответы и есть та история, которую продолжает оцениваемый ход.
shots
Точно выровнена одна ось, остальные — нет. Считать долю по невыровненной оси нормально там, где уровень большой, и обманчиво там, где он мал, поэтому вот числа.
Точно. Семейство × сложность: 33 клетки ровно по 25 вопросов, по 275 на уровень сложности. Именно по этой сетке усредняется , и это единственный срез, где клетки можно сравнивать друг с другом напрямую.
balance_score
Ровно с точностью до вопроса. Речевой регистр: пять регистров, и в 30 клетках из 33 каждый встречается ровно пять раз. Три клетки неровные — от четырёх до шести на регистр, — потому что разговор говорит одним голосом, регистр принадлежит всей цепочке, а 25 ходов клетки складываются из 25 цепочек разной длины. По всему сплиту пять регистров дают от 164 до 167.
session
Неровно намеренно. Длина документа, потому что длина — это половина того, что здесь значит сложность: 50 коротких, 275 средних, 500 длинных, и смесь меняется с уровнем — на лёгком 50/145/80, на среднем 0/100/175, на тяжёлом 0/30/245. Средний вход растёт с 9 700 до 14 000 и 17 200 знаков.
Неровно, и выравнивать нечего. Нотации идут за тем, что может дать корпус:
| больше всего | меньше всего | |
|---|---|---|
| источник | yaml 153, json 134, jsonl 88 | ini 8, properties 4 |
| цель | yaml 273, json 242, jsonl 157 | SQL INSERT 37, properties 3 |
Доля по как цели считается по трём вопросам и не значит ничего; properties и ini как источники — немногим больше. Корпус неровен так же: 114 файлов, медиана пять вопросов на файл, и одна таблица стоит за 93 из них.
properties
instruction [str] — шаблон промпта с местами для вставки частей вопросаinputs [dict] — четыре блока промпта: task (что за работа и в каких нотациях), input_data (исходный документ или два под фиксированными метками), format (требования к упаковке и правила сверки), question (конкретная инструкция)
outputs [str] — эталонный ответ в блоке кода с нужным тегом. Заполнен в. shots, у оцениваемых строк пуст
meta [dict] — id и base_id; fence_tag, тег, который должен нести блок ответа; reference, эталонный документ сырым текстом — скоринг читает эталон отсюда, а не из outputs — и его reference_sha256; task_meta и checks, JSON-строки с параметрами самого вопроса и каноническими структурами, из которых верификаторы выводят ответ; dialogue_id, turn_index, n_turns — координаты хода в разговоре и null в остальных случаях; и categories — семейство, сложность, язык, нотации источника и цели, длина, речевой регистр, файл корпуса
Четыре блока с текстовыми метками, всегда в одном порядке, инструкция последняя:
Задача:
<что за работа и в каких нотациях>
Входные данные:
<исходный документ>
Формат ответа:
<требования к упаковке и правила сверки>
Инструкция:
<конкретное задание>
20 шаблонов: пять речевых регистров — , casual, request, spec, formal — по четыре редакции каждый. Как они распределены — в разделе «Где баланс есть, а где нет».
command
Семейство — 75 разговоров на 268 ходов: тридцать шесть по три хода, тридцать пять по четыре, четыре по пять. Первый ход показывает документ, каждый следующий работает над результатом предыдущего, который в промпте не повторяется.
session
Оценивается один ход разговора, и это последний. Это не выбор, а следствие: состояние, с которого ход начинает, — это ответ на предыдущий ход, поэтому оценить два хода одного разговора значило бы опубликовать ответ на один из них. 193 ранних хода лежат в вместе с ответами, и few-shot-сэмплер воспроизводит их как историю оцениваемого хода.
shots
Под многоходовостью ход (turn) — обычный вопрос обычного семейства: 165 ходов из 268 — работа , 103 — patch, — и проверяется ограничениями этого семейства плюс одним: ответ, который лишь повторяет уже лежащее на столе состояние, не принимается.
transform
Такой прогон обязан запускаться с . Число few-shot — верхняя граница числа воспроизводимых ходов, а не количество примеров: история достаётся только оцениваемым ходам разговоров, а остальные 750 вопросов при той же команде остаются одноходовыми.
--apply_chat_template --fewshot_as_multiturn
Источники. 114 настоящих файлов из открытых репозиториев — конфигурации, выгрузки данных, таблицы, схемы, — прочитанных как 139 различных документов: большой файл берётся через одно из своих поддеревьев. Отбор шёл за байтовую грязь: эмодзи и суррогатные пары, экранированные кавычки и переводы строк внутри значений, числа-строки, почти одинаковые ключи. Документ допускается, только если его модель данных укладывается в две-три фразы, которые можно написать в промпте; всё, что читается неоднозначно — смешанное содержимое в XML, скаляры, чью типизацию YAML решает по-своему, — отвергается, а не объясняется. Сколько вопросов даёт каждый файл, не выравнивалось: медиана — пять, самая большая таблица стоит за 93.
Сборка. Для каждого вопроса документ приводится к исходной нотации, операция применяется, эталон выписывается и читается обратно: если разбор не совпал со структурой, из которой он собран, вопрос выбрасывается. Затем эталон оценивается теми же проверками, которыми потом оценивается модель, и принимается только при 1.0 по всем применимым ограничениям. Семантика каждого диалекта реализована дважды и независимо, и обе сводятся на каждом вопросе.
Перед выпуском. Про каждое ограничение показано, что оно не только принимает эталон, но и что-то отвергает; метрики лежат в своих границах; а порядок ключей, переводы строк, BOM и хвостовые пробелы не меняют вердикт там, где вопрос их не оценивает. Одна проверка есть ровно про разделение по ролям: ни один оцениваемый ответ не встречается нигде в — ни ответом, ни внутри промпта раннего хода.
shots
sample_pass_rate — доля вопросов, где выполнены сразу все применимые ограничения. Главная метрика.balance_score — геометрическое среднее по 33 клеткам «семейство ×. сложность». Клетка с нулём учитывается как 0.01, поэтому одна мёртвая клетка умножает балл на 0.87, а не обнуляет его. Модель с ровными 0.60 во всех клетках получает 0.60; модель со средним 0.64 и тремя мёртвыми клетками — 0.48.constraint_pass_rate — доля выполненных ограничений; частичный зачёт отделяющий одно нарушенное правило от проигнорированного формата.format_pass_rate — упаковка: один блок кода, верный тег, ничего снаружи, тело разбирается как целевая нотация.content_pass_rate — содержание: структура совпадает с эталоном, числа в пределах относительного допуска 1e-6, строки побайтово.task_pass_rate — собственная семантика семейства: то, чего сверка с эталоном не видит.