ESPN DeportesReal Madrid protesta: "Pésimo arbitraje define derbi"ESPN'Did that really happen?' How the Red Sox went from 10-17 to the postseasonBusiness AMNieuw veiligheidspact moet verdediging van Groenland onder NAVO brengenVanguardWhatsApp lists Android phones that can no longer use the appOwngoal NigeriaThe Growing Link Between Football Fandom and Online GamingStraits Times SportAustralia bowling attack boosted as Cummins and Starc return v S AfricaRai NewsAfD primo in Pomerania, dramma Cdu fuori dal Parlamentino. Merz: "Cesura ma il voto non è su di me"BBC NewsAirlines criticise air traffic control as second glitch causes more disruptionPopular ScienceFragment of oldest known peace treaty discovered in Turkey20 MinutenWo kämpfen die Kinder der reichen Politiker, Herr Klitschko?ColliderPrime Video's New 'Reacher' Spin-Off Is Officially Abandoning the Show’s FormulaSBS 뉴스"회계부정 의혹 등 5건 전달"…"청와대 입장에선 가십"
The Daily Newsstand · Free, Always
Monday, September 21, 2026

Тест Jev в качестве реранкера против LLM на классификации товаров по справочнику из 78 тысяч кодов

Translate

Публичные тарифы, токены фактические (у Gemini учтены токены мышления). Поиск без реранка даёт Acc@1 0.487 — ниже нижней границы графика.

Мы классифицируем позиции закупок по справочнику ОКТРУ: 77 772 кодов. Схема обычная, retrieve → rerank: поиск отбирает 30 кандидатов, LLM выбирает один. Второй шаг съедает почти всё время и почти все деньги пайплайна. Я проверил, можно ли отдать его модели, которая не генерирует текст: TypeSafe Jev принимает состояние и типизированные вопросы, а возвращает вероятности. Сравнивал на 928 позициях из технических спецификаций госзакупок с той же gpt-oss-120b в двух режимах, без reasoning и с ним, с Gemma-4-31B, с облачными Gemini 3.5 Flash Lite, 3.8 Flash и 3.1 Pro и с классическим кросс-энкодером Qwen3-Reranker-8B, на одном пуле кандидатов. Коротко: Jev дал лучшую точность из всех участников сравнения, и по парному тесту значимо лучшую — включая фронтир, который стоит в шестьдесят раз дороже и точнее не оказался; при этом Jev вдвое дешевле LLM без reasoning, в 2.5 раза дешевле LLM с reasoning и в 13 раз дешевле облачной модели с мышлением, а латенси на позицию ниже в 4.5 и в 12 раз. И ещё одно: gpt-oss меняет свой ответ примерно на каждой шестой позиции от прогона к прогону, и выключение reasoning это не лечит. Ниже методика сравнения, метрики и код.

Почему поиск с реранком, а не классический ML-классификатор

ОКТРУ — казахстанский классификатор товаров, работ и услуг. Позиция вроде «Спикерфон Yealink CP900 with dongle Teams, максимальная мощность 7 Вт…» должна получить листовой код с полным путём по иерархии. Соседние коды отличаются нюансами: «диктофоны» рядом с «устройствами громкой связи», «кабель силовой» рядом с «кабелем контрольным».

Первый вопрос от любого, кто занимался ML: почему здесь вообще LLM или Jev, а не обученный классификатор? Ответ короткий, а подробности заслуживают отдельной статьи. Классов 78 тысяч, и по большинству из них размеченных примеров нет совсем: реальные закупки покрывают справочник неравномерно, длинный хвост кодов встречается по несколько раз в год или не встречается вовсе. Обучать не на чем. Синтетика в общем случае не спасает: чтобы сгенерировать правдоподобные позиции для кода, нужны правдоподобные примеры этого кода, а их как раз нет, и как модель, обученная на синтетике, поведёт себя на реальных закупках, заранее неизвестно. Поэтому задача решается как поиск по описаниям кодов с последующим выбором, а не как обучение с учителем.

