Навык Алисы на TypeScript: создание с нуля на Node.js и umbot

Пошаговая разработка навыка для Яндекс.Алисы на TypeScript и Node.js: команды, шаги диалога, формы, кнопки, TTS, отладка в консоли и частые ошибки новичка.

Навык Алисы на TypeScript: создание с нуля на Node.js и umbot

26 Сентября, 2026 Автор: Максим М

Навык Алисы на TypeScript: создание с нуля на Node.js и umbot

Пошагово: от установки до работающего навыка с кнопками, голосом, формами и тестами в консоли.

Большинство руководств по созданию навыка для Алисы начинается с «чистого Node.js»: вручную собрать JSON ответа, вручную следить за лимитом в 1024 символа, руками писать tts и надеяться не опечататься в end_session. Работает — но при каждом изменении ответа вы пересобираете структуру заново, а первый же баг в формате ловится только на опубликованном навыке. Мы пойдём другим путём: навык на TypeScript, где типы описывают формат ответа, а рутину берёт фреймворк umbot. Разберём создание навыка для Яндекс.Алисы с нуля — от установки Node.js до диалога с кнопками, шагами и TTS в консоли вашего компьютера.

Как устроен навык Алисы: 30 секунд теории

Навык — это обычный HTTPS-сервер. Когда пользователь говорит с навыком, Яндекс.Диалоги отправляют на ваш адрес (вебхук) POST-запрос с JSON: что сказал пользователь (request.command), данные сессии и сохранённое состояние. Ваш сервер за несколько секунд должен вернуть JSON с текстом ответа, голосом (tts), кнопками и признаком завершения сессии. Всё. Фреймворк нужен, чтобы вы писали не этот JSON, а логику диалога.

Шаг 1. Создание проекта

Установите Node.js 20+ и выполните:

npx umbot create my-skill
cd my-skill
npm install
npm run build
npm start

CLI разворачивает готовый проект: точку входа src/index.ts, конфигурацию, класс-контроллер и tsconfig.json. В .gitignore уже внесён .env — токены не уедут в репозиторий. Сам файл .env с шаблонами переменных создайте одной командой:

npx umbot add env

Для быстрого прототипа есть флаг --minimal: он создаёт рабочий проект без класса-контроллера — вся логика пишется в одном файле через addCommand. Именно такой стиль используется в примерах ниже.

Шаг 2. Логика навыка: команды и фразы-синонимы

Основной способ описания логики — регистрация команд списком фраз-синонимов. Типовой навык из getting-started:

import { Bot, WELCOME_INTENT_NAME, FALLBACK_COMMAND } from 'umbot';
import { voicePlatforms } from 'umbot/plugins';

const bot = new Bot()
    .use(voicePlatforms) // Алиса, Маруся, SmartApp
    .setAppConfig({ isLocalStorage: true });

// Приветствие — на фразы из списка
bot.addCommand(WELCOME_INTENT_NAME, ['привет'], (_, bc) => {
    bc.text = 'Привет! Я новый навык.';
    bc.buttons.addBtn('Помощь');
});

// Команда со списком фраз-синонимов
bot.addCommand('help', ['помощь', 'что ты умеешь'], (_, bc) => {
    bc.text = 'Я умею отвечать на команды и показывать кнопки.';
});

// Fallback — ловит всё, что не совпало с командами
bot.addCommand(FALLBACK_COMMAND, [], (userCommand, bc) => {
    if (bc.messageId === 0) {
        // первый запрос сессии: «Алиса, запусти навык ...»
        bc.text = 'Привет! Я новый навык. Скажите «помощь», чтобы узнать, что я умею.';
        bc.buttons.addBtn('Помощь');
        return;
    }
    bc.text = `Не знаю команду «${userCommand}». Скажите «помощь».`;
});

bot.start('localhost', 3000);

Что здесь важно: WELCOME_INTENT_NAME — имя интента приветствия, FALLBACK_COMMAND ловит нераспознанное. Тонкость, о которую спотыкаются почти все: при запуске навыка («Алиса, запусти навык…») команда пустая, и если fallback зарегистрирован, первым сработает именно он, а не приветствие. Поэтому начало сессии обрабатывается в fallback по bc.messageId === 0 — иначе на запуск навык ответит «не знаю команду», и такой навык не пройдёт модерацию. Ввод пользователя приводится к нижнему регистру, поэтому фразы пишутся в нижнем. Слоты можно задавать и регулярными выражениями — фреймворк проверяет их на ReDoS-уязвимости до выполнения.

