Jev: решения вместо текста
Модель, которая не пишет ответы, а принимает решения — да или нет, выбор из вариантов, оценка по шкале — и возвращает вероятности.
Jev (TypeSafe) — модель другого класса, чем чат-модели. Она не генерирует текст. Вы отправляете ей данные и вопросы с заранее известными вариантами ответа, а она возвращает готовые значения: вероятность «да», выбранный вариант, оценку по шкале. Парсить JSON из текста не нужно — ответ сразу ложится в if, сортировку или порог в вашем коде.
В RouterAI Jev доступна через выделенный эндпоинт /api/v1/decisions. В примерах используется алиас ~typesafe/jev-latest — он всегда указывает на актуальную версию; конкретную версию можно закрепить именем вроде typesafe/jev-1.13. Отдельный аккаунт TypeSafe не нужен — работает обычный ключ RouterAI.
| Чем хороша | Почему |
|---|---|
| Быстро | Ответ приходит меньше чем за секунду, сколько бы вопросов вы ни задали: они обрабатываются параллельно |
| Дёшево | Тарифицируются только входные токены. Классифицировать одно обращение стоит доли копейки |
| Предсказуемо | Ответ всегда из ваших вариантов — модель не придумает значение, которого вы не предлагали |
| Честно про сомнения | Вместе с ответом приходят вероятности: видно, когда модель уверена, а когда решение лучше отдать человеку |
Когда брать Jev, а когда чат-модель
| Задача | Что подойдёт |
|---|---|
| Определить тему, отдел, намерение, язык, тип документа | Jev |
| Проверить, есть ли в тексте признак: срочность, жалоба, персональные данные, попытка взлома промпта | Jev |
| Оценить по шкале: критичность бага, раздражение клиента, релевантность документа запросу | Jev |
| Промодерировать список: ники, отзывы, объявления — одним запросом | Jev |
| Выбрать, какой модели или обработчику отдать запрос | Jev |
| Написать ответ клиенту, пересказать, перевести, сгенерировать код | Чат-модель (Chat Completions) |
| Посчитать, сравнить даты, решить многошаговую задачу | Обычный код или модель с рассуждениями |
Хорошее правило: Jev отвечает на вопросы, на которые знающий человек ответил бы за пару секунд, взглянув на текст. Если нужен анализ из нескольких шагов — разбейте его на простые вопросы и соберите результат в коде.
Три типа вопросов
| Тип | Вопрос | Что возвращает |
|---|---|---|
noul |
Да или нет? | noul — вероятность «да» от 0 до 1 |
choice |
Какой вариант из списка? | choice — победивший вариант, probabilities — вероятность каждого, confidence — уверенность |
score |
Где на шкале? | score — положение на вашей шкале, probabilities по уровням, confidence |
В одном запросе типы можно смешивать. Подробно — в гайде «Как задавать вопросы».
Первый запрос
1. Получите ключ
Ключ создаётся в личном кабинете. Это тот же ключ, что и для остальных эндпоинтов RouterAI.
2. Отправьте данные и вопросы
В state — текст, который нужно оценить. В questions — ваши вопросы: имя вопроса придумываете сами, под ним же придёт ответ. Вопросы и критерии можно писать по-русски.
curl -X POST "https://routerai.ru/api/v1/decisions" \
-H "Authorization: Bearer $ROUTERAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "~typesafe/jev-latest",
"state": "Здравствуйте! Третий день не могу подключить оплату на сайте — платежи клиентов не проходят, мы теряем заказы. Помогите, пожалуйста, срочно.",
"questions": {
"is_urgent": {
"type": "noul",
"instructions": "Клиент сообщает о срочной проблеме?"
},
"department": {
"type": "choice",
"instructions": "Какая команда должна заняться обращением?",
"criteria": {
"billing": "Платежи, счета, возвраты, подписки",
"technical": "Ошибки, сбои, интеграции, настройка",
"sales": "Тарифы, покупка, вопросы до оплаты"
}
},
"frustration": {
"type": "score",
"instructions": "Насколько раздражён клиент?",
"criteria": [
"Спокоен, просто описывает ситуацию",
"Раздражён, но вежлив",
"Очень зол, резкие выражения"
]
}
}
}'
import requests
response = requests.post(
"https://routerai.ru/api/v1/decisions",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"model": "~typesafe/jev-latest",
"state": "Здравствуйте! Третий день не могу подключить оплату на сайте — платежи клиентов не проходят, мы теряем заказы. Помогите, пожалуйста, срочно.",
"questions": {
"is_urgent": {
"type": "noul",
"instructions": "Клиент сообщает о срочной проблеме?",
},
"department": {
"type": "choice",
"instructions": "Какая команда должна заняться обращением?",
"criteria": {
"billing": "Платежи, счета, возвраты, подписки",
"technical": "Ошибки, сбои, интеграции, настройка",
"sales": "Тарифы, покупка, вопросы до оплаты",
},
},
"frustration": {
"type": "score",
"instructions": "Насколько раздражён клиент?",
"criteria": [
"Спокоен, просто описывает ситуацию",
"Раздражён, но вежлив",
"Очень зол, резкие выражения",
],
},
},
},
)
answers = response.json()["answers"]
print(answers["is_urgent"]["noul"]) # 0.98
print(answers["department"]["choice"]) # "billing"
print(answers["frustration"]["score"]) # 0.88
const response = await fetch('https://routerai.ru/api/v1/decisions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.ROUTERAI_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: '~typesafe/jev-latest',
state:
'Здравствуйте! Третий день не могу подключить оплату на сайте — платежи клиентов не проходят, мы теряем заказы. Помогите, пожалуйста, срочно.',
questions: {
is_urgent: {
type: 'noul',
instructions: 'Клиент сообщает о срочной проблеме?',
},
department: {
type: 'choice',
instructions: 'Какая команда должна заняться обращением?',
criteria: {
billing: 'Платежи, счета, возвраты, подписки',
technical: 'Ошибки, сбои, интеграции, настройка',
sales: 'Тарифы, покупка, вопросы до оплаты',
},
},
frustration: {
type: 'score',
instructions: 'Насколько раздражён клиент?',
criteria: [
'Спокоен, просто описывает ситуацию',
'Раздражён, но вежлив',
'Очень зол, резкие выражения',
],
},
},
}),
});
const { answers } = await response.json();
console.log(answers.is_urgent.noul); // 0.98
console.log(answers.department.choice); // "billing"
console.log(answers.frustration.score); // 0.88
3. Прочитайте ответ
Ответ на запрос выше, полученный от живой модели (вероятности от прогона к прогону могут немного отличаться):
{
"id": "rai-dec-1790130957-6mleoJ8dF5ZpJfN2MAkK",
"model": "typesafe/jev-1.13-20260917",
"provider": "TypeSafe",
"answers": {
"is_urgent": { "type": "noul", "noul": 0.98 },
"department": {
"type": "choice",
"choice": "billing",
"confidence": 0.61,
"probabilities": { "billing": 0.74, "technical": 0.26, "sales": 0 }
},
"frustration": {
"type": "score",
"score": 0.88,
"confidence": 0.82,
"probabilities": { "0": 0.12, "1": 0.88, "2": 0 },
"legend": {
"0": "Спокоен, просто описывает ситуацию",
"1": "Раздражён, но вежлив",
"2": "Очень зол, резкие выражения"
}
}
},
"usage": { "input_tokens": 633, "output_tokens": 73 }
}
is_urgent= 0,98 — почти наверняка срочно. В коде этоif noul > 0.8.department=billing, ноtechnicalполучил 0,26: в обращении есть и оплата, и «не могу подключить». Поэтомуconfidenceвсего 0,61 — модель честно показывает, что вариантов два. Такое обращение разумно отдать в биллинг с копией техподдержке.frustration= 0,88 — между «спокоен» (0) и «раздражён, но вежлив» (1), ближе ко второму. Индекс 0 соответствует первому уровню в вашем спискеcriteria; список повторяется в ответе в полеlegend.
Поле model в ответе содержит датированный снимок версии, который обслужил запрос (typesafe/jev-1.13-20260917), даже если в запросе стоял алиас.
Официальный SDK TypeSafe
Если у вас уже есть код на SDK TypeSafe (@typesafe-ai/sdk для JavaScript и TypeScript, typesafe-sdk для Python), его не нужно переписывать: смените адрес и ключ. Запрос и ответ те же, что у /api/v1/decisions.
# pip install typesafe-sdk
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
client = TypeSafeClient(
base_url="https://routerai.ru/api",
api_key="YOUR_API_KEY",
model="jev-latest",
)
response = client.system_one(
state="Здравствуйте! Третий день не могу подключить оплату на сайте — платежи клиентов не проходят, мы теряем заказы. Помогите, пожалуйста, срочно.",
questions={
"is_urgent": Noul(instructions="Клиент сообщает о срочной проблеме?"),
"department": Choice(
instructions="Какая команда должна заняться обращением?",
criteria={
"billing": "Платежи, счета, возвраты, подписки",
"technical": "Ошибки, сбои, интеграции, настройка",
"sales": "Тарифы, покупка, вопросы до оплаты",
},
),
"frustration": Score(
instructions="Насколько раздражён клиент?",
criteria=[
"Спокоен, просто описывает ситуацию",
"Раздражён, но вежлив",
"Очень зол, резкие выражения",
],
),
},
)
print(response.answers["is_urgent"].noul) # 0.98
print(response.answers["department"].choice) # "billing"
print(response.answers["frustration"].score) # 0.88
// npm install @typesafe-ai/sdk
import { TypeSafeClient, choice, noul, score } from '@typesafe-ai/sdk';
const client = new TypeSafeClient({
baseURL: 'https://routerai.ru/api',
apiKey: process.env.ROUTERAI_API_KEY,
defaultModel: 'jev-latest',
});
const response = await client.systemOne({
state:
'Здравствуйте! Третий день не могу подключить оплату на сайте — платежи клиентов не проходят, мы теряем заказы. Помогите, пожалуйста, срочно.',
questions: {
is_urgent: noul('Клиент сообщает о срочной проблеме?'),
department: choice('Какая команда должна заняться обращением?', {
billing: 'Платежи, счета, возвраты, подписки',
technical: 'Ошибки, сбои, интеграции, настройка',
sales: 'Тарифы, покупка, вопросы до оплаты',
}),
frustration: score('Насколько раздражён клиент?', [
'Спокоен, просто описывает ситуацию',
'Раздражён, но вежлив',
'Очень зол, резкие выражения',
]),
},
});
console.log(response.answers.is_urgent.noul); // 0.98
console.log(response.answers.department.choice); // "billing"
console.log(response.answers.frustration.score); // 0.88
Что нужно знать:
- Оба SDK читают адрес и ключ и из переменных окружения:
TYPESAFE_BASE_URL=https://routerai.ru/apiиTYPESAFE_API_KEY=<ключ RouterAI>— тогда конструктор можно не менять. - Имена моделей принимаются в записи TypeSafe:
jev-latest(значение SDK по умолчанию, если модель не указана) обслуживается как алиас~typesafe/jev-latest,jev-1.13— какtypesafe/jev-1.13. Имя с автором используется как есть. В ответе полеmodelсодержит идентификатор модели RouterAI. - Список моделей через SDK (
client.models.list()) не работает: SDK ждёт формат TypeSafe, аGET /api/v1/modelsотдаёт каталог RouterAI. Смотрите модели в каталоге. - Стоимость запроса SDK не показывает, см. раздел о стоимости.
Уверенность: когда действовать автоматически
Вероятности — главное отличие Jev от чат-модели, которая отвечает одинаково уверенным тоном и когда знает, и когда гадает. confidence у choice и score показывает, насколько ответ однозначен: вся вероятность на одном варианте — близко к 1, размазана по нескольким — близко к 0. У noul отдельного confidence нет: сама вероятность и есть сигнал, значение около 0,5 означает «не знаю».
Удобно делить на три зоны и ставить порог по цене ошибки:
| Уверенность | Что делать |
|---|---|
| Высокая | Действовать автоматически |
| Средняя | Действовать осторожно: попросить подтверждение, пометить для проверки |
| Низкая | Не действовать: передать человеку или более сильной модели |
intent = answers["intent"]
if intent["confidence"] < 0.5:
route_to_human(message) # модель сомневается — не угадываем
elif intent["choice"] == "check_balance":
show_balance(account_id) # ошибка дешёвая — хватит умеренной уверенности
elif intent["choice"] == "approve_transfer":
if intent["confidence"] > 0.9:
confirm_then_execute(account_id)
else:
ask_user_to_confirm(account_id) # ошибка дорогая — переспрашиваем
Конкретные пороги зависят от ваших данных. Начните с осторожных значений, прогоните на своих примерах с известными ответами и подстройте. Подбирали пороги под конкретную версию модели — логируйте поле model из ответа и перепроверяйте пороги после её обновления.
Сколько это стоит
- Тарифицируются только входные токены: ваш
stateи вопросы. Выходные токены бесплатны. Актуальная цена в рублях — на странице модели. - К каждому запросу провайдер добавляет около 280 служебных токенов: запрос с коротким
stateи одним вопросом занимает примерно 300 входных токенов. Поэтому десять вопросов одним запросом заметно дешевле десяти запросов по одному вопросу — текст и служебная часть оплачиваются один раз. - Русский текст занимает больше токенов, чем английский той же длины.
- В ответе поле
usageсодержит только токены. Стоимость запроса в рублях доступна по идентификатору из заголовка ответаX-Generation-Id(он же полеidответа) черезGET /api/v1/generation?id=<id>— полеtotal_cost, а также в истории запросов в личном кабинете.
Отличия от документации TypeSafe
Формат запроса и ответа тот же, что в документации TypeSafe, поэтому её материалы по формулировке вопросов и порогам применимы без изменений. Отличия только в подключении:
- Эндпоинт —
POST https://routerai.ru/api/v1/decisions, ключ — обычный ключ RouterAI. - Модель указывается через алиас
~typesafe/jev-latest(с ведущей тильдой — так в RouterAI выглядят все алиасы) или конкретной версией, напримерtypesafe/jev-1.13. - Официальные SDK TypeSafe работают: укажите
base_urlhttps://routerai.ru/apiи ключ RouterAI, см. раздел про SDK. - Стоимость не приходит в
usage, см. раздел выше.
Частые вопросы
Это языковая модель? Нет. Jev — модель принятия решений: она возвращает типизированные ответы с вероятностями, а не текст, рассуждения или объяснения. Когда нужен текст — берите чат-модель. Когда нужно решение, на которое код может опереться, — Jev.
Может ли Jev объяснить ответ?
Нет, объяснений и рассуждений в ответе нет — только вероятности. Если нужна письменная причина, пусть решение принимает Jev, а формулирует чат-модель. Если уверенность низкая — отдайте случай человеку. Часто причину можно получить и без текста: вместо noul «одобрить?» задайте choice с вариантами «ок / бессмыслица / мат / ненависть» — выбранный вариант и будет причиной.
Можно ли задать несколько вопросов в одном запросе?
Да, и нужно: все независимые вопросы к одному state отправляйте вместе. Они обрабатываются параллельно и не видят ответов друг друга. Каждый вопрос даёт ровно один ответ, поэтому для списка элементов нужен свой вопрос на каждый — см. рецепт пакетной проверки.
Можно ли использовать ~typesafe/jev-latest?
Да. Алиас указывает на текущую версию Jev и переводится на новую, когда она выходит; в ответе, логах и тратах при этом фигурирует реальная модель. Если вы подбирали пороги уверенности под конкретную версию, закрепите typesafe/jev-1.13 — иначе после обновления пороги придётся перепроверять.
Можно ли отправить картинку?
Jev — нет: она работает только с текстом, и запрос с картинкой RouterAI отклонит с ошибкой 400. Картинки принимают другие decisions-модели с тем же форматом вопросов и ответов — liquid/d1, inception/mercury-decide, openai/gpt-6-luna-decisions, perplexity/pplx-decider-v1.1-27b и модели cloudflare/clef*: фото передаётся частью image_url в массиве state, только в base64. Как это устроено и сколько стоит — в разделе «Картинки в state», готовый сценарий — в рецепте «Проверка фото в объявлении».
Какой размер контекста?
32 000 токенов на state и самый длинный вопрос, 64 000 — на state и все вопросы вместе. Подробнее — в лимитах.
Нужен ли аккаунт TypeSafe или их ключ?
Нет. И прямые запросы к /api/v1/decisions, и SDK TypeSafe работают с обычным ключом RouterAI, запросы оплачиваются с баланса RouterAI.
Работают ли параметры temperature, response_format, reasoning?
Нет, у decisions-модели их нет. Тело запроса — только model, state и questions. Обращение с этими полями к /api/v1/chat/completions или другим эндпоинтам вернёт ошибку: Jev обслуживается только на /api/v1/decisions.
Что дальше
- Как задавать вопросы — три типа вопросов, структура
state, как писать критерии. - Рецепты и ограничения — разбор обращений, маршрутизация, защита LLM, пакетная модерация, извлечение данных, проверка фото.
- Справочник API — параметры запроса, формат ответа, ошибки.