Jev от TypeSafe на русском: тест против FRIDA и Qwen 3.6

Всем привет, с вами Низамов Илья. Jev — новая нейросеть от TypeSafe AI, которая не пишет текст, а только принимает решения: получает кусок текста или JSON и типизированный вопрос, возвращает выбор с вероятностями. После релиза 15 сентября про Jev вышли десятки обзоров, но все на английских примерах, а сама TypeSafe честно пишет, что русский модель знает хуже. Я проверил Jev на русском в реальной задаче: роутер агента интернет-магазина на LangGraph, 104 реплики из длинных диалогов с резкими сменами темы. Соперники — открытая FRIDA-Decisions от ai-forever (823M, локально) и Qwen3.6-35B-A3B на vLLM как эталон.

Короткий итог: Jev и Qwen — по 99,0 %, FRIDA — от 46 до 90 % в зависимости от того, сколько истории ей дать. Дальше — почему так, где каждая модель ошибается и что из этого брать в свой проект. Все цифры ниже взяты из базы прогонов стенда, виджеты читают те же данные.

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

TypeSafe называет Jev «System One model» — моделью быстрых суждений. Генерации нет вообще: вы передаёте state (текст или JSON) и набор вопросов, у каждого вопроса есть тип:

  • choice — выбор одного варианта из списка (наш случай: какая ветка агента);
  • score — оценка по упорядоченной шкале;
  • noul — да/нет.

Все вопросы обрабатываются параллельно, в ответ приходят выбор и откалиброванные вероятности, без текста и без парсинга. Вендор обещает 70–500 мс на вызов, цена — $0.042 за миллион входных токенов, выход бесплатный. Лимит — 32k токенов state. Вес и архитектура не опубликованы, обучали на синтетике, в основном на английском.

У этого формата есть русский открытый родственник — FRIDA-Decisions от ai-forever. Это энкодер на 823M параметров: он не генерирует текст, а сравнивает state с текстовым описанием каждого варианта и возвращает вероятности. Формат запроса у FRIDA и Jev совпадает почти полностью (state + вопрос route типа choice), поэтому их можно прогонять одним кодом. Главное ограничение FRIDA — 512 токенов state. Всё, что длиннее, модель обрезает сама.

Третий участник — обычная LLM: Qwen3.6-35B-A3B в NVFP4 на vLLM, две RTX 5070 Ti. Она другого класса, генерирует ответ, поэтому ей задан свой системный промпт и JSON-схема с enum веток. В сравнении промптов она не участвует, это эталон: «как роутит большая модель, если не экономить».

Стенд: агент магазина на LangGraph

Задача — та, ради которой такие модели и делают. Агент магазина перед каждым ответом решает, какому узлу графа отдать реплику клиента: greeting, products, orders, delivery или farewell. Ошибка роутера — агент отвечает не про то: клиент спросил, есть ли товар в наличии, а ему рассказывают про курьера.

Граф собран на LangGraph: узел-роутер и пять узлов-заглушек, переход по условному ребру:

graph = StateGraph(AgentState)
graph.add_node("router", router_node)
for branch in BRANCH_ORDER:
    graph.add_node(branch, make_branch_node(branch))

graph.add_edge(START, "router")
graph.add_conditional_edges("router", lambda s: s["route"],
                            {b: b for b in BRANCH_ORDER})

Роутер внутри router_node подменяется: FRIDA, Jev или Qwen. Граф, датасет и подсчёт точности одни и те же.

Датасет — синтетические, но злые диалоги: 5 разговоров по 35–50 реплик, товары взяты из демо-базы 1С. Клиент спрашивает про сок, потом про заказ, потом про курьера в Тулу, потом снова про сок. Каждая реплика клиента — отдельный тестовый пример: история до неё, само сообщение и эталонная ветка. Всего 104 примера, из них 57 со сменой темы, история в среднем 20 реплик, максимум 42.

Длинная история здесь — не украшение. В реальном чате именно она путает роутер: двадцать реплик шла речь о доставке, а клиент пишет «спс, пока».

Поскольку у FRIDA лимит 512 токенов, сравнивались три стратегии сборки контекста, каждая — отдельный прогон:

Стратегия Что уходит в модель
full текущее сообщение и вся история
last_n текущее сообщение и последние 8 реплик
current_only только текущее сообщение