Свои интенты со слотами регистрируются через setPlatformParams:

bot.setPlatformParams({
    intents: [
        { name: 'help', slots: ['помощь', 'что ты умеешь'] },
    ],
});

Важно: переданный массив интентов заменяет встроенные welcome/help — либо добавьте их в свой список, либо задайте свои слоты для приветствия и помощи. Нативные NLU-интенты, настроенные в консоли Яндекс.Диалогов, при этом тоже доступны: распознанное придёт в nlu.intents запроса.

Шаг 3. Шаги диалога и состояние пользователя

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

bot.addCommand('game_start', ['играть', 'начать игру'], (_, bc) => {
    bc.userData.score = 0; // состояние пользователя
    bc.text = 'Игра началась! Сколько будет 2+2?';
    bc.buttons.addBtn('3').addBtn('4').addBtn('5');
    bc.thisIntentName = 'game_answer'; // следующий ответ обработает шаг
});

bot.addStep('game_answer', (bc) => {
    if (bc.userCommand === '4') {
        bc.userData.score = Number(bc.userData.score ?? 0) + 1;
        bc.text = 'Правильно!';
    } else {
        bc.text = 'Неправильно.';
    }
    bc.thisIntentName = null; // выходим из шага
});

userData — встроенное состояние: у голосовых платформ оно хранится в хранилище платформы (приходит в каждом запросе), поэтому для навыка Алисы отдельная БД на старте не нужна.

Шаг 4. Формы: сбор данных в несколько вопросов

Частая задача навыка — задать пользователю несколько вопросов подряд: имя, телефон, дату записи. На шагах это десяток обработчиков; для таких случаев есть addForm — поля, валидация и итоговый обработчик в одном месте:

bot.addForm('registration', {
    fields: [
        { name: 'name', prompt: 'Как вас зовут?', validate: (v) => v.length > 0 },
        { name: 'age', prompt: 'Сколько вам лет?', validate: (v) => +v > 0 || 'Возраст должен быть числом' },
    ],
    onComplete: (bc, answers) => {
        bc.text = `Спасибо, ${answers.name}!`;
    },
});

// Запуск формы из команды
bot.addCommand('start_signup', ['зарегистрироваться'], (_, bc) => {
    bc.thisIntentName = '__form_registration_0';
    bc.text = 'Как вас зовут?'; // первый вопрос формы
});

Если ответ не прошёл валидацию, навык повторит вопрос с текстом ошибки. Промежуточные ответы хранятся в userData, так что форма переживает паузы между репликами.

Шаг 5. Кнопки, карточки, голос

  • Кнопки: bc.buttons.addBtn('Да').addBtn('Нет') — единый API, адаптер Алисы сам разложит их по формату платформы и обрежет по лимитам.
  • Карточки: bc.card.addOneImage('image.jpg', 'Заголовок', 'Описание') — одиночная карточка BigImage; addImage() — список до 5 элементов, галерея — до 10.
  • Голос: bc.tts задаётся отдельно от текста — то, что услышит пользователь, может отличаться от того, что он увидит на экране. Стандартные звуки и эффекты Алисы и паузы в речи — через SoundConstants.
  • Медиа: изображение по URL или пути загрузится на платформу при первом использовании, его идентификатор закэшируется — повторные показы мгновенны. Для загрузки картинок в Алису понадобится OAuth-токен навыка.

Шаг 6. Запуск и отладка в консоли

После npm run build и npm start навык слушает вебхук на порту 3000. Но до деплоя его можно проверить прямо в терминале. Для этого при создании проекта укажите режим dev в JSON-конфигурации CLI — тогда точка входа соберётся не вокруг HTTP-сервера, а вокруг класса BotTest:

// my-skill.json — конфигурация для CLI
{
    "name": "my-skill",
    "mode": "dev",
    "isEnv": true
}
npx umbot create my-skill.json

Сгенерированная точка входа выглядит так (сокращённо):

import { BotTest } from 'umbot/test';
import { fullPlatforms } from 'umbot/plugins';

