Downloads · 30 days
861
25% of all-time downloads
livadies/Bonsai-27B-Android-Local
Bonsai-27B-Android-Local is a text generation model from livadies. Use it when you need the model to write or continue text. The card lists the license as other.
Русский · English · Структурированные результаты
Downloads · 30 days
861
25% of all-time downloads
All-time downloads
3.4K
Public
Repo size
3.9 GB
Likes
6
Public
Click a slice to open those files.
.gguf3.8 GB · 97%
From the Hugging Face model README
Русский · English · Структурированные результаты
Исследовательское Android-приложение для полностью локального запуска
Prism ML Bonsai-27B GGUF
через JNI и специальный форк llama.cpp. После помещения GGUF на устройство
диалог не использует сервер, облачный API или интернет.

Bonsai-27B-Q1_0.gguf размером 3 803 452 480 байт;arm64-v8a реального телефона и x86_64 эмулятора;prompt_b64 для воспроизводимых автоматических тестов Unicode prompts.| Компонент | Значение |
|---|---|
| ОС хоста | Windows 11 |
| CPU хоста | Intel Core Ultra 5 125H |
| Android Studio | 2025.2 |
| Android Gradle Plugin | 8.13.2 |
| Gradle | 8.14.3 |
| JDK сборки | JetBrains Runtime 21.0.9 |
| compileSdk / targetSdk | 36 / 36 |
| minSdk | 30 (Android 11) |
| Android NDK | 28.2.13676358 |
| CMake | 3.22.1 |
| ABI | arm64-v8a, x86_64 |
| Тестовый AVD | Android 17 preview, x86_64, 8 ГБ RAM, 16 ГБ data |
| PrismML llama.cpp commit | 62061f91088281e65071cc38c5f69ee95c39f14e |
Все числа ниже получены внутри Android-эмулятора, а не настольным
llama-cli.
| Проверка | Результат |
|---|---|
| Сборка debug APK | успешно |
| Установка и запуск Android | успешно |
| Распознавание модели | qwen35 27B Q1_0, 26.9B params, 3.53 GiB |
| Backend | CPU, динамически выбранный x86_64 variant |
| Prompt processing, pp64 | 2.89 tok/s |
| Token generation, tg32 | 1.79 tok/s |
Арифметика 37 × 19 | корректный результат 703 |
| Thinking trace | работает |
| Русский + Kotlin, лимит 512 токенов | prompt понят, но весь лимит ушёл на thinking; чистый финальный код не выведен |
| Полностью offline после импорта | да |
| Крэши / FATAL EXCEPTION | не обнаружены |
Скриншоты:
02-model-loaded.png — модель загружена;03-benchmark.png — benchmark;04-reasoning.png — реальная генерация и ответ 703;05-russian-kotlin.png — негативный capability-тест:
модель поняла русский Kotlin prompt, но исчерпала лимит в thinking-mode.Скорость эмулятора нельзя переносить на физический телефон: виртуализированный CPU, thermal policy и доступные SIMD-инструкции отличаются. В карточке модели Prism ML публикует существенно более высокие результаты для нативного MLX на современном iPhone; этот проект использует Android/llama.cpp CPU backend.
flowchart TD
UI["Android UI · MainActivity"] --> API["InferenceEngine Kotlin API"]
API --> DISP["Single-thread coroutine dispatcher"]
DISP --> JNI["JNI · libai-chat.so"]
JNI --> COMMON["llama-common · chat template · sampler"]
JNI --> LLAMA["PrismML llama.cpp"]
LLAMA --> GGML["GGML CPU backend loader"]
GGML --> ABI{"Device ABI / CPU features"}
ABI --> ARM["ARM variants · NEON / DOTPROD / I8MM / SVE / SME"]
ABI --> X86["x86_64 variants · SSE4 / AVX2 / AVX512 / AMX"]
GGUF["Bonsai-27B-Q1_0.gguf · 3.80 GB"] --> LLAMA
app/ — UI, импорт модели, чат, benchmark и тестовый Base64 intent.lib/ — Android-friendly Kotlin API и JNI wrapper.third_party/llama.cpp/ — форк PrismML с Q1_0 и hybrid-attention kernels;
находится рядом с проектом, на уровень выше BonsaiAndroid.models/ — локальная копия GGUF для исследования; модель не упаковывается
в APK.screenshots/ — фактические результаты запуска в эмуляторе.MainActivity ждёт состояния InferenceEngine.State.Initialized..gguf в files/models и getExternalFilesDir()/models.InferenceEngine.loadModel().Dispatchers.IO dispatcher.llama_model_load_from_file(), затем создаёт контекст 8192
токенов, batch 512 и sampler.nativeLibraryDir.Flow<String>.Критический фрагмент JNI:
llama_model_params model_params = llama_model_default_params();
g_model = llama_model_load_from_file(model_path, model_params);
llama_context_params ctx_params = llama_context_default_params();
ctx_params.n_ctx = 8192;
ctx_params.n_batch = 512;
ctx_params.n_threads = n_threads;
g_context = llama_init_from_model(g_model, ctx_params);
Сериализация native calls важна: глобальные llama_model, llama_context,
llama_batch и sampler не должны одновременно изменяться UI и benchmark
корутинами.
private val llamaDispatcher = Dispatchers.IO.limitedParallelism(1)
override suspend fun loadModel(pathToModel: String) =
withContext(llamaDispatcher) {
load(pathToModel)
prepare()
}
При фактической загрузке полного GGUF runtime сообщил:
Bonsai-27B не MoE-модель. У неё нет набора экспертов и router, поэтому проверка «всех экспертов» неприменима. Это dense 27B hybrid-attention model: примерно 75% слоёв используют linear/recurrent attention и 25% — full attention.
Текущий APK текстовый. Дополнительные компоненты из репозитория модели не подключены:
Bonsai-27B-mmproj-Q8_0.gguf — vision tower;Bonsai-27B-dspark-Q4_1.gguf — speculative decoding drafter.Вес модели не включён внутрь APK, потому что APK с asset размером 3,8 ГБ
непрактичен. Проверенная копия опубликована рядом с проектом как
models/Bonsai-27B-Q1_0.gguf, поэтому её можно скачать из этого репозитория
без отдельного поиска. SHA-256 модели:
17EF842E47450CAEB8EAA3EBFBBAB5D2F2278B62B79BE107985FB69A2F819AA0
Официальная карточка указывает около 5.2 ГБ peak memory при 4K context без
KV-cache compression. Android dumpsys meminfo показывает для процесса
меньше, потому что memory-mapped страницы GGUF и page cache учитываются не так,
как private native heap.
Открыть папку BonsaiAndroid в Android Studio.
Убедиться, что рядом есть third_party/llama.cpp:
gpt/
├── BonsaiAndroid/
└── third_party/llama.cpp/
Установить SDK 36, NDK 28.2.13676358 и CMake 3.22.1.
Проверить путь SDK в local.properties.
Выполнить Build > Make Project или из PowerShell:
$env:JAVA_HOME = 'C:\Program Files\Android\Android Studio1\jbr'
java -classpath gradle\wrapper\gradle-wrapper.jar `
org.gradle.wrapper.GradleWrapperMain :app:assembleDebug
Debug APK появляется в:
app/build/outputs/apk/debug/app-debug.apk
Проверенный итоговый артефакт дополнительно скопирован в:
release/BonsaiLocal-debug.apk
Его размер — 120 762 843 байта, SHA-256:
BDAF2D9EE7EE1BBB2A424242678D75AC35F2B770973E3F4C9E58639CE8F93E5C
Первая сборка долгая: генерируются сотни C/C++ объектов и несколько CPU variants для двух ABI. Инкрементальные сборки значительно быстрее.
Проект был вынесен из examples/llama.android, поэтому относительный путь
исходников пришлось изменить:
set(LLAMA_SRC ${CMAKE_CURRENT_LIST_DIR}/../../../../../third_party/llama.cpp)
add_subdirectory(${LLAMA_SRC} build-llama)
Для Android компилируются обе ABI:
ndk {
abiFilters += listOf("arm64-v8a", "x86_64")
}
Bonsai-27B-Q1_0.gguf на телефон.После первой установки APK:
adb -s emulator-5556 shell mkdir -p `
/sdcard/Android/data/com.prismml.bonsailocal/files/models
adb -s emulator-5556 push .\models\Bonsai-27B-Q1_0.gguf `
/sdcard/Android/data/com.prismml.bonsailocal/files/models/
После перезапуска приложение найдёт модель автоматически.
Debug Activity принимает Base64 UTF-8 prompt. Это обход нестабильного Unicode input у ADB-клавиатуры preview-эмулятора и не участвует в обычном UI.
$prompt = 'Ответь по-русски одним предложением.'
$b64 = [Convert]::ToBase64String(
[Text.Encoding]::UTF8.GetBytes($prompt)
)
adb shell am start `
-n com.prismml.bonsailocal/.MainActivity `
--es prompt_b64 $b64
В коде extra декодируется без сетевых вызовов:
String(Base64.decode(encoded, Base64.NO_WRAP), Charsets.UTF_8)
Коллекция публикует GGUF и специальный PrismML fork, но не готовый AAR/APK.
Решение: официальный examples/llama.android из форка использован как база,
а CMake собирает runtime прямо внутри Gradle.
Модель использует Q1_0 и Qwen 3.5/3.6 hybrid architecture. Решение: закреплён
именно PrismML fork commit 62061f9, содержащий нужные quantization и Gated
Delta Net paths.
Gradle запускался на JBR 21, а исходный sample требовал установленный JDK 17
через jvmToolchain(17). Gradle не имел repository для автоматической загрузки.
Решение: убрать принудительный поиск отдельного toolchain и явно компилировать
Java/Kotlin bytecode target 17:
kotlin {
compilerOptions { jvmTarget.set(JvmTarget.JVM_17) }
}
__android_log_is_loggable() доступен только с API 30, а ранняя конфигурация
использовала minSdk 28. Решение: локальный фильтр log level и итоговый minSdk
30.
Существующий Pixel_7 имел 2 ГБ RAM и раздел data 6 ГБ, из которых свободно
около 1.1 ГБ. Модель туда не помещалась. Создан отдельный AVD
Bonsai_27B_Test с 8 ГБ RAM и 16 ГБ data, не затрагивающий пользовательский
Pixel_7.
Android 15+ требует 16 KB-compatible native libraries. Проект использует NDK r28 и AGP 8.13.2. Проверено:
LOAD alignment: 2**14 для native .so;zipalign -v -c -P 16 4 app-debug.apk: Verification successful.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-проверка станет обязательной.
Импорт в private storage может временно требовать две копии. Для тестового AVD модель отправлялась сразу в app-specific external directory, которую приложение сканирует при старте.
Запрос с требованием вернуть одно число всё равно сгенерировал подробный
<think> блок. Это ожидаемое поведение модели и полезная проверка reasoning,
но на CPU-эмуляторе занимает минуты. UI генерирует асинхронно и не блокирует
main thread. Более сложный русский Kotlin prompt подтвердил понимание задачи,
но за 512 токенов модель не вышла из thinking в финальный ответ. Это не падение
runtime, а ограничение текущей политики генерации; для прикладного UI нужны
отдельная панель reasoning, больший лимит или поддерживаемое моделью отключение
thinking-mode.
models/;<think> в сворачиваемую UI-панель.mmproj и Android Photo Picker для vision.Локальные LLM на Android уже не являются новой идеей. Официальный llama.cpp
содержит Android Studio sample и динамический выбор CPU kernels; PocketPal AI и
ChatterUI запускают разные GGUF на телефоне; MLC LLM, MNN и ExecuTorch предлагают
собственные Android runtime и demo-приложения.
| Проект | Что уже делает | Отличие этого исследования |
|---|---|---|
| llama.cpp Android | официальный JNI/sample и CPU variants | проверена конкретная редкая Q1_0 hybrid-модель и собран готовый APK |
| PocketPal AI | зрелый GGUF-клиент, загрузки HF и benchmark | универсальный продукт, а здесь узкий воспроизводимый Bonsai-27B test case |
| ChatterUI | GGUF и API-чаты через React Native | здесь минимальный native Android/JNI путь без React Native |
| MLC LLM | GPU-oriented Android SDK и demo | другой model format/toolchain; текущий проект использует исходный GGUF и CPU |
| MNN | производительный мультимодальный Android-клиент | значительно шире и быстрее; этот репозиторий проще как regression fixture для Q1_0/GDN |
| ExecuTorch | AAR и experimental LLM Java API | требует export в .pte; здесь тестируется GGUF/llama.cpp путь |
Поиск по открытым Hugging Face и GitHub проектам на дату публикации не выявил другой воспроизводимой сборки именно Bonsai-27B Q1_0 внутри Android APK. Это не доказательство абсолютного первенства, но практическая новизна публикации состоит в сочетании следующих элементов:
Сейчас это полезный engineering baseline и regression artifact, а не новая научная архитектура или production-конкурент PocketPal/MNN. Наибольшую ценность следующий этап даст после ARM64-тестов на физических Snapdragon/Dimensity, измерений RAM/энергии/first-token latency, CI-сборки и upstream PR с найденными Android-исправлениями.
third_party/llama.cpp.LICENSE и NOTICE файлов upstream-проектов.