Что именно уходит в модель?

FRIDA режет state справа. Если положить историю по порядку, а текущее сообщение в конец, при переполнении потеряется именно то, что надо классифицировать. Поэтому state собирается наоборот: сначала текущее сообщение, потом история от свежих реплик к старым.

# current_first: модель обрезает state справа,
# поэтому текущее сообщение первым, история — от свежих к старым
lines = [f"Текущее сообщение клиента: {current_message}", ""]
if turns:
    lines.append("Предыдущие реплики диалога (от последней к первой):")
    lines.extend(_turn_line(m) for m in reversed(turns))
return "\n".join(lines)

Вызов Jev — обычный POST с тем же запросом плюс поле model. На 429 и 529 (лимит и перегрузка) — повтор с экспоненциальной паузой:

payload = {"model": "jev-latest", **request}
for attempt in range(max_retries + 1):
    response = client.post("/systemone", json=payload)
    if response.status_code not in (429, 529) or attempt == max_retries:
        break
    time.sleep(0.5 * 2 ** attempt)

В виджете ниже — настоящие запросы стенда для пяти показательных реплик. Переключите стратегию на full у реплики «спс, пока» и посмотрите вкладку FRIDA: история весит больше 512 токенов, и в видимую часть попадают вопросы о доставке.

Промпт FRIDA против промпта Jev

Запрос у FRIDA и Jev одного формата, но «родной» способ его написать разный. Я собрал два промпта и прогнал оба через обоих судей.

Промпт frida — state одной строкой с подписями «Клиент:» / «Оператор:», инструкция-команда «Определи, к какой ветке относится ТЕКУЩЕЕ сообщение клиента», у каждой ветки строка-перечень признаков.

Промпт jev написан по документации TypeSafe: state объектом {current_message, history}, инструкция — вопрос со ссылкой на поле (К какой теме относится `current_message`?), у веток три поля:

"orders": {
  "what": "вопрос об уже оформленном заказе: статус, когда он придёт, оплата и списания, отмена, изменение состава",
  "not_for": "доставка вообще, без привязки к конкретному заказу — это delivery; цена и наличие товара — products",
  "examples": ["Мой заказ уже отправили?", "Деньги за заказ списались, а подтверждения нет"]
}

Поле not_for — главное. Оно описывает границу с соседней веткой: «это не про доставку вообще, это про конкретный заказ». В документации TypeSafe это отдельная рекомендация: Jev читает оговорки буквально, и без них путает похожие варианты.

Что получилось:

  • Jev на своём промпте лучше: 99,0 % против 97,1 % на промпте frida. Разница — две реплики вида «а когда ЗК-777568 привезут?»: без not_for Jev отдаёт их в доставку, с ним — в заказы.
  • FRIDA без истории на промпте jev лучше: 90,4 % против 87,5 %. Описания с not_for и примерами вылечили её главную слабость: «и вам хорошего дня» и «Всего доброго!» без контекста больше не уходят в приветствие (farewell 4 из 9 → 9 из 9).
  • Но тот же формат провалил у FRIDA заказы: 21 из 24 → 15 из 24. Длинное описание со списком исключений, похоже, размывает вектор ветки для энкодера.
  • Историю в виде JSON FRIDA не читает: с промптом jev и историей точность 46 % при любой стратегии, хуже текстового state.

Вывод для практики: промпт под судью — не универсальная вещь. Описание, которое помогает одной модели, может топить другую, и проверять его надо на своём датасете, а не по документации.

Результаты: два судьи и эталон

Выберите промпт и стратегию — карточки и графики пересчитаются по прогонам из базы.

Сводка по лучшим прогонам каждой модели:

Модель Точность Медиана вызова Где работает
TypeSafe Jev 99,0 % (103 из 104) 328–374 мс облако, api.typesafe.ai
Qwen3.6-35B-A3B 99,0 % (103 из 104) 143–168 мс vLLM, 2× RTX 5070 Ti
FRIDA-Decisions 90,4 % (94 из 104) 26 мс torch, RTX 3080 Ti

Три наблюдения, ради которых стоило всё это собирать.

Jev не отвлекается на историю. Его прогоны на full, last_n и current_only дали одинаковые ответы на все 104 реплики — меняется только латентность. Тридцать восемь реплик о товарах, заказе и доставке перед «спс, пока» его не сбивают. На русском, на котором он «поддерживается хуже».

