Jev против дообученного кросс-энкодера: 0.868 против 0.883, и почему интереснее не это
TypeSafe выпустила Jev — модель, которая не пишет текст, а возвращает типизированное решение с калиброванной вероятностью. Мы поставили её на свой отложенный набор из 18 792 пар «требование ↔ резюме» против собственного дообученного кросс-энкодера. Zero-shot Jev дал 0.868 против наших 0.883, и разница оказалась статистически неразличимой. Зато заявленная калибровка на наших данных не подтвердилась (ECE 0.117 против 0.071), а оба числа держатся на дефекте разметки, на который Jev опирается сильнее нашей модели.
Авторы: slavb18
15 сентября TypeSafe AI вышла из стелса с 40 миллионами посева и моделью Jev, которую называет моделью первого рода: она не генерирует текст, а возвращает типизированный ответ с вероятностью за один параллельный проход. Обещания звучат так, как нужно тому, кто считает много одинаковых решений: 40–200 раз быстрее генеративных моделей, 0.042 доллара за миллион входных токенов, вывод бесплатный, галлюцинация и ошибка типа невозможны по построению.
У нас есть задача этой формы и есть на чём её мерить. Мы считаем соответствие кандидата вакансии: у вакансии список требований, у кандидата резюме, на каждую пару нужен ответ «закрыто или нет». Год назад это делала облачная генеративная модель, сейчас — свой кросс-энкодер на 278 миллионов параметров, исполняемый внутри приложения на процессоре. У него есть измеренное качество, измеренный потолок и отложенный набор, на котором это измерено.
Поэтому вопрос стоял узко: что Jev покажет на нашем наборе против нашей модели. Замер занял четыре минуты и 17 центов.
Как устроен замер
Сравнивать модели можно только на одних и тех же строках, одной и той же метрикой. Обе взяты готовыми, ни одна не придумана под этот случай.
Набор — distill-test.jsonl, отложенная часть обучающего набора нашего кросс-энкодера: 18 792 пары
«требование ↔ резюме» на 105 вакансиях. Разбиение сделано по вакансиям, а не по парам: у одной
вакансии требования повторяются во всех её офферах дословно, и случайное разбиение оставило бы те
же требования по обе стороны. Модель показала бы качество на том, что видела.
Метрика — ROC-AUC «закрыто против не закрыто», где меткой служит вердикт облачной модели: закрыто
при matched ≥ 0.9, не закрыто при ≤ 0.1, середина выброшена. По ней измерены все предыдущие шаги
этой работы, поэтому у нового числа есть с чем соседствовать:
| линия | ROC-AUC |
|---|---|
| комбинация признаков без модели | 0.829 |
| дообученный кросс-энкодер, 278M, на CPU | 0.885 |
| облако против собственного записанного вердикта — потолок | 0.924 |
Потолок в последней строке мы измерили отдельным прогоном: облачная модель на своих же записанных входах воспроизводит себя с AUC 0.924, а не 1.0. Система, повторяющая облако идеально, выше этого не поднимется, и гнаться за оставшимися пунктами бессмысленно.
Вход обеим моделям одинаковый: текст требования и восемь отобранных кусков резюме, то же, что
получает кросс-энкодер в проде. Jev спрашивается примитивом noul (вопрос с ответом «да/нет» и
вероятностью), сразу двумя формулировками, русской и английской, в одном запросе над одним
состоянием. Вендор предупреждает, что английский у модели основной, а остальные языки «не одинаково
хорошо», и просит мерить на своих данных; данные у нас русские.
Взяли 2 000 пар из 18 792, детерминированной выборкой, по 82 вакансиям. Меньше полного набора потому, что это боевые резюме, и отправлять их во внешний сервис целиком ради статьи не стоит.
Что получилось
| линия | ROC-AUC | ECE | Brier | точн. |
|----------------------------|---------|-------|--------|-------|
| кросс-энкодер на месте | 0.883 | 0.071 | 0.1266 | 81.8% |
| Jev, вопрос по-русски | 0.868 | 0.117 | 0.1299 | 81.4% |
| Jev, вопрос по-английски | 0.868 | 0.118 | 0.1306 | 81.3% |
2 000 пар, 4.16 миллиона входных токенов, 0.17 доллара, 28 пар в секунду при двенадцати потоках. Задержка Jev — 322 миллисекунды в медиане и 411 на 95-м процентиле, с двумя вопросами в запросе и сетью до США. Наш кросс-энкодер тратит 189 миллисекунд на пару на процессоре в четыре потока.
Язык вопроса не изменил ничего: 0.868 обе формулировки, разница в третьем знаке. Предупреждение вендора про неанглийские данные на нашей задаче не сработало, по крайней мере там, где вопрос короткий, а понимать нужно технический текст с латинскими названиями инструментов.
А дальше выясняется, что zero-shot модель, которая наши данные видит впервые, отстала от специально дообученной на них на пятнадцать тысячных. Наш кросс-энкодер учился на 104 726 парах, снятых с собственной базы, и стоил аренды видеокарты. Jev получил текст требования и кусок резюме.
Пятнадцать тысячных не отличимы от нуля
Прежде чем делать из этого вывод, надо проверить, отличимы ли 0.883 и 0.868 вообще. Две тысячи пар звучат солидно, но пары внутри одной вакансии зависимы: требования у них общие, кандидаты похожи. Настоящая единица наблюдения здесь — вакансия, и их 82.
Мы прогнали кластерный бутстрэп: две тысячи повторов, в каждом ресэмплируются вакансии целиком, считается разность AUC на одних и тех же строках. Сравнение парное, поэтому общий шум выборки из разности уходит.
AUC кросс-энкодера 0.883 [0.832; 0.921]
AUC Jev (русский вопрос) 0.869 [0.811; 0.907]
разность кросс − Jev 0.014 [-0.030; 0.067]
кросс-энкодер выше Jev в 71.9% повторов
Доверительный интервал разности накрывает ноль. На этой выборке дообученная модель и zero-shot внешний сервис статистически неразличимы: в 28% повторов Jev оказывается выше. Писать «наша модель лучше на 0.015» нельзя. Писать «Jev догнал дообученную модель» тоже нельзя: мы измерили отсутствие доказательств разницы, а это слабее равенства.
Чтобы разница такого размера стала различимой, нужен полный набор и заметно больше вакансий. Это выполнимо, полные 18 792 пары стоят около 1.6 доллара и пятнадцати минут, но упирается в решение, которое дороже статьи: отправлять ли боевые резюме наружу пачками.
Калибровка не подтвердилась
Главное заявление Jev — не скорость и не цена, а калибровка: обучение идёт под соответствие вероятности исходу, и 0.85 должно означать «верно в 85 случаях из ста». На этом держится весь предлагаемый способ работы: уверенное решает программа, неуверенное уходит человеку или тяжёлой модели.
На наших данных калибровка Jev вдвое хуже, чем у нашего кросс-энкодера: ожидаемая ошибка калибровки 0.117 против 0.071. Наша модель никогда не обучалась под калибровку специально, она обучалась на бинарных метках, и её выход оказался откалиброван по построению, что мы проверили отдельным замером.
Заявление вендора это не опровергает, и путать тут легко. Калибровка — свойство модели на распределении, а наше распределение для Jev чужое: русский технический текст, наши формулировки требований и метки, снятые чужой моделью. Вендор об этом и предупреждает. Мы проверили, и ответ для нашей задачи такой: числу Jev на наших данных нельзя верить как вероятности, его пришлось бы калибровать самим, на отложенной выборке, температурой, тем же инструментом, которым калибруют любую другую модель. Ради этого свойства идти во внешний сервис незачем.
Оба числа держатся на дефекте разметки
Самое неприятное в замере касается нас, а не Jev.
Метки набора — вердикты облачной модели, снятые до 18 сентября 2026 года. В этот день мы запретили своему промпту ставить ноль за молчание резюме: «в резюме не указано» не доказывает, что навыка нет, человек просто не написал. Все накопленные вердикты сняты до правки, значит часть отрицательных меток дефектна.
Дефектных меток много. В нашей выборке из 2 000 пар отрицательных 545, и 220 из них, 40.4%, поставлены за молчание. Мы разложили замер по этому признаку.
| срез | пар | кросс-энкодер | Jev ru | Jev en |
|---|---|---|---|---|
| все пары | 2000 | 0.883 | 0.868 | 0.868 |
| без нулей за молчание | 1780 | 0.858 | 0.827 | 0.825 |
| только молчаливые нули и закрытые | 1675 | 0.920 | 0.929 | 0.931 |
На парах, где отрицательная метка дефектна, Jev обходит нашу модель: 0.929 против 0.920. На парах, где метка честная, он проседает сильнее нашего: 0.827 против 0.858, и разрыв вырастает с 0.015 до 0.031.
Причина видна на одной пробе. Мы дали Jev требование «опыт работы с Kafka» и резюме, где Kafka не упоминается вовсе, а есть Java, Spring и PostgreSQL. Ответ — 0.05. Модель прочитала отсутствие упоминания как отсутствие навыка, то есть сделала ту самую ошибку, которую мы своему промпту запретили.
Отсюда два следствия, и оба не про Jev. Часть нашего собственного 0.883 — это согласие с дефектом, и честное число на чистых метках 0.858. И любой внешний замер, где метки сняты одной моделью, а проверяется другая, меряет в том числе совпадение их предрассудков. Jev в этой паре оказался ближе к старому поведению облака, чем наша модель, обученная на тех же метках. Выглядит это как преимущество до момента, когда отделишь дефектные метки от честных.
Что это значит для нас
Ничего не меняется, и решает тут не качество.
Jev поставляется только как закрытый управляемый API. Открытых весов нет, self-hosted-варианта нет, разворачивания в своём контуре нет. Наша работа последнего года ведётся ради одного свойства: заказчик ставит систему к себе, и данные кандидатов не уходят наружу. Модель, которую нельзя поставить рядом с данными, эту задачу не решает ни при каком AUC. Нам пришлось запросить у себя же разрешение на отправку двух тысяч боевых пар ради этого замера, и это нормальный порядок работы с персональными данными.
По существу мы бы тоже ничего не выиграли. Разница неразличима, калибровка хуже, задержка через сеть больше, чем у нашей модели на процессоре, а цена — 1.6 доллара за прогон отложенного набора против нуля после однократной аренды видеокарты за 77 центов.
Что это значит не для нас
Вывод «Jev не нужен» отсюда не следует.
Zero-shot модель, которая на чужой задаче, чужом языке и чужой разметке подходит вплотную к специально дообученному кросс-энкодеру, — сильный результат. Нам он обошёлся в 17 центов и четыре минуты против недели работы, аренды GPU и конвейера обучения. Для команды, у которой нет 104 726 размеченных пар и нет требования закрытого контура, это выглядит как способ получить приличное качество за вечер.
Осторожнее стоит быть с двумя вещами. Калибровку проверяйте на своих данных: на наших заявленное свойство не воспроизвелось, и порог, выбранный по документации, дал бы не ту рабочую точку. И смотрите, что у вас в метках. Если разметку ставила другая модель, часть согласия с ней — это общие ошибки, а не качество, и увидеть это можно, только разложив набор по видам меток.
Как повторить
Замер и разбор лежат в репозитории и запускаются двумя командами:
# сам замер: выборка, вопросы к Jev, кросс-энкодер на тех же строках
BENCH_DIR=~/bench-train PAIRS=2000 bun scripts/verification-bench/jev.ts
# разбор: доверительные интервалы по вакансиям и срез по дефекту разметки
BENCH_DIR=~/bench-train bun scripts/verification-bench/jev-analysis.ts
Ответы Jev кешируются рядом с набором, поэтому повторный прогон ничего не платит и ничего не отправляет. Оценка расхода печатается до первого запроса, и превышение потолка — отказ, а не счёт постфактум.
Если Jev вам неинтересен, из этого замера всё равно остаётся метод. Сравнивать модели надо на одних строках одной метрикой, иначе сравниваются выборки. Разницу в третьем знаке надо проверять интервалом, а ресэмплировать при этом не строки, а то, что порождает зависимость между ними, — у нас это вакансия. И набор стоит раскладывать по видам меток: общее число показывает среднее по смеси честных и дефектных пар, а какая модель держится за дефект, в нём не видно.