Демо «умный дом» на Jev: команды на естественном языке → действия
В документации TypeSafe есть демо ассистента для умного дома. Пользователь пишет команду обычными словами, а Jev раскладывает её на решения, которые выполняет код. Разбираем, как устроено демо, где в нём нужна LLM и как повторить схему в своём проекте.
Что это за демо
В разделе Demos документации TypeSafe пока одно демо — ассистент для умного дома. Пользователь пишет запрос обычными словами, а приложение решает, что делать: переключить устройство, ответить на вопрос или просто поддержать разговор. Демо собрано как простое одностраничное приложение на Vite и React, которое обращается к API TypeSafe. Видео работы есть прямо в документации.
Исходники TypeSafe обещает выложить на GitHub вместе с README, где описано, какой код за что отвечает. На момент написания в официальном аккаунте компании их нет, поэтому ниже — разбор по описанию в документации и наш пример запроса в формате API.
Главный приём: все вопросы сразу
Возьмём команду «Выключи весь свет в доме». Чтобы её выполнить, коду нужны четыре ответа:
- Что это за запрос? — Команда умному дому.
- К какой зоне он относится? — Весь дом.
- Какие устройства? — Свет.
- Что сделать со светом? — Выключить.
Четвёртый вопрос имеет смысл, только если речь о свете. Но демо задаёт его сразу, ещё не зная, о чём просит пользователь. TypeSafe называет такие вопросы спекулятивными: все они считаются параллельно в одном запросе, а лишние ответы код просто отбрасывает. На этом паттерне построено всё демо, подробнее о нём — в статье о speculative fan-out.
Неправильный путь — спрашивать по очереди: сначала тип запроса, потом зону и устройство, потом действие. Число вопросов минимально, но, по словам TypeSafe, такая цепочка выходит заметно медленнее и дороже одного общего запроса. Каждый вызов заново передаёт команду и служебные токены, а пользователь ждёт несколько ответов сети подряд.
Как может выглядеть запрос
Это наш пример в формате API, а не код демо:
{
"model": "jev-latest",
"state": { "command": "Выключи весь свет в доме" },
"questions": {
"category": {
"type": "choice",
"instructions": "Что хочет пользователь в `command`?",
"criteria": {
"device_command": "Изменить состояние устройства",
"info": "Узнать факт: погоду, время, справку",
"chat": "Поговорить или что-то другое"
}
},
"zone": {
"type": "choice",
"instructions": "К какой части дома относится `command`?",
"criteria": {
"whole_house": "Весь дом",
"kitchen": "Кухня",
"bedroom": "Спальня",
"not_stated": "Зона не названа"
}
},
"device": {
"type": "choice",
"instructions": "Каким устройством хочет управлять пользователь?",
"criteria": {
"lights": "Свет, лампы, люстры",
"climate": "Отопление, кондиционер, термостат",
"blinds": "Шторы и жалюзи",
"other": null
}
},
"light_action": {
"type": "choice",
"instructions": "Если речь о свете, что с ним сделать?",
"criteria": { "on": "Включить", "off": "Выключить", "dim": "Приглушить" }
},
"is_compound": {
"type": "noul",
"instructions": "В `command` больше одного отдельного действия?"
}
}
}
Дальше решает код:
a = response.answers
if a["category"].choice == "device_command" and a["is_compound"].noul < 0.5:
if a["zone"].confidence < 0.6:
ask_user("В какой комнате?")
elif a["device"].choice == "lights":
set_lights(zone=a["zone"].choice, action=a["light_action"].choice)
Пороги 0,5 и 0,6 здесь условные. Подбирайте их на своих командах, как описано в статье об уверенности Jev.
Где в демо работает LLM
Jev не генерирует текст, поэтому демо подключает обычную языковую модель в двух местах.
Составные команды. Один из вопросов — Noul: просит ли пользователь больше одного отдельного действия. Если да, LLM разбивает фразу вроде «выключи свет на кухне и опусти шторы в спальне» на список простых команд. Каждую из них Jev затем оценивает отдельно.
Вопросы и разговор. Если Jev определила, что пользователь спрашивает о чём-то или просто общается, демо зовёт LLM, и та пишет свободный ответ. Известные команды обрабатываются быстро и дёшево, а гибкость генеративной модели остаётся для всего остального. По словам TypeSafe, первый ответ Jev приходит настолько быстрее ответа LLM, что почти не добавляет задержки. Эту связку подробнее разбираем в статье о каскаде Jev и LLM.
По сути это частный случай паттерна intent routing из документации TypeSafe. Jev быстро классифицирует запрос, после чего часть запросов обрабатывает обычный код без LLM, часть уходит в языковую модель с нужным контекстом, а неуверенные случаи — человеку. В умном доме таким человеком становится сам пользователь: переспросить дешевле, чем включить не тот прибор.
Аргументы команды: что спрашивать у Jev, а что нет
Полезное дополнение к демо — рецепт Function calling из документации TypeSafe. Он превращает фразы на естественном языке в вызовы обычных функций, и для умного дома подходит почти без изменений.
- Значения из закрытого списка — комната, устройство, режим — задаются как Choice ровно по тем вариантам, которые принимает функция. Что бы ни ответила модель, в функцию попадёт допустимое значение.
- Необязательные аргументы получают дополнительный Noul: говорит ли пользователь об этом вообще. Если нет, функция берёт значение по умолчанию. Без такого вопроса Choice уверенно назовёт хоть какой-то вариант.
- Числа, даты и свободный текст в рецепте вопросов не получают. Для команды «поставь 22 градуса» это важно: TypeSafe пишет, что Jev не калькулятор и с числами работает хуже, чем со смыслом. Число извлеките регулярным выражением или LLM, а Jev оставьте выбор из готовых кандидатов.
- Уверенность всей команды рецепт считает по самому неуверенному ответу, а не перемножает вероятности: одного неверного аргумента хватает, чтобы испортить вызов.
Похожий подход описывает Флавио Копес. В одном из демо сообщества чат-бот без генеративной модели выбирал инструмент и его аргументы через Choice и выключал свет по обычной фразе примерно за 300 мс от запроса до результата.
Как расширять набор команд
Новое устройство в такой схеме — это новый вариант в device и ещё один спекулятивный вопрос о действии для него. Запрос растёт на токены этого вопроса, а время ответа почти не меняется: вопросы считаются параллельно. Масштаб у подхода приличный. В рецепте Function calling один запрос несёт 54 вопроса: выбор из десяти функций и аргументы сразу для всех.
Упираться придётся в два лимита. В одном Choice не больше 255 вариантов, а весь запрос должен уложиться в 64 тыс. токенов. Если ламп у вас сотни и у каждой своё имя, выбирайте в два шага: сначала зону или группу, потом устройство внутри неё. Типы вопросов и их ограничения подробно разобраны в статье о примитивах Jev.
Перед запуском соберите тестовый набор: простые команды, составные, вопросы, болтовню и фразы с ошибками. Если команды приходят из распознавания речи, добавьте в набор реальные расшифровки с опечатками. Сравните ответы с ручной разметкой по каждому вопросу отдельно — так видно, где проседает зона, а где действие.
Безопасность и русский язык
Опасные действия подтверждайте. Выключить свет можно и при средней уверенности. Открыть замок или снять дом с охраны — только при высокой уверенности и после подтверждения пользователем. Для рискованных действий держите отдельный, более строгий порог.
Пишите условия буквально. По данным TypeSafe, Jev отвечает на вопрос, который вы написали, а не на тот, который имели в виду: отрицания и подразумеваемые условия она читает дословно. Точное условие пишите в instructions, а пограничные случаи — в criteria.
Проверьте враждебный текст. Компания признаёт, что текст, специально написанный, чтобы увести модель, может сдвинуть ответ. Прогоните странные и провокационные команды до запуска.
Проверьте язык. Английский — основной язык обучения Jev, на нём точность лучше всего. Другие языки модель понимает, но TypeSafe советует проверять качество на своих данных. Для русскоязычного ассистента соберите пару сотен реальных команд и сравните ответы модели с ручной разметкой.
Итог
Демо умного дома показывает рабочую схему для любого интерфейса команд на естественном языке. Jev за один запрос раскладывает фразу на тип, зону, устройство и действие. Код выполняет команду и проверяет уверенность. LLM подключается только для составных фраз и свободного разговора. Та же логика подходит для чат-ботов поддержки и внутренних инструментов, а игровые демо TypeSafe с похожими принципами разобраны в статье про Doom и викирейсинг.
Частые вопросы
Можно ли управлять умным домом через Jev?
Да, у TypeSafe есть такое демо. Jev определяет тип запроса, зону, устройство и действие, а команду выполняет ваш код. Для составных команд и свободного разговора демо подключает обычную LLM.
Понимает ли Jev команды на русском?
Модель принимает текст на разных языках, но TypeSafe пишет, что точнее всего она работает на английском. Перед запуском проверьте качество на своих русских командах.
Где взять код демо умного дома?
По словам TypeSafe, демо — одностраничное приложение на Vite и React, а исходники появятся на GitHub. На момент написания в официальном GitHub-аккаунте компании их нет.
Как Jev справляется с температурой и другими числами?
Хуже, чем со смыслом. TypeSafe советует не поручать модели арифметику и точные числа. Число лучше извлечь кодом, а Jev оставить выбор из готовых вариантов.