Qwen держит тот же уровень, но это 35B на двух видеокартах. На полной истории она прочитала больше тысячи токенов промпта и всё равно решила по текущему сообщению. Цена — железо: две RTX 5070 Ti, занятые под одну задачу маршрутизации.

FRIDA живёт только без истории. На full у неё 50 %, на last_n — 55 %, на current_only — 87,5 % (90,4 % на промпте jev). История для неё — шум: 43 из 104 запросов на full упёрлись в лимит 512 токенов, и даже в тех, что влезли, модель цепляется за тему прошлых реплик.

Где ошибаются модели?

По веткам, отдельно на репликах со сменой темы и самые частые промахи:

FRIDA с историей путает всё с доставкой. На full самый частый промах — products → delivery, 17 раз: клиент спрашивает «полусапожки есть в наличии?», а перед этим три его вопроса были про почту, курьера и сроки до Краснодара — и энкодер голосует за доставку. Второй — products → greeting, 11 раз, и все — в первых четырёх вопросах клиента: истории ещё мало, и приветствие оператора, похоже, перевешивает вопрос о цене.

FRIDA без истории путает прощание с приветствием. «И вам хорошего дня» и «Всего доброго!» — 5 промахов farewell → greeting на промпте frida. Без контекста это и правда двусмысленно: так здороваются и прощаются. Лечится описанием с not_for — см. раздел про промпты.

Две реплики, на которых спотыкаются даже сильные. «А когда ЗК-736745 привезут?» — эталон orders (есть номер заказа), но слово «привезут» тянет в доставку. Jev на своём промпте и Qwen с историей её решили, Jev на промпте frida, Qwen без истории и FRIDA — нет. Вторая — «жду ответа» с эталоном products: Jev и Qwen дали orders при любом промпте и стратегии. В другом диалоге та же фраза размечена как orders, то есть правильный ответ зависит от контекста. Это скорее спорная разметка датасета, чем ошибка моделей — оставил её как есть, чтобы не подгонять цифры.

Реплика за репликой

Каждый квадрат — одна реплика: зелёный — модель выбрала верную ветку, красный — промах. Точка сверху — смена темы. Нажмите на квадрат, чтобы увидеть сообщение и ответы всех трёх моделей.

На карте хорошо видно, что промахи FRIDA с историей идут не случайно, а сериями: как только диалог надолго уходит в доставку, все вопросы о товарах в этом отрезке краснеют. Это и есть «прилипание к теме», ради которого датасет делали с дрейфом.

Все комбинации на одном экране

Пятнадцать прогонов: два промпта, три стратегии, три модели. Qwen на промпте jev не прогонялась — у неё свой системный промпт.

Если нужно понять, как такие прогоны хранить и сравнивать между собой после каждой правки промпта, — я разбирал это в статье про тестирование LLM в Langfuse. Здесь хранение проще: SQLite, одна строка на прогон и одна на реплику, но идея та же — сравнивать item в item, а не средние.

Скорость и цена

FRIDA на RTX 3080 Ti отвечает за 14 мс на коротком state и за 36 мс на полном. Отдельный бенчмарк пропускной способности на RTX 5070 Ti (torch, bf16, батчинг запросов из очереди):

Длина state 1 поток, p50 1 поток, req/s 64 потока, req/s
full, ~450 токенов 24,6 мс 45,7 42,7
current_only, ~30 токенов 11,6 мс 84,6 173,2

На длинных state батчинг почти ничего не даёт: потолок около 45–50 запросов в секунду, параллельные запросы просто ждут в очереди. На коротких — около 170 в секунду. Пик видеопамяти — 1.8–2.5 GiB, старт с прогревом — 4 секунды. То есть FRIDA встаёт рядом с любой другой моделью на ту же карту.

Jev — 330–370 мс медиана с сетью до США. Это на порядок медленнее FRIDA и примерно вдвое медленнее Qwen на своём железе, но для чата, где следом всё равно пойдёт генерация ответа, треть секунды не критична. Деньги — почти ноль: весь прогон на 104 запроса с полной историей — около 134 тысяч входных токенов по грубой оценке (символы / 3), меньше цента. Тысяча маршрутизаций обходится примерно в $0.05 с полной историей и в $0.03 без неё — основную часть запроса занимают описания веток, а не история.