Гибридный поиск по индексу (BM25 плюс эмбеддинги) с этим справляется до определённого предела. На нашем наборе он ставит правильный код первым в 49% случаев, но в top-30 держит его в 90%. Дальше работает реранкер, и одним вызовом он поднимает точное попадание в листовой код до 78%, а попадание в правильную группу третьего уровня (это уровень «кабели силовые» против «кабели контрольные») до 82%. Полный продовый пайплайн поверх того же реранкера даёт 72–76% точных попаданий, а там, где он сам ставит высокую уверенность (78% позиций), точность 83%; остальное уходит на ручную проверку. Вот что стоит один вызов реранкера на позицию в замере ниже:

  • один вызов gpt-oss-120b, ~6 400 входных токенов (текст позиции плюс 30 описаний кандидатов) и ~700 выходных: reasoning-трейс, то есть цепочка рассуждений, которую модель пишет перед ответом и которая тоже оплачивается, плюс JSON с решением;

  • 5.2 секунды на позицию;

  • по публичному тарифу gpt-oss-120b на OpenRouter ($0.15 за 1M входных, $0.60 за 1M выходных) это $1.39 за тысячу позиций.

При потоке в миллион позиций в квартал реранк по этим тарифам стоит около $1 400 и занимает 9 дней машинного времени на восьми воркерах. Отсюда вопрос: обязательно ли для выбора одного кода из тридцати генерировать 700 токенов текста? Первое, что напрашивается, это выключить reasoning у той же модели, и такой вариант в сравнении тоже есть.

Что такое Jev и чем он отличается от LLM

Jev от TypeSafe — модель класса System One: она обучена отдавать решение с вероятностью, а не текст. Вместо промпта и текстового ответа она принимает state (данные строкой или JSON) и словарь типизированных вопросов трёх видов: Noul (да/нет, возвращает вероятность «да»), Choice (один вариант из набора, возвращает распределение по вариантам) и Score (позиция на упорядоченной шкале). Никакого сгенерированного текста, никакого парсинга JSON, никакой проверки, что модель не выдумала несуществующий код: ответ приходит в виде вероятностей по тем вариантам, которые вы сами перечислили. Цена считается по входным токенам ($0.042 за 1M), выход в usage есть, но бесплатен. Латенси не зависит от длины рассуждения, потому что рассуждения нет.

Это и есть главное отличие от сравнения «LLM с reasoning против LLM без». Reasoning у генеративной модели можно выключить, но она всё равно генерирует ответ токен за токеном: в нашем замере gpt-oss без reasoning пишет 230 выходных токенов на позицию вместо 700. Jev не пишет ничего.

В замере использовалась версия jev-1.13.0 (алиас jev-latest на момент прогона). Одна оговорка из документации TypeSafe: основной язык модели английский, остальные «поддерживаются, но не одинаково хорошо». Весь бенчмарк ниже на русском тексте.

Реранк на Jev делается двумя способами, и я проверил оба.

Парная схема (pairwise). Каноническая, из документации TypeSafe: один вопрос Noul на каждую пару «позиция, кандидат», затем сортировка кандидатов по вероятности «да». Тридцать кандидатов, тридцать независимых вызовов. Текст инструкции и критериев ниже сокращён.

from typesafe_sdk import Noul, NoulCriteria, TypeSafeClient

question = Noul(
    instructions=(
        "Классифицируется позиция из прайс-листа или техзадания по справочнику ОКТРУ. "
        "Кандидат — один листовой код справочника со своей иерархией, названием и описанием. "
        "Обозначает ли кандидат ТОТ ЖЕ вид товара, что и классифицируемая позиция?"
    ),
    criteria=NoulCriteria(
        true="Кандидат называет тот же вид товара. Расхождения в марке, типоразмере, "
             "исполнении или производителе попаданию не мешают.",
        false="Другой вид товара: соседняя группа, изделие того же материала иного назначения, "
              "деталь вместо изделия, услуга вместо товара, слишком общая надкатегория.",
    ),
)
client = TypeSafeClient()
resp = client.system_one(
    state={"позиция": text, "кандидат": candidate_text},
    questions={"same_product": question},
)
resp.answers["same_product"].noul  # -> 0.87

