Чат-боты на Kotlin: создаем умного помощника с нуля

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему Kotlin — идеальный язык для чат-ботов?

Вы когда-нибудь задумывались, почему всё больше разработчиков выбирают Kotlin для создания чат-ботов? Этот язык — настоящий швейцарский нож в мире программирования. Он сочетает лаконичность Python, мощь Java и современные фишки, которые превращают написание бота из рутины в удовольствие.

Представьте: вы пишете бота для Telegram, который должен обрабатывать сотни запросов в секунду. На Python вы бы боролись с GIL (Global Interpreter Lock), на Java — тонули бы в шаблонном коде. Kotlin же предлагает корутины (coroutines) для асинхронности и нулевую стоимость абстракций. В этом руководстве мы создадим полноценного чат-бота с нуля — от регистрации в Telegram до деплоя на сервер.

Что вы получите в итоге?

  • Рабочего бота, который отвечает на команды и ведёт диалог
  • Понимание архитектуры чат-ботов на Kotlin
  • Готовый код, который можно сразу использовать в своих проектах

Шаг 1: Настройка окружения и получение токена

Первым делом вам понадобится токен бота. Идём в Telegram, находим @BotFather и создаём нового бота. Команда /newbot — и вы получаете заветный токен вида 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11. Сохраните его в local.properties — никогда не коммитьте токены в репозиторий!

Теперь создаём проект. Я рекомендую использовать Gradle Kotlin DSL — это современный стандарт. Вот минимальный build.gradle.kts:

plugins {
    kotlin("jvm") version "1.9.22"
    application
}

dependencies {
    implementation("io.ktor:ktor-client-core:2.3.7")
    implementation("io.ktor:ktor-client-cio:2.3.7")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
    implementation("com.google.code.gson:gson:2.10.1")
}

application {
    mainClass.set("MainKt")
}

Обратите внимание: мы используем Ktor Client для HTTP-запросов к Telegram API и Gson для парсинга JSON. Kotlin сериализация тоже подойдёт, но Gson проще для старта.

Шаг 2: Базовая структура бота

Любой чат-бот — это бесконечный цикл: получаем обновление → обрабатываем → отправляем ответ. В Telegram используется long polling (метод getUpdates) или вебхуки. Мы реализуем polling — он проще для локальной разработки.

Создаём базовый класс TelegramBot:

class TelegramBot(private val token: String) {
    private val client = HttpClient(CIO)
    private val baseUrl = "https://api.telegram.org/bot$token"

    suspend fun getUpdates(offset: Long = 0): List<Update> {
        val response: HttpResponse = client.get("$baseUrl/getUpdates") {
            parameter("offset", offset)
            parameter("timeout", 30)
        }
        val body = response.body<String>()
        val apiResponse = Gson().fromJson(body, ApiResponse::class.java)
        return apiResponse.result ?: emptyList()
    }

    suspend fun sendMessage(chatId: Long, text: String) {
        client.post("$baseUrl/sendMessage") {
            parameter("chat_id", chatId)
            parameter("text", text)
        }
    }
}

Класс Update — это data class, который маппится на JSON-ответ от Telegram. Вот как он выглядит:

data class Update(
    @SerializedName("update_id") val updateId: Long,
    val message: Message? = null
)

data class Message(
    @SerializedName("message_id") val messageId: Long,
    val text: String? = null,
    val chat: Chat
)

data class Chat(val id: Long)
data class ApiResponse(
    val ok: Boolean,
    val result: List<Update>? = null
)

Шаг 3: Обработка команд — сердце бота

Теперь самое интересное — научим бота понимать команды. В Kotlin это можно сделать элегантно через sealed class и when-выражения. Создадим диспетчер команд:

sealed class Command {
    data class Start(val chatId: Long) : Command()
    data class Help(val chatId: Long) : Command()
    data class Echo(val chatId: Long, val text: String) : Command()
}

class CommandParser {
    fun parse(update: Update): Command? {
        val message = update.message ?: return null
        val text = message.text ?: return null
        val chatId = message.chat.id

        return when {
            text == "/start" -> Command.Start(chatId)
            text == "/help" -> Command.Help(chatId)
            text.startsWith("/") -> null // неизвестная команда
            else -> Command.Echo(chatId, text)
        }
    }
}

Обратите внимание на sealed class — это мощный инструмент Kotlin, который гарантирует, что мы обработали все возможные команды. Компилятор сам подскажет, если вы что-то забыли.

Реализуем обработчик

class CommandHandler(private val bot: TelegramBot) {
    suspend fun handle(command: Command) {
        when (command) {
            is Command.Start -> bot.sendMessage(command.chatId, 
                "Привет! Я бот на Kotlin. Напиши /help для списка команд.")
            is Command.Help -> bot.sendMessage(command.chatId, 
                "Доступные команды:\n/start - начать\n/help - помощь\nЛюбой текст - эхо")
            is Command.Echo -> bot.sendMessage(command.chatId, 
                "Вы написали: ${command.text}")
        }
    }
}

Шаг 4: Главный цикл — всё собираем вместе

Теперь соединяем компоненты в main функции. Используем корутины для асинхронной обработки:

suspend fun main() {
    val token = System.getenv("BOT_TOKEN") ?: throw IllegalStateException("Токен не найден")
    val bot = TelegramBot(token)
    val parser = CommandParser()
    val handler = CommandHandler(bot)

    var lastUpdateId = 0L
    println("Бот запущен и ждёт команды...")

    while (true) {
        val updates = bot.getUpdates(lastUpdateId + 1)
        for (update in updates) {
            val command = parser.parse(update)
            if (command != null) {
                handler.handle(command)
            }
            lastUpdateId = maxOf(lastUpdateId, update.updateId)
        }
        delay(1000) // пауза 1 секунда, чтобы не спамить API
    }
}

Запускаем — и ваш первый чат-бот на Kotlin жив! Напишите ему /start в Telegram, и он ответит приветствием.

Шаг 5: Продвинутые сценарии — конечные автоматы

Простое эхо — это скучно. Давайте добавим конечный автомат (FSM) для сложных диалогов. Например, бот-опросник:

enum class UserState {
    IDLE, WAITING_NAME, WAITING_AGE, WAITING_CITY
}

class FsmBot(private val bot: TelegramBot) {
    private                

Блоги

Рекомендаций по книгам