Jev от TypeSafe: практическое руководство по модели принятия решений
Не удалось запустить аудио. Нажмите кнопку воспроизведения в плеере.
TypeSafe Jev принимает текстовое состояние системы и возвращает решения в заранее заданном формате. В этом руководстве вы подключите API, разберёте три типа вопросов и соберёте маршрутизатор, который выбирает следующего исполнителя, оценивает готовность работы и передаёт сомнительные случаи человеку.
Общую идею System One, устройство RLCD и ограничения модели я разобрал в посте «Jev: TypeSafe представила модель для принятия решений». Здесь сосредоточимся на практической интеграции.
Содержание
- Как Jev встраивается в программу
- Когда Jev подходит для задачи
- Подготовка окружения
- Первый запрос через API
- Choice, Score и Noul
- Маршрутизатор агентной задачи
- Пороги уверенности и ручная проверка
- Проектирование вопросов
- Обработка ошибок и ограничений
- Проверка качества перед внедрением
- Полезные сценарии
- Ограничения текущей версии
Как Jev встраивается в программу
Обычная языковая модель получает запрос и генерирует продолжение текста. Jev работает иначе: вы передаёте ей текущее состояние и набор вопросов с допустимыми типами ответов. Модель возвращает выбранные варианты, оценки и вероятности.[1]
Базовая схема выглядит так:
Данные и состояние процесса
↓
Jev: Choice / Score / Noul
↓
Решения и распределения вероятностей
↓
Обычный код: маршрутизация и действияСхема показывает границу ответственности: Jev оценивает состояние и возвращает вероятности, а код применяет пороги, выполняет действие или отправляет случай человеку.
Jev интерпретирует неструктурированные данные и принимает ограниченное решение. Код хранит правила, управляет процессом, вызывает инструменты и проверяет результат.
Например, модель может выбрать, кому передать задачу: исследователю, автору или редактору. Создать файл, отправить сообщение или опубликовать материал должна уже программа. Уверенный ответ модели не доказывает, что внешнее действие действительно выполнено.
TypeSafe рекомендует строить обычный программный процесс и вставлять System One только там, где требуется смысловая оценка. Детерминированные правила, побочные эффекты и управление потоком остаются в коде.[2]
Когда Jev подходит для задачи
Jev полезна там, где решение трудно описать набором точных условий, но можно заранее определить варианты ответа.
Подходящие задачи:
- распределение обращений между отделами;
- выбор следующего агента или инструмента;
- классификация документов;
- оценка срочности, качества или релевантности;
- проверка необходимости ручного подтверждения;
- ранжирование найденных материалов;
- массовая разметка переписки и исторических данных;
- проверка действий агента перед выполнением.
Jev не предназначена для написания текста, кода или свободного плана. Она также не заменяет обычные условия там, где правило уже известно.
Если задача звучит как «остановиться после десяти действий», используйте счётчик в коде. Если нужно определить, достаточно ли собранных источников для написания черновика, это уже кандидат для Jev.
Подготовка окружения
Официальный Python SDK требует Python 3.10 или новее.[3]
Создайте папку проекта и виртуальное окружение:
mkdir jev-router
cd jev-router
python3 -m venv .venv
source .venv/bin/activate
pip install typesafe-sdkВ Windows PowerShell активация выглядит так:
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install typesafe-sdkПолучите ключ в панели TypeSafe и сохраните его в переменной окружения.
macOS или Linux:
export TYPESAFE_API_KEY="ваш_ключ"Windows PowerShell:
$env:TYPESAFE_API_KEY="ваш_ключ"Не вставляйте ключ непосредственно в Python-файл и не сохраняйте его в Git.
SDK также поддерживает переменные TYPESAFE_BASE_URL, TYPESAFE_DEFAULT_MODEL и TYPESAFE_LOG_LEVEL. Если модель не указана, используется jev-latest.[4]
Первый запрос через API
Минимальный вызов можно сделать через cURL:
curl -X POST https://api.typesafe.ai/v1/systemone \
-H "Authorization: Bearer $TYPESAFE_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<'EOF'
{
"model": "jev-latest",
"state": {
"task": "Подготовить обзор трёх новых инструментов для ИИ-агентов",
"completed_work": "Найден один источник"
},
"questions": {
"materials_sufficient": {
"type": "noul",
"instructions": "Достаточно ли текущих материалов, чтобы перейти к написанию обзора?",
"criteria": {
"true": "Материалов достаточно для проверяемого и содержательного обзора",
"false": "Ключевых источников или подтверждений пока не хватает"
}
}
}
}
EOFОтвет содержит идентификатор модели, результаты вопросов и расход токенов:
{
"model": "jev-1.13.0",
"answers": {
"materials_sufficient": {
"type": "noul",
"noul": 0.18
}
},
"usage": {
"input_tokens": 178,
"output_tokens": 12
}
}Число 0.18 означает низкую вероятность ответа «да». Это ещё не команда для программы. Вы сами определяете порог и действие: продолжить исследование, запросить подтверждение или остановить процесс.
Choice, Score и Noul
Jev поддерживает три типа вопросов.
| Тип | Задача | Что возвращается |
Choice | Выбрать один вариант | вариант, вероятности вариантов, уверенность |
Score | Оценить по упорядоченной шкале | дробная оценка, вероятности уровней, уверенность |
Noul | Ответить «да» или «нет» | вероятность ответа «да» |
Choice: выбор одного варианта
Choice подходит, когда программа должна выбрать одну ветку:
Choice(
instructions="Кто должен работать над задачей следующим?",
criteria={
"research": "Не хватает фактов, источников или подтверждений",
"write": "Материалов достаточно для создания черновика",
"review": "Задача неоднозначна или готова к проверке человеком",
},
)Названия вариантов и их описания передаются модели. Идентификатор самого вопроса используется только для связи запроса с ответом и не является инструкцией.[5]
Если список может быть неполным, добавьте вариант other, unknown или none. Иначе модель будет вынуждена выбрать наиболее близкий вариант, даже когда ни один не подходит.
Score: положение на шкале
Score оценивает состояние по упорядоченным уровням:
Score(
instructions="Насколько работа готова к редакционной проверке?",
criteria=[
"Ключевые данные отсутствуют",
"Основная работа выполнена, но остаются существенные пробелы",
"Есть полный кандидат, который можно передать на проверку",
],
)Для трёх уровней результат находится в диапазоне от 0 до 2 и может быть дробным. Значение 1.3 означает положение между вторым и третьим уровнями, а не «готовность на 65%».[6]
Читайте оценку вместе с распределением вероятностей и уверенностью. Одинаковое итоговое число может быть получено из разных распределений.
Noul: вероятность ответа «да»
Noul используется для одного бинарного признака:
Noul(
instructions="Требует ли следующее действие подтверждения человека?",
criteria={
"true": "Действие внешнее, необратимое или связано с публикацией",
"false": "Действие внутреннее, обратимое и не меняет внешние системы",
},
)Значение около 1 означает уверенное «да», около 0 — уверенное «нет», около 0.5 — неопределённость. Отдельного поля confidence у Noul нет.[7]
Маршрутизатор агентной задачи
Теперь соберём сквозной пример. Программа передаёт Jev состояние задачи и задаёт три независимых вопроса:
- кто должен работать следующим;
- насколько результат готов;
- требуется ли подтверждение человека.
Создайте файл router.py:
import json
from datetime import datetime, timezone
from pathlib import Path
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
state = {
"goal": "Сравнить три инструмента для ИИ-агентов и подготовить обзор",
"completed_work": [
"Найдены официальные страницы двух инструментов",
"Собраны заметки по основным возможностям",
],
"source_count": 2,
"draft_exists": False,
"publish_requested": False,
"available_workers": ["research", "write", "review"],
}
questions = {
"next_worker": Choice(
instructions="Кто должен работать над задачей следующим?",
criteria={
"research": (
"Нужно собрать недостающие источники, факты "
"или подтверждения"
),
"write": (
"Источников достаточно, можно создавать "
"содержательный черновик"
),
"review": (
"Задача неоднозначна, работа завершена "
"или требуется решение человека"
),
},
),
"readiness": Score(
instructions="Насколько задача готова к редакционной проверке?",
criteria=[
"Ключевые данные отсутствуют",
"Основная работа сделана, но остаются существенные пробелы",
"Есть полный кандидат, который можно передать на проверку",
],
),
"needs_human_approval": Noul(
instructions=(
"Требует ли следующее действие подтверждения человека "
"до публикации или другого внешнего изменения?"
),
criteria={
"true": (
"Планируется публикация, отправка, удаление "
"или другое внешнее либо необратимое действие"
),
"false": (
"Следующее действие внутреннее, обратимое "
"и не изменяет внешние системы"
),
},
),
}
with TypeSafeClient() as client:
response = client.system_one(
state=state,
questions=questions,
)
next_worker = response.answers["next_worker"]
readiness = response.answers["readiness"]
approval = response.answers["needs_human_approval"]
destination = next_worker.choice
reasons = []
if next_worker.confidence < 0.65:
destination = "review"
reasons.append("низкая уверенность в выборе исполнителя")
if readiness.confidence < 0.60:
destination = "review"
reasons.append("неоднозначная оценка готовности")
if approval.noul >= 0.50:
destination = "review"
reasons.append("требуется подтверждение человека")
result = {
"created_at": datetime.now(timezone.utc).isoformat(),
"model": response.model,
"state": state,
"decision": {
"destination": destination,
"choice": next_worker.choice,
"choice_confidence": next_worker.confidence,
"choice_probabilities": next_worker.probabilities,
"readiness_score": readiness.score,
"readiness_confidence": readiness.confidence,
"readiness_probabilities": readiness.probabilities,
"human_approval_probability": approval.noul,
"review_reasons": reasons,
},
"usage": {
"input_tokens": response.usage.input_tokens,
"output_tokens": response.usage.output_tokens,
},
}
queue_dir = Path("queue") / destination
queue_dir.mkdir(parents=True, exist_ok=True)
output_path = queue_dir / f"task-{int(datetime.now().timestamp())}.json"
output_path.write_text(
json.dumps(result, ensure_ascii=False, indent=2, default=str),
encoding="utf-8",
)
print(f"Задача направлена: {destination}")
print(f"Решение сохранено: {output_path.resolve()}")Запустите файл:
python router.pyПроверяемый результат — сообщение с выбранным направлением и новый JSON-файл в одной из папок:
queue/research/
queue/write/
queue/review/Откройте файл и убедитесь, что в нём сохранены:
- версия модели;
- выбранный исполнитель;
- полное распределение вероятностей;
- оценка готовности;
- вероятность необходимости подтверждения;
- причины ручной проверки;
- расход токенов.
Папки пока работают как локальные очереди. Подключение реальных исследовательских, пишущих и проверяющих агентов — отдельный следующий шаг.
Пороги уверенности и ручная проверка
confidence у Choice и Score вычисляется из распределения вероятностей. Если вероятность сосредоточена на одном варианте, уверенность выше. Если несколько вариантов почти равны, она падает.[8]
Удобная начальная схема:
- высокая уверенность — выполнить обратимое действие автоматически;
- средняя — запросить подтверждение или дополнительные данные;
- низкая — ничего не делать и передать случай человеку.
Универсального порога нет. Он зависит от цены ошибки.
Показать пользователю не тот раздел интерфейса можно при сравнительно мягком пороге. Отправить письмо, удалить данные или подтвердить финансовую операцию следует только при более строгих условиях и с дополнительным подтверждением.
Порог 0.65 в примере служит отправной точкой. Настраивать его нужно на размеченных примерах из вашего процесса.
Проверяйте результат действия отдельно. Если агент должен создать файл, убедитесь, что файл существует. Если система отправляет сообщение, получите подтверждение сервиса. Если задача меняет данные, повторно прочитайте изменённый объект.
Проектирование вопросов
Качество интеграции зависит не только от модели. Большую роль играет то, какую задачу вы ей дали.
Передавайте структурированное состояние
Jev принимает строку, объект или массив текстовых значений. Для рабочих процессов лучше использовать JSON-объект с понятными названиями полей.[9]
Хорошо:
{
"goal": "Подготовить обзор",
"completed_work": ["Найдены два официальных источника"],
"source_count": 2,
"draft_exists": false
}Хуже:
Мы тут что-то нашли, но непонятно, достаточно ли этого.Структура снижает неоднозначность и позволяет явно ссылаться на нужные части состояния.
Один вопрос должен проверять одно свойство
Вопрос «Готов ли материал и можно ли его публиковать?» объединяет две разные проверки:
- готов ли текст;
- разрешена ли публикация.
Разделите их на Score готовности и Noul разрешения. После этого код сможет использовать для них разные пороги.
Описывайте границы вариантов
Варианты good, bad и other дают модели мало информации. Лучше объяснить, что входит в каждый вариант и чем он отличается от соседнего.
Для сложных границ instructions и criteria могут быть объектами или массивами, но начинать лучше с коротких строк.
Передавайте все независимые вопросы вместе
TypeSafe обрабатывает вопросы к одному состоянию независимо и параллельно. Поэтому классификацию, оценку готовности и проверку разрешения можно отправить одним запросом, а затем использовать только нужные ответы.[10]
Один вопрос не видит ответ другого. Если второе решение зависит от результата первого или от нового внешнего факта, выполните промежуточное действие и сформируйте следующий запрос.
Пересобирайте список вариантов
Если доступные инструменты меняются, не храните их список навсегда внутри промпта.
Сначала получите актуальный перечень исполнителей, моделей или действий. Затем сформируйте criteria для Choice. После изменения состояния пересоберите список.
Иначе модель будет выбирать из вчерашнего меню.
Обработка ошибок и ограничений
API использует стандартные HTTP-коды:[11]
| Код | Причина | Что делать |
401 | отсутствует или неверен ключ | проверить TYPESAFE_API_KEY |
422 | ошибка в структуре запроса | проверить поле, указанное в ответе |
429 | превышен лимит | повторить запрос с задержкой |
529 | временная перегрузка | повторить запрос позже |
Официальные SDK самостоятельно обрабатывают 429 и 529 с задержкой. Политику повторов можно настроить:
from typesafe_sdk import RetryPolicy, TypeSafeClient
client = TypeSafeClient(
retry=RetryPolicy(
max_retries=3,
backoff_max=0.2,
timeout=1.0,
)
)Не делайте бесконечные повторы. У процесса должны быть ограничения по числу вызовов, времени и расходам.
Для производственного использования сохраняйте:
- точную версию модели;
- состояние запроса или его безопасный идентификатор;
- вопросы и критерии;
- ответы и вероятности;
- применённые пороги;
- принятое кодом решение;
- фактический результат действия.
Если вы настроили пороги под определённую версию, закрепите идентификатор наподобие jev-1.13.0. Алиас jev-latest может перейти на новую модель без изменения вашего кода.[12]
Проверка качества перед внедрением
Дешёвый вызов не делает систему экономичной, если ошибочное решение запускает дорогого агента или неверный процесс.
Минимальная проверка:
- Соберите примеры из реального рабочего процесса.
- Разметьте ожидаемые решения вручную.
- Зафиксируйте версию модели и формулировки вопросов.
- Запустите выборку через Jev.
- Посчитайте ошибки отдельно для каждого решения.
- Изучите случаи с низкой и ошибочно высокой уверенностью.
- Настройте пороги автоматического действия.
- Проверьте пограничные и намеренно неоднозначные примеры.
- Измерьте стоимость завершённой задачи, а не отдельного вызова.
- Повторите тест перед обновлением модели или критериев.
Если процесс работает на русском языке, тестовая выборка должна быть русскоязычной. TypeSafe называет английский основным языком обучения и рекомендует отдельно проверять качество других языков.[12]
Полезные сценарии
Маршрутизация между агентами
Задача: выбрать исследователя, автора или проверяющего. Вход: цель, выполненная работа, доступные исполнители. Результат: выбранная очередь и вероятность каждого варианта. Ограничение: выполнение и проверка работы остаются за системой.
Распределение обращений
Задача: направить запрос в поддержку, продажи или биллинг. Вход: сообщение клиента и связанные сведения о заказе. Результат: категория, срочность и необходимость эскалации. Ограничение: возврат денег и другие действия выполняются по отдельным правилам.
Массовая классификация документов
Задача: разметить письма, отчёты или расшифровки по нескольким признакам. Вход: текст документа и набор независимых вопросов. Результат: структурированные признаки, пригодные для поиска и аналитики. Ограничение: вопросы должны быть определены заранее, а качество проверено на выборке.
Проверка действий агента
Задача: определить, можно ли выполнить вызов инструмента автоматически. Вход: предполагаемое действие, аргументы и правила проекта. Результат: вероятность риска и решение о ручной проверке. Ограничение: критичные запреты лучше дополнительно зафиксировать обычным кодом.
Выбор модели
Задача: направлять простые запросы дешёвой модели, сложные — более мощной. Вход: пользовательская задача и описание доступных моделей. Результат: выбранная модель и уверенность маршрутизатора. Ограничение: экономию нужно считать с учётом стоимости ошибочного маршрута.
LangChain предоставляет интеграцию TypeSafeClassifier и два экспериментальных middleware-компонента: для выбора модели и предварительной проверки вызовов инструментов. Их API может меняться. AutoModeMiddleware блокирует рискованный вызов, но само не запрашивает подтверждение человека; для этого его нужно сочетать с human-in-the-loop middleware.[13]
Ограничения текущей версии
По состоянию на 2026-09-20 актуальная стабильная версия — Jev 1.13.0.[12]
Основные параметры:
- стоимость — $0,042 за миллион входных токенов;
- выходные токены отдельно не тарифицируются;
- контекст — 64 тысячи токенов на запрос;
stateвместе с самым длинным вопросом — до 32 тысяч токенов;- ввод — только текст, JSON-объекты и массивы текстовых значений;
- изображения, аудио и видео напрямую не поддерживаются;
- один
Choiceпринимает до 255 вариантов; - лимиты сервиса могут меняться.
Заявленные TypeSafe ускорение и снижение стоимости относятся к задачам подходящей формы и собственным измерениям компании. Их нельзя автоматически переносить на любой рабочий процесс.[14]
По заявлению TypeSafe, Jev возвращает ответы в заданной структуре. Это защищает программу от выдуманного названия поля или варианта за пределами схемы, но не гарантирует правильность смыслового решения.
Чеклист перед запуском
other или none.Начните с одного повторяющегося решения, для которого у вас есть примеры правильных и неправильных ответов. Проверьте Jev на этих данных, настройте безопасную эскалацию и только затем подключайте следующую точку принятия решений.
Официальные ссылки
Следующий шаг
Agents API или Codex: как выбрать способ автоматизации
Связанные материалы
- Статья: Карпатый объяснил, почему вайб-кодинг и агентный инжиниринг — два разных мира
- Блог: Jev: TypeSafe представила модель для принятия решений
- База знаний: OpenAI Agents API: как устроены агенты, сессии и инструменты
Если в вашем процессе накопилось много небольших решений между агентами, инструментами и ручной проверкой, можно отдельно разобрать их риски и выбрать подходящие точки для Jev.
Если захотите обсудить, как это применить у себя или в команде — пишите в Telegram @pimenov