Списочная схема (listwise). Один вопрос Choice, где все 30 кандидатов заданы как варианты: ключ варианта — код, описание варианта — текст кандидата. В ответе распределение по всем тридцати, так что полный порядок получается из одного вызова.

from typesafe_sdk import Choice

resp = client.system_one(
    state={"позиция": text},
    questions={"code": Choice(
        instructions="Какой код обозначает тот же вид товара, что и позиция? ...",
        criteria={code: candidate_text for code, candidate_text in candidates},
    )},
)
resp.answers["code"].choice          # -> "1071-0001-0006-100043174"
resp.answers["code"].probabilities   # -> {"1071-...": 0.88, "1083-...": 0.11, ...}
resp.answers["code"].confidence      # -> 0.87

Noul даёт абсолютную вероятность: «это тот же товар» не зависит от того, кто ещё в списке, поэтому оценки сравнимы между позициями и годятся для порога отсечения. Вероятности Choice нормированы внутри списка: 0.88 означает «лучший из этих тридцати», а не «это точно он». Зато списочная схема тратит один вызов вместо тридцати и не пересылает текст позиции и критерии тридцать раз.

Контекст: 64k токенов на запрос, 32k на состояние плюс самый длинный вопрос. Тридцать описаний кандидатов вместе с инструкцией занимают 13 тысяч токенов, влезает. На случай более длинных списков в коде стоит защита от переполнения: список режется на чанки, победители чанков разыгрывают финал. На top-30 она ни разу не сработала.

Участники

Сначала о том, по какому принципу набран список, потому что «почему именно эти модели» — первый вопрос к любому такому сравнению.

Я не ищу лучшую модель мира. Я решаю производственную задачу: миллион позиций в квартал, реранк — самая дорогая стадия пайплайна, и вопрос в том, чем заменить то, что там стоит сейчас. Поэтому список набран по осям бюджета вокруг продовой точки: то, что работает сегодня (gpt-oss-120b с reasoning); та же модель с выключенным reasoning — соперник Jev по деньгам; вдвое более дешёвая открытая модель у того же провайдера (Gemma); специализированный кросс-энкодер — нижняя граница по цене; облачные модели классом выше (Gemini Flash Lite и 3.8 Flash) и, чтобы знать потолок, фронтир — Gemini 3.1 Pro.

Все участники сравнения получают один и тот же набор из 30 кандидатов и один и тот же текст кандидата (об этом в следующем разделе). Различается только то, кто и как выбирает.

  • gpt-oss-120b с reasoning (reasoning_effort=medium): продовый промпт, калиброванный JSON-ответ. Верхняя планка по качеству и по цене.

  • gpt-oss-120b без reasoning (reasoning_effort=low): та же модель, тот же промпт, изменён один параметр. Честный соперник Jev по бюджету.

  • Gemma-4-31B: тот же промпт, другая модель, reasoning не пишет.

  • Gemini 3.5 Flash Lite и Gemini 3.8 Flash через Google API, тот же промпт. Lite не думает (около 100 выходных токенов), 3.8 Flash думает (650 токенов мышления на позицию, они тарифицируются как выходные и в замере учтены). Это ответ на вопрос «а если взять облачную модель классом выше».

  • Gemini 3.1 Pro через тот же API, тот же промпт — фронтир на момент замера. Нужен ровно за одним: показать, сколько точности на этой задаче ещё можно купить за деньги, если бюджет не ограничен.

  • Jev 1.13, списочная и парная схемы.

  • Qwen3-Reranker-8B, классический кросс-энкодер: модель читает пару «запрос + один документ» одним куском и выдаёт одну оценку релевантности. Схема поточечная, кандидаты друг друга не видят. Мы зовём его по HTTP, и все 30 документов уходят одним запросом, но внутри это 30 независимых прогонов.

Как сравнивал

