Вернуться к списку задач

IFHardBench

Способность модели
Attention to detail
Format control
Instruction following
Constraint satisfaction
Self-verification
Метрика
balance_score
sample_pass_rate
constraint_pass_rate
Top score
IFHardBench измеряет точность следования инструкциям на русском языке.

Описание задачи

IFHardBench измеряет точность следования инструкциям на русском языке. Каждый из 1260 вопросов соединяет нарочито тривиальное, не требующее знаний задание на письмо («напиши про место, в котором ты по-настоящему отдыхаешь») со стеком из трёх–шести машинно проверяемых требований к ответу: точное число слов, запрещённая буква, нужное слово в заданной позиции, фиксированное число запятых, список определённой формы, правило, действующее только если в приложенном контексте упомянут дождь. Оценивается исключительно соблюдение требований — не смысл ответа и не знания.

За каждым требованием стоит детерминированный верификатор, поэтому здесь нет ни LLM-судьи, ни сопоставления с эталонным ответом, ни случайности, а за любым потерянным баллом стоит конкретное невыполненное требование.

Проверяемые навыки: Instruction following, Format control, Constraint satisfaction, Attention to detail, Self-verification

Авторы: Артём Червяков

Мотивация

Датасет рассчитан на инструктивные модели, чей вывод используется по заранее заданным правилам: ассистент, которому велели ответить тремя предложениями без разметки; шаг генерации, результат которого дальше разбирается кодом; системный промпт, фиксирующий стиль. Он не подходит для базовых (не инструктивных) моделей, у которых нет понятия подчинения блоку требований, и он не измеряет качество письма, знания или рассуждение: задания на письмо подобраны так, чтобы на них мог ответить кто угодно и о чём угодно.

Результаты адресованы инженерам, выбирающим модель под фиксированный контракт вывода. Головное число читается напрямую: sample_pass_rate — вероятность того, что один запрос вернётся выполнившим сразу все заявленные требования, без повторов и без правки.

По построению изолируются три способности:

  1. Удержание нескольких независимых требований одновременно. Стеки смешивают семейства (счёт, лексика, стилистика, формат, условные), поэтому одной привычкой их не закрыть — каждое требование приходится вести отдельно прямо по ходу письма.
  2. Самопроверка. Точные счётчики, акростихи, кольца и контрольные пометки невозможно выдать одним лишь беглым письмом: нужно пересчитать написанное и исправить его до отправки.
  3. Вычисление правила, а не его исполнение. Условные требования называют обе ветки и делают выбор зависимым от приложенного контекста, поэтому слепое исполнение «того, что после если» сразу обнаруживает себя.

Всё остальное намеренно нейтрализовано, чтобы сохранить валидность измерения. Задания на письмо не требуют знаний о мире и не имеют правильного содержания, поэтому неверный ответ не может быть пробелом в знаниях; формулировки требований сами объявляют свою конвенцию счёта; противоречащие друг другу требования исключены по построению; а каждый вопрос строился вместе с эталоном — естественным русским ответом, удовлетворяющим всему стеку, — так что провал — это провал модели, а не вопроса. Типы требований вдобавок отфильтрованы по free rate, то есть по тому, как часто требование выполняется случайно в ответе, который его не требовал, поэтому ни один тип нельзя пройти, не прочитав его (планка 0.15, худший из вошедших в сборку типов — 0.125).

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

Выбор метрик следует из того, как такой ответ потребляется. Ответ, в котором нарушено одно требование из пяти, непригоден ровно так же, как тот, в котором нарушены все пять, — поэтому головной sample_pass_rate устроен по принципу «всё или ничего». Но чинятся эти два случая по-разному, поэтому constraint_pass_rate отдельно показывает долю выполненных требований как диагностику. Обе усредняют по вопросам; constraint_pass_rate сначала считает долю внутри каждого вопроса, поэтому каждый вопрос имеет одинаковый вес, а отдельный вердикт в коротком стеке весит больше, чем в длинном. Частые типы требований всё равно получают больший суммарный вес, чем редкие, — а это может скрыть как раз тот режим отказа, который инженеру важнее всего: вид инструкции, который модель не умеет выполнять вовсе. balance_score закрывает этот пробел: пасс-рейты по типам, сведённые геометрически с равным весом на тип, так что сконцентрированные провалы стоят дороже размазанных. Вместе головная метрика говорит, как часто ответ верен целиком, а баланс — есть ли у модели слепое пятно.