Qwen — 134–168 мс на двух RTX 5070 Ti. Бесплатно по токенам, но это 32 GB видеопамяти, которые больше ничем не заняты.

Что выбрать для своего агента?

  • Нужна максимальная точность и данные можно отдавать в облако — Jev. 99 % на русском, не зависит от длины истории, стоит копейки. Минус — данные клиентов уходят на американский API. Для чата магазина с номерами заказов и именами это вопрос 152-ФЗ, а не вкуса.
  • Всё должно остаться внутри периметра, видеокарты есть — LLM на vLLM. Qwen3.6-35B-A3B дала те же 99 %. Если своя модель уже крутится для генерации ответов, роутинг на ней почти бесплатен. Как поднять такую модель — в статье про Qwen 3.6 NVFP4 на vLLM и SGLang.
  • Нужен дешёвый и быстрый фильтр, допустимы 10 % ошибок — FRIDA, но только на текущем сообщении и с хорошими описаниями веток. 14–26 мс на старой карте, 2 GiB памяти. Разумная схема — каскад: FRIDA отвечает сама, когда уверенность высокая, а сомнительные реплики (прощания без контекста, «а когда привезут?») отдаёт LLM.

Отдельно о том, что этот тест не показал. Пять веток — простая задача. На двадцати ветках с пересекающимися темами разрыв между моделями может быть совсем другим. И это синтетика: реальные клиенты пишут с опечатками, голосовыми и скриншотами.

Если вы собираете агента для своего бизнеса или для 1С и упираетесь в маршрутизацию, контекст и оценку качества — это то, что мы разбираем на живых проектах в курсе «ИИ для 1С: разработка ИИ-агентов, RAG и MCP-серверов». Там же — сборка графа на LangGraph, о которой подробно в статье «LangGraph-агент для 1С».

Как повторить тест?

Стенд — обычный Python-проект: LangGraph, пакет frida-decisions, httpx для TypeSafe и vLLM, прогоны в SQLite. Код, датасет из 104 реплик и все 15 прогонов из статьи лежат в архиве — кнопка «Материалы к статье» под текстом. Ключей в нём нет, а сравнить прогоны и открыть презентацию с графиками можно сразу, без моделей и API (команды compare и serve). Порядок:

python src/run_experiment.py generate                     # датасет: диалоги → data/dialogs.jsonl
python src/run_experiment.py run --router frida --strategy current_only
python src/run_experiment.py run --router jev --strategy full --prompt jev
python src/run_experiment.py run --router qwen --strategy full
python src/run_experiment.py compare 79 83                # расхождения двух прогонов item в item
python src/run_experiment.py serve                        # презентация с графиками из runs.db

Ключ TypeSafe и адрес сервера для Qwen — в .env по шаблону .env.template. Для FRIDA на CPU есть int8 ONNX: точность 0.891 против 0.893 у полной модели, 100–300 мс на вызов — для роутера без видеокарты этого достаточно.

Следующий шаг, который я проверю, — гибридный промпт для FRIDA: текстовый state и инструкция от frida, а развёрнутые описания с not_for только у тех веток, где они помогли (greeting, farewell, products). Цель — выше 90,4 % без провала на заказах.

Jev — первая модель, которая делает роутинг агента дешевле и проще, чем держать под это LLM. А FRIDA показывает, что тот же подход можно запустить у себя бесплатно, если понимать её ограничения. Обе стоит иметь в арсенале, а выбирать — на своём датасете. Как такой датасет собрать и как встроить роутер в агента, который работает с вашей учётной системой, — в курсе «ИИ для 1С».

Курс по теме статьи

Курс ИИ для 1С — разработка ИИ-агентов, RAG и MCP-серверов

Для программистов и аналитиков 1С: на курсе пишете код и собираете 4 проекта — ИИ-агента, RAG по базе знаний и MCP-сервер к своей 1С. Рассрочка, бесплатный вебинар.

150 000 ₽

Перейти к курсу «Курс ИИ для 1С — разработка ИИ-агентов, RAG и MCP-серверов»

Материалы к статье

jev-frida-bench.zip · 299,8 KB

Скачать

Частые вопросы