Золотой набор: 928 позиций из технических спецификаций госзакупок. Эталон проверен двумя независимыми валидаторами, в наборе оставлены только записи, где они сошлись. В эталоне у записи может быть несколько допустимых кодов, и попадание в любой засчитывается. Так вышло потому, что справочник дублирует позиции: «Радиатор» и «Радиатор охлаждения» это два разных кода, а два «Генератора» в одной группе третьего уровня отличаются только номером. Эталон дополнен такими дубликатами по двум правилам: коды, которые справочник связывает как один товар, и коды с буквально одинаковым названием (справочник повторяет одну позицию в каждой ветке применения: «Глушитель» встречается отдельно у легковых, грузовых, автобусов и спецтехники, а «Болт» — в тридцати четырёх ветках). Правила применены к эталону независимо от того, что ответили модели; без них все модели теряли около пяти пунктов, а различия между ними тонули в шуме разметки.

Три условия, без которых разница между реранкерами не отделима от шума поиска.

Один пул кандидатов на всех. Поиск запускается один раз, его результат кэшируется. Каждая модель судит один и тот же набор из 30 кодов, разница в метриках принадлежит реранкеру. Заодно известен потолок: R@30 поиска, 0.900. Выше него не прыгнет никто.

Один и тот же текст кандидата. Все модели видят кандидата в одном рендере: код, путь по иерархии, название, описание. Для LLM это часть промпта с номерами кандидатов, для Jev состояние или варианты вопроса без номеров, для кросс-энкодера документ. Приор поиска при этом никуда не девается: в списочной схеме порядок вариантов в вопросе совпадает с порядком выдачи поиска, это неявный аналог номеров в промпте LLM.

Повторы там, где модель шумит. Обе конфигурации gpt-oss, Gemma и списочный Jev прогнаны трижды.

Метрики: Acc@1, macro-F1, латенси p50/p95, стоимость по фактическим токенам из usage. Отдельной строкой в таблице стоит R@30 поиска — доля позиций, где правильный код вообще есть среди тридцати кандидатов. Это потолок: реранкер выбирает из того, что ему дали, и выше R@30 не прыгнет никто, а разрыв между его Acc@1 и этой строкой — то, что реранкер ещё не добрал. Одна оговорка: при одном предсказании на позицию micro-F1 численно равна Acc@1, поэтому в таблице её нет. Macro-F1 (усреднение по классам, включая коды, в которые модель промахнулась) показывает, не выезжает ли модель на частых кодах.

Значимость разниц по Acc@1 считал парным тестом Макнемара по записям: для двух моделей смотрим, сколько позиций верно только у одной и только у другой. Межпрогонный разброс модели для этого не подходит, он показывает шум модели, а не ошибку выборки.

Результат

Знак ± показан там, где модель прогонялась трижды. Цены и латенси — в таблице ниже.

Acc@1

macro-F1

p50 / p95 на позицию

$ за 1000 позиций

потолок: код среди 30 кандидатов (R@30)

0.900

Jev 1.13, списочная

0.775 ±0.001

0.544

0.4 / 0.6 с

0.56

Gemini 3.1 Pro, фронтир

0.753

0.500

12.2 / 21.6 с

33.46

Gemini 3.8 Flash, с reasoning

0.751

0.486

2.4 / 6.2 с

7.46

gpt-oss-120b без reasoning

0.741 ±0.003

0.486

1.9 / 3.3 с

1.10

gpt-oss-120b с reasoning

0.736 ±0.006

0.483

5.2 / 10.6 с

1.39

Jev 1.13, парная

0.731

0.498

0.6 / 0.9 с *

1.71

Gemma-4-31B

0.730 ±0.001

0.468

1.5 / 2.8 с

0.65

Gemini 3.5 Flash Lite

0.698

0.419

1.0 / 1.3 с

2.28

Qwen3-Reranker-8B

0.676

0.415

0.4 / 1.7 с

0.32

поиск без реранка

0.487

0.250

0

* У парной схемы тридцать вызовов на позицию идут параллельно, и p50 — время самого медленного из них, а не сумма; подробности в разделе про скорость.

Строки отсортированы по точности: сверху потолок пула, снизу поиск без реранка, между ними участники. Знак ± стоит там, где модель прогонялась трижды. Потолок — свойство пула, а не реранкера, поэтому в остальных колонках у него прочерки.

Дальше по осям.

Точность