Описание датасета

Поля данных

  • instruction [str] — шаблон промпта с плейсхолдерами под поля inputs
  • inputs — задание, которое видит модель:
    • question [str] — задание на письмо;
    • constraints [str] — требования, по одному в строке, каждое начинается с -;
    • context [str] — фоновые сведения, никогда не оцениваются; непустой абзац у 717 из 1260 вопросов и пустая строка у остальных;
  • outputs [str] — эталон: ответ, удовлетворяющий всему стеку, сохранённый как свидетельство решаемости вопроса. При оценке с ним никогда не сравнивают, поэтому в сплите test он поставляется пустым, а в shots — заполненным;
  • meta — метаданные, скрытые от модели:
    • id [int] — сквозной номер по всему датасету;
    • base_id [str] — устойчивый идентификатор вопроса;
    • constraints [str] — машиночитаемый список требований, который читает скорер, строкой с JSON внутри. У каждого требования есть categoryfamilyparams и is_terminal — признак того, что требование задаёт форму всего ответа целиком (JSON-объект, JSON-массив, CSV-строка, markdown-таблица, ответ из двух частей), и рядом с ним могут стоять только совместимые с этой формой требования; таких 210 из 5585;
    • categorieslanguagetier (квартиль предсказанной сложности стека: easy / medium / hard / expert, по 315 вопросов), length_tiern_constraintsconstraint_familiesprompt_styletopic (одна из девяти бытовых тем банка) и stratumcore — базовая сборка по политике, topup — вопросы, добавленные сверх неё, чтобы редкий тип требования вообще можно было прочитать по отдельности;
    • annotation — is_solvable и language_correctness, зарезервированы под отметки ручной проверки и пока не заполнены.

Как это выглядит для модели

Тот же вопрос после подстановки inputs в instruction. В JSON выше переводы строк записаны escape-последовательностями; модель получает вот такой текст:

Можешь написать для меня одну вещь?

Контекст:
Коробку с инструментами я держу под столом, чтобы доставать не глядя. Материал закупаю раз в месяц на рынке. Времени уходит по часу в день.

Требования к ответу:
- Мне нужно ровно 4 абзаца, отделённых друг от друга пустой строкой.
- Абзацы делай одинаковыми: ровно 3 предложения в каждом.
- Слово, которым заканчивается первый абзац, обязано повториться где-нибудь в последнем абзаце, форма та же.
- Считая пробелы, в ответе должно быть ровно 492 символа.
- Не используй букву «п» — нигде в ответе.

Задание:
Чем ты занимаешься в свободное время просто для удовольствия?

Перечитай, пожалуйста, список перед тем, как отправлять.

  А вот эталон из outputs, который проходит все пять требований:  

Старые инструменты я отчищал от ржавчины неделю. Мастерскую заменяет угол кухни и складной стол. Одиннадцать вечера — самое тихое время.

Убираю рабочее место дольше, чем работаю. Занятие требует тишины и ровного света. Результат нравится мне далеко не всегда.

На готовую вещь смотрю дольше, чем делал её. Времени уходит немало, зато голова отдыхает. Такие мелочи и делают обычный день хорошим.

Вечер за делом — лучшее время дня. Дорога заняла ровно двадцать минут. Онлайн я бываю всё реже.

Промпты

40 шаблонов распределены по вопросам. Каждый блок вводится фиксированной меткой и больше ничем, в фиксированном порядке:

[обращение]

Контекст:
{context}

Требования к ответу:
{constraints}

Задание:
{question}

[напоминание]

Метки одинаковы во всех шаблонах; различаются обращение в начале и напоминание в конце — они и несут пять тональностей: просьба, приказ, обезличенная спецификация, разговорная, строгая, по восемь шаблонов на каждую. Обезличенная обходится без обращения и начинается сразу с первого размеченного блока. Вопрос без фоновых сведений получает шаблон вовсе без блока Контекст:, а не пустой блок. Задание всегда идёт последним блоком, поэтому требования никогда не оказываются погребены в середине, и никакого триггера Ответ: нет: промпты адресованы инструктивным моделям, где ход пользователя закрывается токеном конца хода.

