Почему это не «судья, только аккуратнее»
Граница, записанная в LLM as Judge, делит мир надвое: что выразимо кодом — проверяется кодом, остальное уходит судье. Формулировка верная и неполная, потому что молчаливо считает выразимость свойством задачи.
Она свойство формы ответа. «Назови три жилых комплекса с наибольшей доходностью и укажи её» — вопрос с единственным верным ответом, и проверяется он тривиально, как только из абзаца прозы извлечены три названия и три числа. Непроверяемой задачу делает не её содержание, а то, что ответ пришёл текстом.
Отсюда разделение труда, в котором вероятностной части достаётся механическая работа:
| Что делает | Кто | Чем проверяется |
|---|---|---|
| превратить прозу в структуру по схеме | модель | привязка к фрагменту, сравнение двух независимых извлечений |
| сравнить структуру с эталоном | код | ничем: сравнение детерминированное |
Модель при этом не выносит суждения о правильности — она только переносит написанное в поля. Ошибиться она может, и ошибку ловят ниже; но ошибка извлечения — это расхождение с текстом, а не расхождение во мнении, и потому проверяемо.
Привязка к дословному фрагменту
Извлекатель обязан вернуть вместе со значением опорный фрагмент — кусок исходного ответа, на котором значение стоит. Дальше чистая работа со строками, без единого вызова модели: фрагмент ищется в ответе после приведения регистра и пробелов, затем без учёта пунктуации, затем нечётко. Не нашёлся — утверждение помечается выдуманным.
Это и есть механизм, ради которого стоит менять судью на извлекателя. Судью проверить нечем: его вердикт — мнение, у мнения нет места в тексте, куда можно ткнуть. У извлечения место есть всегда, и проверка стоит ноль.
Пороги нечёткого совпадения — вопрос калибровки, а не значения: у авторов это 0,6 по отношению всей строки и 0,8 по лучшему окну, и подобраны они под свой корпус. Универсального числа здесь нет, метод же простой — прогнать на размеченных случаях и смотреть, где начинаются ложные пометки.
Коллегия собирается по разногласию, а не по умолчанию
Дешёвый путь — две модели разных вендоров извлекают одно и то же независимо, плюс проверка на дословность. Сошлись значениями и обе привязаны — подтверждено, конец. Дорогой путь открывается только при расхождении: доизвлекают ещё три модели, и анализатор решает по пяти извлечениям и сырому ответу.
Ценно здесь то, что триггер объективный. «Коллегия при сомнении» обычно упирается в вопрос, откуда берётся сомнение: самооценка модели для этого не годится по той же причине, по которой не годится самопроверка вместо валидатора. Здесь сомнение — это факт: два извлечения разошлись, или фрагмент не нашёлся в тексте.
Требование к составу коллегии то же, что к подтверждениям вообще (Source Independence): модели берутся от разных поставщиков. Пять извлечений одной моделью — это одно извлечение с четырьмя копиями.
Неуверенность разложена на причины, а не свалена в ведро
Исход у каждого утверждения один из двух — подтверждено или требует разбора, — но во втором случае обязательно назван признак, по которому оно туда попало:
| Причина | Что произошло | Куда смотреть |
|---|---|---|
disagreement |
оба извлечения привязаны, значения разные | в текст: скорее всего он допускает два чтения |
possibly_hallucinated |
одно извлечение нашло значение, второе — что факта нет | в извлекатель, нашедший лишнее |
possibly_missed |
зеркальный случай | в извлекатель, не нашедший имеющееся |
primary_ungrounded / secondary_ungrounded |
фрагмент не найден в ответе | в извлекатель: он сочинил опору |
both_ungrounded |
не найдены оба | в схему извлечения: скорее всего она не о том |
analyzer_uncertain |
арбитр не уверен сам | к человеку |
Смысл дробления тот же, что у перечня допустимых исправлений в сообщении об ошибке (Validation Loops): за названной причиной стоит своё следующее действие, а за общим «не уверен» — никакого.
Пустой ответ арбитра не считается согласием
Отказ, ради которого стоит читать код, а не описание. Арбитр иногда возвращает пустой или неразбираемый JSON — типично, когда мнётся на схеме-списке. Наивная обработка прочитала бы это как «итогового значения нет», то есть как подтверждённое отсутствие факта: два извлекателя молчат, арбитр молчит, значит все согласны.
Это ровно тот же дефект, что вызов инструмента, не вернувший ничего (Tool Calling): пустота заполняется утверждением, которого никто не делал. Защита в коде поставлена явно — если большинство из пяти попыток вернули непустое значение, пустота арбитра не принимается, и итог берётся из попыток.
Правило берётся руками: молчание участника — это отсутствие голоса, а не голос «против». Различать их обязан код, потому что на выходе они выглядят одинаково.
Вторая деталь оттуда же стоит внимания отдельно. Выбирать среди попыток «самую длинную» оказалось мало: несколько извлечений давали список той же длины, но с пустыми полями внутри — обрыв вывода по лимиту токенов. Ранжирование переделали на пару «длина плюс число заполненных полей». Тот самый молчаливый обрыв, ради которого заведены правила output-truncation-unchecked, только проявившийся не в проде, а в оценочном стенде.
Две дисциплины самого набора
Эталон живёт не в банке вопросов, а в коде проверяющих. Вопросы лежат отдельным файлом и их можно отдать наружу целиком; правильные ответы — в скриптах, по одному на вопрос. Разделение не про секретность как таковую, а про то, что оцениваемая система видит ровно вопросы и ничего сверх них.
Текст вопроса сверяется дословно, и расхождение валит прогон. Файл с ответами модели несёт не только идентификатор, но и сам вопрос; не совпал с банком — прогон прерывается, а не продолжается на том, что нашлось. Без этого устаревший шаблон молча оценивал бы ответы на другие вопросы, и числа получились бы правдоподобные. Тот же приём, что --check у генераторов: расхождение обязано падать, а не выправляться на ходу.
Оговорка: детерминированное сопоставление бывает хрупким
Общее правило «где выразимо кодом — проверяй кодом» здесь получает границу, и авторы формулируют её как признание: точное сопоставление по ключевым словам внутри проверяющих оказалось ломким, и его заменили голосованием нескольких моделей с программной перекрёстной сверкой полей.
Причина в том, что сущность, названная в свободном тексте, совпадает с эталоном хуже, чем кажется: синонимы, транслитерация, неполное имя, другой порядок слов. Сравнение чисел и множеств остаётся детерминированным; сопоставление названий — нет, и попытка сделать его точным даёт не строгость, а ложные несовпадения.
Практический вывод: правило остаётся в силе, но выразимость проверяется на своих данных, а не предполагается. И у голосования здесь есть страховка, которой не было у точного совпадения, — программная сверка полей рядом с голосом.
Полный след решения хранится вместе с оценкой
У каждого сопоставленного утверждения остаются голоса моделей с обоснованиями, результат программной сверки полей, совпадение по ключевым словам, признак вызова арбитра, его вердикт и исходное извлечение. Оценка не число, а реконструируемое решение — то же требование, что к цепочке доказательств вообще (Evidence Spine).
Практическая ценность появляется при расхождении с человеческой разметкой: без следа спор упирается в «модель посчитала иначе», со следом видно, на каком шаге — извлечении, привязке или сопоставлении — разошлись.
Связано с
- LLM as Judge — судья и его границы; здесь конструкция, в которой судья не нужен
- Agent Evals — эталонный набор целиком; здесь про устройство проверяющей части
- Source Independence — почему коллегия собирается из моделей разных поставщиков
- Evidence Spine — след, по которому оценку можно пересобрать
- Validation Loops — названная причина вместо общего «не уверен», там же про перечень исправлений
- Tool Calling — пустой ответ, прочитанный как содержательный
- Paraphrase Drift — сила утверждения не выше силы совершённого действия