Списочный Jev первый и по Acc@1, и по macro-F1, и при 928 записях парный тест показывает, что он значимо лучше каждого соперника. Против gpt-oss с reasoning: только у Jev верно 80 позиций, только у gpt-oss 40, p < 0.001. Против gpt-oss без reasoning 76 против 45, p = 0.006. Против Gemini 3.8 Flash с мышлением 48 против 27, p = 0.02. Против фронтира, Gemini 3.1 Pro, 45 против 26, p = 0.03. Против Gemma 58 против 17, p < 0.001. Против Gemini 3.5 Flash Lite 96 против 26, p < 0.001. Против кросс-энкодера 121 против 30, p < 0.001. Против собственной парной схемы 61 против 21, p < 0.001.

Отдельно про фронтир. Gemini 3.1 Pro на этой задаче встаёт там же, где Flash: 0.753 против 0.751, разница 20 записей против 18 в другую сторону, p = 0.87. От gpt-oss без reasoning он тоже неотличим (64 против 52, p = 0.31), а стоит в тридцать раз дороже и думает 1 670 токенов на позицию вместо 230. То есть потолок этой задачи определяет не класс модели: от Flash Lite до фронтира все генеративные участники лежат в полосе 0.70–0.75, а оставшиеся 15 пунктов до потолка пула (0.900) деньгами и размером модели не покупаются. Упирается всё в другое — в сам справочник, где один товар размазан по десяткам почти одинаковых кодов, и в жанр техспецификации, где название товара упоминается один раз среди страницы требований. Это, кстати, и есть главный аргумент против «давайте просто возьмём модель посильнее»: сильнее уже некуда, а Jev при этом значимо выше всех и стоит в шестьдесят раз меньше фронтира.

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

Отдельно стоит посмотреть на пару «gpt-oss с reasoning против него же без reasoning»: 0.736 против 0.741. Reasoning здесь не помогает, и это воспроизводится во всех трёх повторах (0.731 / 0.742 / 0.734 против 0.740 / 0.738 / 0.744), при том что он утраивает выход (712 токенов против 228) и утраивает латенси. У Gemini похожая история в свою сторону: мышление даёт 3.8 Flash преимущество над Lite в 5.3 пункта, но 3.8 Flash стоит в 3.3 раза дороже Lite и всё равно уступает Jev.

И ещё одна цифра: R@3 у списочного Jev 0.887 при потолке пула 0.900. То есть правильный код он затаскивает в тройку почти всегда, когда тот вообще есть в пуле.

Цена

По публичным тарифам списочный Jev стоит $0.56 за тысячу позиций против $1.10 у gpt-oss без reasoning (в 2.0 раза), $1.39 с reasoning (в 2.5 раза), $7.46 у Gemini 3.8 Flash (в 13 раз) и $33.46 у фронтира (в 60 раз). Дешевле него только кросс-энкодер, $0.32, но он проигрывает по точности 9.9 пункта.

Выключение reasoning у gpt-oss экономит только 21%: выход падает с 712 до 228 токенов, но вход в 6 400 токенов никуда не девается, а он даёт две трети счёта. У Jev входных токенов вдвое больше (13 тысяч на позицию: текст кандидатов уходит в варианты вопроса, плюс инструкция), но тариф на вход в 3.6 раза ниже, а выход бесплатен.

Публичные тарифы, токены фактические. У Jev выход бесплатен, поэтому бледной части нет. Столбец фронтира обрезан: $33.46 в шкалу не влезает.

На диаграмме видно, где у кого деньги: насыщенная часть столбца — вход, бледная — выход. У Jev бледной части нет вовсе, у генеративных моделей выход съедает около трети счёта, а у фронтира — почти две трети, и его столбец в шкалу уже не влезает.

Пунктир на скаттере в начале статьи — Парето-фронт без Jev: как точность растёт с ценой у всех остальных, от кросс-энкодера за $0.32 до фронтира за $33. Кривая выходит на плато около 0.75 и дальше не поднимается ни за какие деньги. Jev лежит не на ней, а выше: за те же $0.56 фронт даёт 0.68.

Если считать не за позицию, а за верный ответ, порядок почти тот же: $0.47 за тысячу верных у кросс-энкодера, $0.72 у Jev, $0.89 у Gemma, $1.49 и $1.90 у gpt-oss без reasoning и с ним, $9.93 у Gemini 3.8 Flash и $44.42 у Gemini 3.1 Pro.

