Разработка AI-ассистента в мобильном приложении на базе локальной модели (On-Device)
On-device LLM — это не просто «работает без интернета». Это архитектурное решение: данные пользователя не покидают устройство никогда. Для медицинских дневников, личных заметок, корпоративных документов на устройстве сотрудника — это не фича, а требование. Технически задача решаемая на современных флагманах, но требует тщательного подбора модели и runtime под конкретные устройства.
Что реально запустить на телефоне в 2024–2025
Граница возможного сместилась с появлением новых чипов. iPhone 15 Pro (A17 Pro, 8 ГБ RAM, Neural Engine 35 TOPS) и Samsung Galaxy S24 (Snapdragon 8 Gen 3, 12 ГБ RAM) запускают 3B-модели в INT4 квантизации на скорости 15–30 токенов/сек — достаточно для ассистента с потоковым выводом.
| Устройство | RAM | Рекомендуемая модель | Токены/сек |
|---|---|---|---|
| iPhone 15 Pro / 16 | 8 ГБ | Llama 3.2 3B Q4_K_M | 20–30 |
| iPad Pro M4 | 16 ГБ | Llama 3.1 8B Q4_K_M | 15–25 |
| Samsung S24 Ultra | 12 ГБ | Phi-3 Mini Q4 | 25–35 |
| Бюджетные Android | 4–6 ГБ | Phi-3 Mini Q2 / Gemma 2B | 5–15 |
| Старые устройства | 3 ГБ | Не рекомендуется | — |
Пытаться запустить 7B+ модель на телефоне с 4 ГБ RAM — гарантированный OOM crash.
iOS: Core ML и Apple MLX
Apple предлагает два пути. Core ML — стабильный, поддерживает iOS 16+, автоматически использует Neural Engine. Модель конвертируется через coremltools из PyTorch/GGUF. Объём после конвертации Llama 3.2 3B в INT4 — около 1.8 ГБ.
import CoreML
class OnDeviceLLM {
private let model: MLModel
init() throws {
let config = MLModelConfiguration()
config.computeUnits = .all // CPU + GPU + Neural Engine
model = try LlamaModel(configuration: config).model
}
func generate(prompt: String) -> AsyncStream<String> {
AsyncStream { continuation in
Task.detached(priority: .userInitiated) {
// tokenize → autoregressive decode → yield tokens
let tokens = self.tokenize(prompt)
for _ in 0..<512 {
let nextToken = self.model.predictNextToken(tokens)
continuation.yield(self.detokenize(nextToken))
if nextToken == self.eosTokenId { break }
}
continuation.finish()
}
}
}
}
Apple MLX (Swift framework, iOS 16+) — более удобный API, но требует iOS 16+ и работает лучше на устройствах с унифицированной памятью. Официальные конвертированные модели от Apple доступны на Hugging Face.
llama.cpp — наибольший выбор моделей в GGUF формате, активно поддерживается сообществом. Интеграция через C++ bridging header сложнее, чем Core ML, но даёт доступ к любой GGUF-модели.
Android: TFLite, MediaPipe, ExecuTorch
На Android больше вариантов и меньше единого стандарта.
MediaPipe LLM Inference API (Google) — наиболее зрелое решение для Android. Поддерживает Gemma 2B/7B, Phi-2, Llama 2, ExportedModels в TFLite формате. Интеграция через LlmInference класс:
val options = LlmInference.LlmInferenceOptions.builder()
.setModelPath("/data/local/tmp/gemma-2b-it-gpu-int4.bin")
.setMaxTokens(1024)
.setResultListener { partialResult, done ->
runOnUiThread { appendText(partialResult) }
}
.build()
val llmInference = LlmInference.createFromOptions(context, options)
llmInference.generateResponseAsync(prompt)
TFLite с кастомным LLM runner — гибче, но требует больше работы по интеграции.
ExecuTorch (Meta) — официальный runtime для Llama на Android, поддерживает Llama 3.x напрямую без конвертации. Компилируется через buck2, что нетривиально настроить в Gradle-проекте.
Загрузка и обновление модели
Модель нельзя паковать в bundle приложения — 1.5–3 ГБ сразу приведут к отклонению в App Store и отпугнут пользователей большим размером APK. Правильный подход: первый запуск → предложение скачать модель → фоновая загрузка с прогресс-баром → верификация контрольной суммы.
На iOS: URLSession.downloadTask с backgroundConfiguration — загрузка продолжается при уходе в фон. Файл хранится в Application Support (не Caches — там может быть удалён системой при нехватке места).
На Android: DownloadManager или WorkManager с NetworkType.UNMETERED constraint — пользователь не потратит мобильный трафик.
Обновление модели: сервер публикует манифест с текущей версией и SHA-256 суммой. При запуске приложение проверяет манифест, если версия изменилась — предлагает обновить.
Тепло и батарея
Inference на Neural Engine/GPU греет устройство. Для длинных генераций (>200 токенов) нужно мониторить тепловое состояние через ProcessInfo.thermalState (iOS) — при .serious снижать n_threads или временно переключаться на CPU-only inference. На Android — PowerManager.thermalStatus.
Батарейное потребление: 3B модель на iPhone 15 Pro расходует ~5–8% батареи на 100 запросов. Предупреждать пользователей не нужно — это меньше, чем стриминг видео.
Ориентиры по срокам
Базовый on-device ассистент (одна платформа, Core ML или MediaPipe) — 4–5 недель. Кросс-платформа с управлением загрузкой, обновлениями и тепловым мониторингом — 8–12 недель.







