Исследовательское Android-приложение для полностью локального запуска
Prism ML Bonsai-27B GGUF
через JNI и специальный форк llama.cpp. После помещения GGUF на устройство
диалог не использует сервер, облачный API или интернет.
Bonsai Local с загруженной моделью
Что уже работает
полноценная загрузка Bonsai-27B-Q1_0.gguf размером 3 803 452 480 байт;
inference внутри Android-процесса, без сервера на ПК;
потоковый чат и thinking-mode;
автообнаружение GGUF в приватной и app-specific external папках;
ручной импорт любого совместимого GGUF через Android Storage Access Framework;
05-russian-kotlin.png — негативный capability-тест:
модель поняла русский Kotlin prompt, но исчерпала лимит в thinking-mode.
Скорость эмулятора нельзя переносить на физический телефон: виртуализированный
CPU, thermal policy и доступные SIMD-инструкции отличаются. В карточке модели
Prism ML публикует существенно более высокие результаты для нативного MLX на
современном iPhone; этот проект использует Android/llama.cpp CPU backend.
Сериализация native calls важна: глобальные llama_model, llama_context,
llama_batch и sampler не должны одновременно изменяться UI и benchmark
корутинами.
При фактической загрузке полного GGUF runtime сообщил:
64 transformer blocks;
Q1_0 binary tensors;
recurrent state около 149.62 MiB;
CPU compute buffer около 523.02 MiB;
Flash Attention включён автоматически;
fused Gated Delta Net работает в autoregressive и chunked режимах;
graph содержит около 3703 nodes и один split.
Bonsai-27B не MoE-модель. У неё нет набора экспертов и router, поэтому
проверка «всех экспертов» неприменима. Это dense 27B hybrid-attention model:
примерно 75% слоёв используют linear/recurrent attention и 25% — full
attention.
Текущий APK текстовый. Дополнительные компоненты из репозитория модели не
подключены:
минимум 5 ГБ свободного места только под GGUF, комфортно 8+ ГБ;
рекомендуется 8 ГБ RAM или больше;
для импорта через picker временно может потребоваться место для копии;
первый старт модели может занимать десятки секунд.
Вес модели не включён внутрь APK, потому что APK с asset размером 3,8 ГБ
непрактичен. Проверенная копия опубликована рядом с проектом как
models/Bonsai-27B-Q1_0.gguf, поэтому её можно скачать из этого репозитория
без отдельного поиска. SHA-256 модели:
Официальная карточка указывает около 5.2 ГБ peak memory при 4K context без
KV-cache compression. Android dumpsys meminfo показывает для процесса
меньше, потому что memory-mapped страницы GGUF и page cache учитываются не так,
как private native heap.
Коллекция публикует GGUF и специальный PrismML fork, но не готовый AAR/APK.
Решение: официальный examples/llama.android из форка использован как база,
а CMake собирает runtime прямо внутри Gradle.
2. Стандартный llama.cpp недостаточен
Модель использует Q1_0 и Qwen 3.5/3.6 hybrid architecture. Решение: закреплён
именно PrismML fork commit 62061f9, содержащий нужные quantization и Gated
Delta Net paths.
3. JDK 17 toolchain отсутствовал
Gradle запускался на JBR 21, а исходный sample требовал установленный JDK 17
через jvmToolchain(17). Gradle не имел repository для автоматической загрузки.
Решение: убрать принудительный поиск отдельного toolchain и явно компилировать
Java/Kotlin bytecode target 17:
__android_log_is_loggable() доступен только с API 30, а ранняя конфигурация
использовала minSdk 28. Решение: локальный фильтр log level и итоговый minSdk
30.
5. Эмулятор был слишком маленьким
Существующий Pixel_7 имел 2 ГБ RAM и раздел data 6 ГБ, из которых свободно
около 1.1 ГБ. Модель туда не помещалась. Создан отдельный AVD
Bonsai_27B_Test с 8 ГБ RAM и 16 ГБ data, не затрагивающий пользовательский
Pixel_7.
6. 16 KB memory pages
Android 15+ требует 16 KB-compatible native libraries. Проект использует NDK
r28 и AGP 8.13.2. Проверено:
Android 17 preview system image дополнительно показывает экспериментальный
RELRO compatibility dialog для части динамически загружаемых CPU variants.
Неиспользуемый androidx.datastore был удалён из общего dependency bundle,
что исключило libdatastore_shared_counter.so из APK. После этого в APK
осталось 32 целевых native-библиотеки вместо 36.
APK продолжает работать в page-size compatibility mode. Для production перед
публикацией нужно повторить проверку на стабильном Android 15/16 16 KB image и
обновить NDK/PrismML fork, если preview-проверка станет обязательной.
7. Большой GGUF нельзя дублировать бездумно
Импорт в private storage может временно требовать две копии. Для тестового AVD
модель отправлялась сразу в app-specific external directory, которую приложение
сканирует при старте.
8. Thinking mode делает даже короткие тесты долгими
Запрос с требованием вернуть одно число всё равно сгенерировал подробный
<think> блок. Это ожидаемое поведение модели и полезная проверка reasoning,
но на CPU-эмуляторе занимает минуты. UI генерирует асинхронно и не блокирует
main thread. Более сложный русский Kotlin prompt подтвердил понимание задачи,
но за 512 токенов модель не вышла из thinking в финальный ответ. Это не падение
runtime, а ограничение текущей политики генерации; для прикладного UI нужны
отдельная панель reasoning, больший лимит или поддерживаемое моделью отключение
thinking-mode.
Ограничения текущей версии
только text-to-text; vision projection не загружается;
только CPU backend в протестированном AVD;
нет встроенного resumable downloader и проверки SHA-256 в UI;
модель опубликована отдельно от APK в папке models/;
история чата живёт в памяти Activity и не сохраняется после полного restart;
контекст приложения ограничен 8192 токенами, хотя модель обучена на гораздо
более длинный контекст;
thinking-теги показываются как обычный текст;
на устройствах с 6 ГБ RAM возможен LMK/OOM;
DSpark speculative decoding не подключён.
Куда развивать исследование
Отделить <think> в сворачиваемую UI-панель.
Добавить resumable WorkManager/foreground download с SHA-256.
Подключить mmproj и Android Photo Picker для vision.
Исследовать Vulkan backend на Android GPU и сравнить CPU/Vulkan.
Подключить Q4 KV cache и замерить RAM на 8K/32K/100K.
Проверить DSpark drafter, когда Android path будет поддержан форком.
Добавить Room для истории диалогов и export/import sessions.
Собрать per-ABI APK/AAB, чтобы не поставлять обе native архитектуры каждому
устройству.
Добавить macrobenchmark: cold load, first-token latency, sustained tok/s,
thermal throttling и energy usage.
Запустить тот же test suite на физическом Snapdragon/Dimensity и сравнить
NEON, DOTPROD, I8MM и SVE variants.
Ценность для сообщества и похожие проекты
Локальные LLM на Android уже не являются новой идеей. Официальный llama.cpp
содержит Android Studio sample и динамический выбор CPU kernels; PocketPal AI и
ChatterUI запускают разные GGUF на телефоне; MLC LLM, MNN и ExecuTorch предлагают
собственные Android runtime и demo-приложения.
требует export в .pte; здесь тестируется GGUF/llama.cpp путь
Поиск по открытым Hugging Face и GitHub проектам на дату публикации не выявил
другой воспроизводимой сборки именно Bonsai-27B Q1_0 внутри Android APK.
Это не доказательство абсолютного первенства, но практическая новизна публикации
состоит в сочетании следующих элементов:
полный проверенный GGUF, APK, исходники и checksum находятся вместе;
зафиксированы реальные Android pp/tg замеры, runtime paths и screenshots;
описаны 16 KB page-size и RELRO проблемы preview-Android;
опубликован не только успешный ответ 703, но и отрицательный Kotlin-тест;
документация дана на русском и английском языках.
Сейчас это полезный engineering baseline и regression artifact, а не новая
научная архитектура или production-конкурент PocketPal/MNN. Наибольшую ценность
следующий этап даст после ARM64-тестов на физических Snapdragon/Dimensity,
измерений RAM/энергии/first-token latency, CI-сборки и upstream PR с найденными
Android-исправлениями.
Лицензии
Bonsai-27B GGUF: Apache-2.0 согласно карточке модели.
llama.cpp / PrismML fork: см. лицензии в third_party/llama.cpp.
При распространении APK и модели необходимо сохранить соответствующие
LICENSE и NOTICE файлов upstream-проектов.