Парная схема дороже любой другой модели в таблице: $1.71. Тридцать вызовов на позицию означают, что текст позиции, инструкция и критерии пересылаются тридцать раз, 41 тысяча входных токенов вместо 13. Если нужны абсолютные вероятности, чтобы поставить порог и отказываться от ответа на сомнительных позициях, за них придётся платить.

Скорость

p50 на позицию 0.42 секунды у Jev против 1.9 у gpt-oss без reasoning и 5.2 с reasoning: в 4.5 и в 12 раз.

Сразу оговорка, без которой эти числа читать нельзя: латенси меряет не модель, а связку «модель плюс провайдер». gpt-oss и Gemma я звал у стороннего провайдера, Jev в облаке TypeSafe, Gemini в Google. Разное железо, разная загрузка, разная география.

Каждая модель работала у своего провайдера, так что это латенси сервиса, а не только модели.

Одна цифра в таблице требует отдельной сноски: у парной схемы Jev p50 равен 0.6 секунды, почти как у списочной, хотя вызовов на позицию там тридцать, а не один. Так вышло потому, что p50 на позицию — это время самого медленного из тридцати вызовов, а не их сумма: они уходят параллельно. Один Noul занимает около 0.4 секунды, тридцать параллельных укладываются в 0.6. Стоит это тридцатикратного расхода вызовов, и видно это не в p50, а в общем времени прогона: 564 секунды против 30 у списочной схемы на тех же 928 позициях и том же числе рабочих потоков. Если гнать пары последовательно, позиция займёт около двенадцати секунд.

Что от провайдера не зависит, так это объём генерации: 700 выходных токенов у gpt-oss с reasoning, 230 без него, 650 токенов мышления у Gemini 3.8 Flash, 1 670 у Gemini 3.1 Pro и ноль у Jev. Это свойство схемы, а не хостинга, и разрыв в латенси в основном оттуда. Но утверждение «Jev в 12 раз быстрее gpt-oss» верно для тех сервисов, которые я покупал, а не для моделей в вакууме. Заявленный лимит Jev в 1200 запросов в минуту в парной схеме не сработал: вызовы проходили примерно втрое быстрее, без единого 429. Документация TypeSafe предупреждает, что лимиты «меняются динамически и могут измениться без уведомления», так что на это я бы не закладывался.

Миллион позиций в квартал списочным Jev это около 8.5 часов и $560 вместо 8 дней и $1 400.

Стабильность

Четыре модели прогонялись трижды при температуре 0. Средняя Acc@1 у всех стоит почти на месте, но ответы по позициям расходятся, и очень по-разному.

Считается доля позиций, где во всех трёх прогонах выбран один и тот же код. Выключение reasoning у gpt-oss эту цифру почти не меняет: 85.2% против 82.3%.

Jev воспроизводит top-1 на 97.8% позиций, Gemma на 99.2%, gpt-oss — на 82.3% с reasoning и 85.2% без него. То есть продовый реранкер выдаёт разные коды на каждой шестой позиции от прогона к прогону, а Jev — на каждой сорок пятой.

Для агрегированной метрики это не важно: 0.736 — среднее по случайному выбору модели, а не фиксированный ответ. Для прода важно: кэшировать нельзя, воспроизвести ошибку из тикета нельзя, diff двух прогонов индекса покажет сотни изменений, большинство из которых шум.

Где Jev проигрывает и что не проверено

Вероятности Choice нормированы внутри списка. Если нужен порог, чтобы модель могла сказать «ни один из тридцати не подходит», списочная схема его не даёт: нужна парная, отдельный Noul-вопрос «есть ли в списке подходящий код» поверх списочного выбора (я это не пробовал) или кросс-энкодер, у которого оценки абсолютные по построению. То есть самая точная и самая дешёвая схема здесь же и самая неудобная для отказа от ответа.

Слово «калиброванные» из документации TypeSafe я в этом замере не проверял: ни диаграммы надёжности, ни AUROC по вероятностям Noul. Данные для этого есть, графика нет.