const bot = new BotTest();
bot.use(fullPlatforms);
// ...конфигурация и контроллер из шаблона...
bot.test(); // вводите фразы — получаете ответы навыка

Метод test() принимает опции: isShowResult покажет полный JSON ответа платформы, isShowStorage — что навык запомнил о пользователе, isShowTime — время обработки. Для выхода введите exit. Так вы проверяете и лимит в 1024 символа, и структуру кнопок до того, как их увидит модерация. Подробнее — в статье про тестирование навыка без публикации.

Шаг 7. Подключение к Яндекс.Диалогам

  • Создайте навык в консоли Яндекс.Диалогов (тип «Навык в Алисе»).
  • Для проверки с локального компьютера поднимите туннель (ngrok, cloudflared) до порта 3000 и укажите выданный HTTPS-адрес в поле Webhook URL.
  • Откройте вкладку «Тестирование» в консоли и поговорите с навыком — запросы пойдут на ваш компьютер.
  • Для постоянной работы разверните приложение на сервере или в облаке — пошагово в документации по развёртыванию или в статье про навык на serverless.

Частые ошибки новичков

  • Фразы-слоты в верхнем регистре. Ввод приводится к нижнему регистру — слот 'Привет' никогда не сработает, пишите 'привет'.
  • Навык молчит или «не понимает» при запуске. Приветствие со списком фраз не срабатывает на пустую команду запуска, если зарегистрирован fallback — обработайте messageId === 0 в fallback, как в примере выше.
  • Нет fallback-команды. Пользователь скажет что-то вне сценария — и навык ответит невнятным дефолтом. FALLBACK_COMMAND обязателен.
  • Переопределили интенты и потеряли приветствие. Свой список intents в setPlatformParams заменяет встроенные — не забудьте вернуть welcome/help.
  • Текст длиннее 1024 символов. Фреймворк обрежет его до лимита, и пользователь не услышит конец ответа. Длинный текст разбивайте на шаги.
  • Медиа грузится в момент ответа. Первая загрузка изображения может занять заметную часть времени на ответ — предзагружайте медиа через Preload до старта.
  • Забыли выйти из шага. Если не сбросить thisIntentName, все следующие фразы пользователя попадут в тот же шаг.

Куда дальше

Рекомендую к прочтению следующие статьи:

Telegraf или grammY — что выбрать для Telegram-бота в 2026?

Telegraf или grammY — что выбрать для Telegram-бота в 2026?

Честное сравнение Telegraf и grammY с примерами кода и таблицей: типы, плагины, вебхуки — и когда вместо библиотеки нужен мультиплатформенный фреймворк.

Читать статью

Сколько стоит разработка навыка для Алисы в 2026 году

Сколько стоит разработка навыка для Алисы в 2026 году

Сколько стоит навык для Алисы: цены от 5 000 ₽, что влияет на стоимость, три уровня сложности, доли бюджета по этапам и как сэкономить без потери качества.

Читать статью

Конструктор навыков Алисы или разработка на фреймворке: что выбрать

Конструктор навыков Алисы или разработка на фреймворке: что выбрать

Когда хватит конструктора навыков для Алисы без программирования, а когда нужны фреймворк и разработчик: потолок конструкторов, логика и владение продуктом.

Читать статью

Навык для Алисы без своего сервера: serverless на Yandex Cloud

Навык для Алисы без своего сервера: serverless на Yandex Cloud

Как запустить навык Алисы в Yandex Cloud Functions без своего сервера: генерация serverless-проекта через CLI umbot, деплой, публичный вызов и лимиты.

Читать статью

Бот для мессенджера MAX: создание на typescript и Node.js

Бот для мессенджера MAX: создание на typescript и Node.js

Создание бота для мессенджера MAX на Node.js: регистрация, подключение вебхука, отличия API от Telegram и VK, лимиты отправки и пример бота на фреймворке umbot.

Читать статью

Комментарии

Оставить комментарий

Как со мной связаться?

Свяжитесь со мной по любому поводу!
Я с радостью отвечу на все вопросы!

Телефон:

+7(909) 281 35-20

Дополнительная почта:

info@maxim-m.ru

Я в социальных сетях:

ВверхВверх 👆