IFHardBench измеряет точность следования инструкциям на русском языке. Каждый из 1260 вопросов соединяет нарочито тривиальное, не требующее знаний задание на письмо («напиши про место, в котором ты по-настоящему отдыхаешь») со стеком из трёх–шести машинно проверяемых требований к ответу: точное число слов, запрещённая буква, нужное слово в заданной позиции, фиксированное число запятых, список определённой формы, правило, действующее только если в приложенном контексте упомянут дождь. Оценивается исключительно соблюдение требований — не смысл ответа и не знания.
За каждым требованием стоит детерминированный верификатор, поэтому здесь нет ни LLM-судьи, ни сопоставления с эталонным ответом, ни случайности, а за любым потерянным баллом стоит конкретное невыполненное требование.
Проверяемые навыки: Instruction following, Format control, Constraint satisfaction, Attention to detail, Self-verification
Авторы: Артём Червяков
Датасет рассчитан на инструктивные модели, чей вывод используется по заранее заданным правилам: ассистент, которому велели ответить тремя предложениями без разметки; шаг генерации, результат которого дальше разбирается кодом; системный промпт, фиксирующий стиль. Он не подходит для базовых (не инструктивных) моделей, у которых нет понятия подчинения блоку требований, и он не измеряет качество письма, знания или рассуждение: задания на письмо подобраны так, чтобы на них мог ответить кто угодно и о чём угодно.
Результаты адресованы инженерам, выбирающим модель под фиксированный контракт вывода. Головное число читается напрямую: — вероятность того, что один запрос вернётся выполнившим сразу все заявленные требования, без повторов и без правки.
sample_pass_rate
По построению изолируются три способности:
Всё остальное намеренно нейтрализовано, чтобы сохранить валидность измерения. Задания на письмо не требуют знаний о мире и не имеют правильного содержания, поэтому неверный ответ не может быть пробелом в знаниях; формулировки требований сами объявляют свою конвенцию счёта; противоречащие друг другу требования исключены по построению; а каждый вопрос строился вместе с эталоном — естественным русским ответом, удовлетворяющим всему стеку, — так что провал — это провал модели, а не вопроса. Типы требований вдобавок отфильтрованы по 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 внутри. У каждого требования есть category, family, params и is_terminal — признак того, что требование задаёт форму всего ответа целиком (JSON-объект, JSON-массив, CSV-строка, markdown-таблица, ответ из двух частей), и рядом с ним могут стоять только совместимые с этой формой требования; таких 210 из 5585;
categories —language, tier (квартиль предсказанной сложности стека: easy / medium / hard / expert, по 315 вопросов), length_tier, n_constraints, constraint_families, prompt_style, topic (одна из девяти бытовых тем банка) и stratum: core — базовая сборка по политике, topup — вопросы, добавленные сверх неё, чтобы редкий тип требования вообще можно было прочитать по отдельности;
annotation — is_solvable и language_correctness, зарезервированы под отметки ручной проверки и пока не заполнены.
Тот же вопрос после подстановки в inputs. В JSON выше переводы строк записаны escape-последовательностями; модель получает вот такой текст:
instruction
Можешь написать для меня одну вещь?
Контекст:
Коробку с инструментами я держу под столом, чтобы доставать не глядя. Материал закупаю раз в месяц на рынке. Времени уходит по часу в день.
Требования к ответу:
- Мне нужно ровно 4 абзаца, отделённых друг от друга пустой строкой.
- Абзацы делай одинаковыми: ровно 3 предложения в каждом.
- Слово, которым заканчивается первый абзац, обязано повториться где-нибудь в последнем абзаце, форма та же.
- Считая пробелы, в ответе должно быть ровно 492 символа.
- Не используй букву «п» — нигде в ответе.
Задание:
Чем ты занимаешься в свободное время просто для удовольствия?
Перечитай, пожалуйста, список перед тем, как отправлять.
А вот эталон из , который проходит все пять требований:
outputs
Старые инструменты я отчищал от ржавчины неделю. Мастерскую заменяет угол кухни и складной стол. Одиннадцать вечера — самое тихое время.
Убираю рабочее место дольше, чем работаю. Занятие требует тишины и ровного света. Результат нравится мне далеко не всегда.
На готовую вещь смотрю дольше, чем делал её. Времени уходит немало, зато голова отдыхает. Такие мелочи и делают обычный день хорошим.
Вечер за делом — лучшее время дня. Дорога заняла ровно двадцать минут. Онлайн я бываю всё реже.
40 шаблонов распределены по вопросам. Каждый блок вводится фиксированной меткой и больше ничем, в фиксированном порядке:
[обращение]
Контекст:
{context}
Требования к ответу:
{constraints}
Задание:
{question}
[напоминание]
Метки одинаковы во всех шаблонах; различаются обращение в начале и напоминание в конце — они и несут пять тональностей: просьба, приказ, обезличенная спецификация, разговорная, строгая, по восемь шаблонов на каждую. Обезличенная обходится без обращения и начинается сразу с первого размеченного блока. Вопрос без фоновых сведений получает шаблон вовсе без блока , а не пустой блок. Задание всегда идёт последним блоком, поэтому требования никогда не оказываются погребены в середине, и никакого триггера Контекст: нет: промпты адресованы инструктивным моделям, где ход пользователя закрывается токеном конца хода.
Ответ:
Сплит — пять few-shot примеров, собранных отдельным сидом. Вопросы, стеки требований и идентификаторы с shots не пересекаются, а вот задания на письмо пересекаются: заданий в банке 81 на 1260 вопросов, поэтому каждое из пяти встречается и в test — с другими требованиями. Пример показывает форму ответа, а не сам ответ.
test
Вопросы порождает детерминированный генератор — тот же сид пересобирает датасет побайтово.
Поскольку по требованиям вопроса, распределение размеров стека прямо ограничивает результат: при вероятности выполнить одно требование 0.80 потолок для стека из пяти требований — 0.33, а при среднем по сборке значении 4.43 требования на вопрос — 0.37.
sample_pass_rate = Π pᵢ
Куски рассуждений удаляются перед проверкой: отбрасывается всё до первого включительно. Генерация ограничивается именно закрывающим тегом, а не сбалансированной парой </think>, потому что открывающий тег часто вообще не попадает в генерацию: шаблоны чата рассуждающих моделей регулярно дописывают <think>...</think> в конец промпта, так что модель выдаёт только <think>, а сервер, склеивающий отдельно возвращённую трассу с текстом, способен оставить перед ней просочившийся токен. Дальнейшие сбалансированные блоки тоже удаляются, поэтому у модели, чередующей несколько генераций, ответ между ними сохраняется. В остальном ответ оценивается дословно, без снисходительного извлечения «части с ответом». Незакрытая генерация — модель оборвали посреди её собственного рассуждения, и закрывающего тега нет — оставляет свой текст в качестве ответа и проваливается: ответ не отсутствует, он неверен.
трасса</think>ответ