Английский как основной язык модели. На русских описаниях товаров она сработала лучше всех, но это один домен и один язык.

Self-host невозможен, версия по алиасу, лимиты меняются. Для прода это три отдельных риска, у своего хостинга их нет.

Про кросс-энкодер

Стоит проговорить, чем классический кросс-энкодер отличается от двух схем Jev, потому что снаружи они выглядят похоже. Qwen3-Reranker судит пару «запрос + документ» и отвечает одним числом, вероятностью токена «yes» против «no»; тридцать кандидатов это тридцать независимых прогонов. По смыслу это ровно парная схема Jev, а не списочная. Проверяется в три строки: оценки не нормированы (сумма по шести документам 0.86, а не 1), единственный слабый документ в запросе получает 0.0003, а не всю вероятность, и оценка документа не меняется, если положить рядом заведомо лучший. То есть у кросс-энкодера, как и у Noul, оценки абсолютные и сравнимы между позициями, и порог отказа на них строится; у Choice нет.

Побочное наблюдение оттуда же: два идентичных запроса подряд дают чуть разные числа, 0.00032099 и 0.00032221. Разница в четвёртом знаке, ранжирование от неё не меняется (разрывы между кандидатами на порядки больше), но это тот же сервер, на котором gpt-oss меняет top-1 на каждой шестой позиции, и та же природа: зависимость вычислений от того, как запросы попали в батч. У кросс-энкодера это безвредно, у генеративной модели с длинной траекторией декодирования выливается в другой ответ.

По качеству кросс-энкодер здесь последний: 0.676 против 0.775 у Jev, 121 расхождение в пользу Jev против 30. Зато он самый дешёвый ($0.32 за тысячу) и один из самых быстрых. Если считать деньги за верный ответ, разрыв сокращается: $0.47 против $0.72 у Jev. Так что выбор между ними это выбор между «дешевле за штуку» и «меньше ошибок разгребать руками».

Чего в этих цифрах нет

Набор целиком из одной предметной области. 928 записей дают ошибку выборки около полутора пунктов, и парный тест на них работает уверенно, но это автозапчасти, а не справочник целиком.

Те же модели я гонял ещё на двух золотых наборах поменьше, по 200 позиций: позиции маркетплейса и строки прайс-листов поставщиков. Там порядок моделей другой, и единого победителя между gpt-oss, Gemma и Jev нет: на одном наборе впереди одна модель, на другом другая, причём разрывы внутри ошибки выборки. Так что вывод «Jev лучший» верен для этих данных, а не вообще.

Цены публичные. gpt-oss и Gemma мы вызываем у стороннего провайдера и платим не по тарифам OpenRouter; Jev по тарифу $0.042 за 1M и все три Gemini по тарифам Google это живые деньги, они оплачены по счётчику.

Латенси и модель здесь не разделены: каждая модель жила у своего провайдера, и p50 меряет их вместе. Чтобы отделить одно от другого, нужен один и тот же сервинг для всех, а его у меня нет: Jev и Gemini в принципе не ставятся на своё железо.

Из генеративных моделей проверены только эти. Ни GPT-5.x, ни Claude на задаче не гонялись: фронтир-точка нужна была одна, и на ней выводы про потолок уже видны.

Аффилиации с TypeSafe у меня нет, Jev оплачивался по публичному тарифу: все его прогоны вместе обошлись примерно в $3, а один прогон фронтира — в $31.

Что дальше

Реранкер общего назначения — это способ работать там, где учить классификатор не на чем. Но «не на чем» верно для справочника целиком, а не для каждой его ветки. Поэтому дальше я двигаюсь в обратную сторону: дистиллировать модели поменьше, генерировать синтетику там, где это осмысленно, копить размеченные данные и учить на них собственные BERT-классификаторы по веткам. На автозапчастях это уже получилось. По большинству остальных веток данных всё ещё не хватает — и это тема для отдельной статьи.

Если вы гоняете LLM-реранкер в проде и ни разу не запускали его дважды на одних данных, запустите. Мне интересно, у кого ещё среднее стоит на месте, а top-1 меняется на каждой шестой позиции, и лечится ли это у вас выключением reasoning. У нас не лечится.

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.