Сплит shots — пять few-shot примеров, собранных отдельным сидом. Вопросы, стеки требований и идентификаторы с test не пересекаются, а вот задания на письмо пересекаются: заданий в банке 81 на 1260 вопросов, поэтому каждое из пяти встречается и в test — с другими требованиями. Пример показывает форму ответа, а не сам ответ.

Создание датасета

Вопросы порождает детерминированный генератор — тот же сид пересобирает датасет побайтово.

  1. Каталог. 61 тип требований по пяти семействам (
  2. Задания и контекст. Задания на письмо и фоновые абзацы взяты из написанного вручную банка по девяти бытовым темам. Контексты используются целыми абзацами дословно, их никогда не сшивают из кусков; часть из них — приманки, описывающие привычку оформления, которую требования затем отменяют, чтобы фон, похожий на инструкцию, был вынужден проиграть настоящей.
  3. Сборка стека. Три-шесть требований минимум из двух семейств; каждый стек; фиксирует, сколько текста должно быть в ответе; квоты на формы не дают распределению поехать из-за того, что одни требования сочетаются охотнее других.
  4. Доказательство решаемости. Эталон собирается из написанных человеком предложений банка. Композитор ничего не сочиняет — он выбирает и вправе лишь переставить, перевести в нижний регистр, разбить строки, выделить нужное слово полужирным, поставить впереди строку задания или дописать счётчик. Вопрос, для которого эталон собрать не удалось, отбрасывается, поэтому невыполнимый вопрос не может попасть в датасет.
  5. Фильтрация по free rate. Каждый тип измерен на корпусе из 162 ответов модели на собственные задания датасета, выданных без единого требования: как часто требование выполняется случайно, когда о нём не просили? Каждый вошедший в сборку тип лежит ниже планки 0.15. Условные типы измеряются по веткам отдельно, потому что усреднение двух веток скрыло бы единственное число, решающее, войдёт тип в сборку или нет.
  6. Валидация. Каждый эталон пересчитывается боевым скорером; каждый верификатор проверяется на то, что он отвергает точечную порчу проходящего ответа; ветка каждого условного перевыводится из контекста, с которым он поставляется. Всё это выполняется при сборке, а не предполагается.

Ограничения

  • Человеческая разметка выборки в ≥100 вопросов остаётся невыполненным пунктом приёмки. У каждого вопроса есть конструктивный эталон — это более сильная механическая гарантия, но не то же самое.
  • Ложная ветка условного требования — контроль, а не сложность: модель которая правило не читала, проходит её, потому что запрещённое слово всё равно не собиралось появиться. Истинных веток — 69 %.
  • Два типа реализованы и проверены, но в сборке их мало: 
  • Датасет однотёрновый. Он ничего не говорит о том, переживает ли однажды названное правило последующие ходы.

Оценка

Метрики

  • sample_pass_rate
  • balance_score
  • constraint_pass_rate

Поскольку sample_pass_rate = Π pᵢ по требованиям вопроса, распределение размеров стека прямо ограничивает результат: при вероятности выполнить одно требование 0.80 потолок для стека из пяти требований — 0.33, а при среднем по сборке значении 4.43 требования на вопрос — 0.37.

Куски рассуждений удаляются перед проверкой: отбрасывается всё до первого </think> включительно. Генерация ограничивается именно закрывающим тегом, а не сбалансированной парой <think>...</think>, потому что открывающий тег часто вообще не попадает в генерацию: шаблоны чата рассуждающих моделей регулярно дописывают <think> в конец промпта, так что модель выдаёт только трасса</think>ответ, а сервер, склеивающий отдельно возвращённую трассу с текстом, способен оставить перед ней просочившийся токен. Дальнейшие сбалансированные блоки тоже удаляются, поэтому у модели, чередующей несколько генераций, ответ между ними сохраняется. В остальном ответ оценивается дословно, без снисходительного извлечения «части с ответом». Незакрытая генерация — модель оборвали посреди её собственного рассуждения, и закрывающего тега нет — оставляет свой текст в качестве ответа и проваливается: ответ не отсутствует, он неверен.