Почему Kotlin Multiplatform для AI-агентов — это не просто мода, а вынужденная необходимость
В 2026 году писать отдельные кодовые базы для Android, iOS, Web и Desktop для одного AI-агента — это все равно что вручную настраивать каждый микросервис. Тратишь 80% времени на борьбу с платформенными причудами, а не на логику самого агента. Kotlin Multiplatform (KMP) обещает один код для всех платформ. Звучит как рай для разработчика, пока не пытаешься запихнуть туда модель Mistral-7B или GPT-4 Mini, которая весит 4 ГБ.
Проблема в двух словах: AI-агенты требуют сложной логики (планирование, цепочки мыслей, работа с инструментами), но при этом должны быть легкими, чтобы работать на iPhone 15 Pro и старом Android-смартфоне одновременно. Плюс, каждый магазин приложений имеет свои правила по обработке данных и размеру бандла. Пишешь на Python? Забудь о мобильных устройствах. Используешь Flutter? Готовься к сложной интеграции нативных AI-библиотек. KMP — это попытка взять лучшее от обоих миров: общую бизнес-логику на Kotlin и платформенную оптимизацию там, где это критично.
Архитектурный выбор: что оставить в common, а что выкинуть в platform
Самая большая ошибка — пытаться все запихнуть в общий код. Упаковывать вызовы к нейросетям, работу с камерой или доступ к файловой системе в common модуль — верный путь к хрупкому и неподдерживаемому коду. Вместо этого разделяй логику агента (что он делает) от исполнения (как он это делает).
- Common (Kotlin Multiplatform): State-машина агента, планировщик задач, обработка промптов, управление памятью (что обсуждали с пользователем), логика выбора инструментов. По сути, мозг без рук и ног.
- Platform-specific (Android, iOS, JS, Desktop): Всё, что касается железа и операционки: запуск моделей (инференс), доступ к сенсорам, запись в файлы, UI-рендеринг. Для работы с локальными LLM в 2026 году это чаще всего означает использование платформенно-оптимизированных рантаймов вроде MLC-LLM или Llama.cpp через Kotlin/Native или C-interop.
1 Настройка проекта: не повторяй моих ошибок с Gradle
Создавая новый проект в IntelliJ IDEA с плагином KMP, ты получаешь шаблонный build.gradle.kts. Он сломан для AI-проектов из коробки. Почему? Потому что не включает зависимости для работы с большими бинарными файлами (моделями) и нативными библиотеками.
Вот как надо делать. Сначала создаем структуру модулей:
// settings.gradle.kts
pluginManagement {
repositories {
mavenCentral()
google()
gradlePluginPortal()
}
}
include(":shared") // Общая логика агента
include(":androidApp")
include(":iosApp")
include(":desktopApp")
include(":webApp")
В build.gradle.kts общего модуля :shared добавляем необходимые зависимости. На февраль 2026 года актуальны:
- Kotlinx Serialization 2.1.0 — для работы с промптами и ответами моделей в JSON.
- Kotlinx Coroutines 1.9.0 — асинхронность, без этого никуда.
- KMP-обертка для Model Context Protocol (MCP) SDK 0.5.0 — если твой агент должен работать с внешними инструментами и данными (базы данных, API, файлы). MCP стал стандартом де-факто для подключения инструментов к агентам.
- Ktor Client 3.8.0 — для общения с облачными API моделей (если используешь гибридный подход).
Ошибка №1: Не добавляй тяжелые зависимости для инференса моделей (типа TensorFlow Lite) в commonMain. Они будут тянуться на все платформы и взорвут размер бандла. Вместо этого объяви expect/actual интерфейсы для инференса, а реализацию сделай в каждом целевом модуле.
2 Дизайн ядра агента: забудь о монолитных промптах
Самый примитивный агент — это одна большая функция, которая получает промпт и возвращает ответ от LLM. Он сломается при первой же сложной задаче. Современный агент — это stateful-система с памятью, планировщиком и набором инструментов. В common модуле определяем ключевые компоненты.
Основной цикл агента может выглядеть так (упрощенно):
// shared/src/commonMain/kotlin/com/youraibot/core/Agent.kt
class TaskPlanningAgent(
private val llmClient: LLMClient, // expect interface
private val toolRegistry: ToolRegistry,
private val memory: AgentMemory
) {
suspend fun execute(goal: String): Result {
// 1. Планировщик разбивает цель на шаги
val plan = planner.createPlan(goal)
// 2. Исполнитель выполняет каждый шаг, используя инструменты
for (step in plan.steps) {
val tool = toolRegistry.getTool(step.toolName)
val observation = tool.execute(step.parameters)
memory.addObservation(observation)
// 3. Рефлексия: оцениваем, движемся ли к цели
if (shouldReplan(observation)) {
return execute(adjustedGoal) // репланируем
}
}
return Result.success(memory.getFinalResult())
}
}
Это концептуальная схема. Для реальной работы изучи наше руководство по проектированию современных AI-агентов, где разобраны паттерны ReAct, Planner-Executor и потоковая память.
3 Интеграция моделей: локальные vs облачные, бинарные артефакты и боль
Здесь собака зарыта. В common модуле объявляем интерфейс LLMClient:
// shared/src/commonMain/kotlin/com/youraibot/core/LLMClient.kt
expect class LLMClient {
suspend fun generate(prompt: String, options: GenerationOptions): String
suspend fun generateStreaming(prompt: String): Flow
}
// Параметры генерации
data class GenerationOptions(
val maxTokens: Int = 512,
val temperature: Float = 0.7f,
val stopSequences: List = emptyList()
)
А теперь actual реализации. Для Android (в модуле :androidApp) используем, например, TFLite с загруженной моделью Qwen2.5-Coder-3B-Instruct (актуальная на 2026 компактная модель для кода). Для iOS тот же llama.cpp, но собранный под arm64. Для Desktop (JVM) можно использовать более тяжелые модели через ONNX Runtime. Для Web — здесь самое сложное: либо WebGPU + ONNX WebAssembly, либо fallback на облачный API.
4 Интерфейс: Compose Multiplatform или нативные экраны для каждого?
Compose Multiplatform в 2026 году стабилен для Android, Desktop и Web. Для iOS он все еще считается experimental, но уже работает. Если твой агент требует сложных, анимированных интерфейсов с графиками состояний — можешь рискнуть. Но если нужен нативный look-and-feel на iOS, готовься писать UI на SwiftUI и связывать его с KMP через Kotlin/Native кпдф.
Логику представления (ViewModel) все равно выноси в common. А вот реализацию Composable-функций — в соответствующие модули :compose-ui (для общих экранов) или в платформенные модули.
// shared/src/commonMain/kotlin/com/youraibot/presentation/ChatViewModel.kt
class ChatViewModel(
private val agent: TaskPlanningAgent
) : ViewModel() {
val uiState: StateFlow = ...
fun onUserMessageSent(text: String) {
viewModelScope.launch {
val agentResponse = agent.execute(text)
// Обновляем состояние
}
}
}
// :compose-ui/src/commonMain/kotlin/com/youraibot/ui/ChatScreen.kt
@Composable
expect fun ChatScreen(viewModel: ChatViewModel)
5 Тестирование: как отлаживать агента, который ведет себя по-разному на Snapdragon и Apple Silicon
Юнит-тесты для common логики — стандартно. Интеграционные тесты — ад. Поведение LLM недетерминировано, а еще оно зависит от точности вычислений с плавающей точкой на разных процессорах. Решение: мокировать LLMClient и тестировать только логику принятия решений агентом. Для тестов, близких к реальности, используй симуляторы.
Например, для тестирования навыка автоматизации Android (как в нашем обзоре touch-контроля) потребуется эмулятор или реальное устройство. Настрой CI/CD, который запускает такие тесты на ферме устройств.
6 Сборка и деплой: когда App Store спрашивает, что за бинарные файлы в твоем приложении
Включение предобученных моделей в бандл требует пояснений для ревьюеров магазинов. Готовь документацию о том, как модель используется, какие данные обрабатывает (желательно, локально) и откуда она скачана. Используй ресурсные папки для мелких моделей (до 100 МБ) и внешнее скачивание для больших.
Для подписи нативных библиотек (.so, .dylib) на Android и iOS потребуется корректно настроить задачи сборки в Gradle. На этом этапе многие сдаются и переходят на облачные API. Не сдавайся.
Чего точно делать не надо: грабли, на которые мы все наступали
- Не храни промпты как строки в коде. Выноси их в ресурсы или отдельные конфигурационные файлы. Менять промпт для улучшения агента должно быть так же просто, как редактирование JSON.
- Не игнорируйте квоты памяти на iOS. Локальная LLM, работающая в фоне, может быть убита системой. Используй background tasks и правильно обрабатывай приостановку состояния.
- Не рассчитывай на одинаковую производительность инференса. Модель, которая генерирует 20 токенов в секунду на MacBook M3, на среднем Android будет выдавать 2-3 токена. Проектируй UX с индикаторами прогресса и возможностью прерывания длительных операций.
- Не пренебрегай обновлением моделей. За год выходят более качественные и эффективные версии. Заранее продумай в приложении механизм обновления моделей без переустановки всего апка. (Спойлер: это сложно).
Вопросы, которые тебе зададут на тех-интервью (и правильные ответы)
| Вопрос | Короткий ответ | Что сказать подробнее |
|---|---|---|
| Как организовать потоковую генерацию текста из общей модели на всех платформах? | Kotlin Flow в common, платформенные драйверы моделей должны поддерживать поточную отдачу токенов. | Объясни разницу между blocking вызовом модели и callback-based streaming API на разных платформах. Покажи, как обернуть нативный callback в Flow. |
| Какой инструмент выбрать для создания агента, если не хочешь писать всё с нуля? | В 2026 году посмотри на open-source фреймворки из нашего обзора AI-агентов недели, а также на OpenAI Agent SDK для Java. | Большинство фреймворков написаны на Python. Для KMP придется либо искать Java/Kotlin аналоги, либо писать свои обертки. |
| Можно ли вообще обойтись без сервера для сложного агента? | Да, но с оговорками. Локальные модели на устройствах стали мощнее, но для сложных цепочек с поиском в интернете или обработкой больших PDF все равно нужен прокси-сервер. | Объясни гибридную архитектуру: легкий агент на устройстве + облачные функции для тяжелых операций. Это баланс между приватностью и функциональностью. |
И последнее. Самый важный навык в разработке AI-агентов на KMP — не знание Kotlin, а умение разбивать задачу на общие и платформенные части. Начинай с простого агента с одной облачной моделью, выноси логику в common, затем заменяй облачный вызов на локальные реализации одну за другой. Так не сойдешь с ума. А когда заработает, вспомни, что есть еще архитектура на основе BPMN для бизнес-процессов. Но это уже совсем другая история.