Інтеграція On-Device LLM (Llama.cpp) для офлайн AI-асистента у мобільному застосунку

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1735 послуг
Інтеграція On-Device LLM (Llama.cpp) для офлайн AI-асистента у мобільному застосунку
Складний
~2-4 тижні
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    495

Інтеграція локальної LLM (Llama.cpp) для офлайн AI-помічника в мобільному додатку

Запуск мовної моделі прямо на смартфоні без інтернету — це вже реальність. Llama.cpp забезпечує працюючий інференс на CPU з опціональним Metal/Vulkan прискоренням. Головне запитання — не "чи можна", а "яку модель та в якому квантуванні вибрати, щоб пристрій не перегрівся через 5 хвилин?"

Моделі та їхні реальні вимоги

Llama.cpp працює з моделями в форматі GGUF. Популярні варіанти для мобільних пристроїв:

Модель Квантування Розмір RAM Швидкість (iPhone 14)
Llama-3.2-1B Q4_K_M 0.8 ГБ ~1.2 ГБ 25–35 t/s
Llama-3.2-3B Q4_K_M 2.0 ГБ ~2.5 ГБ 10–15 t/s
Phi-3-mini-4k Q4_K_M 2.2 ГБ ~2.8 ГБ 8–12 t/s
Gemma-2-2B Q4_K_M 1.6 ГБ ~2.0 ГБ 12–18 t/s
Qwen2.5-1.5B Q4_K_M 1.0 ГБ ~1.4 ГБ 20–28 t/s

На iPhone SE 2-го покоління з 3 ГБ RAM модель Llama-3.2-3B Q4 працює на межі своїх можливостей — OOM можлива при довгих контекстах. Безпечний вибір для широкого набору пристроїв — моделі до 1.5–2 ГБ.

Збирання Llama.cpp для iOS

# Клонування репозиторію
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp

# Збирання через CMake для iOS
cmake -B build-ios \
    -DCMAKE_TOOLCHAIN_FILE=ios.toolchain.cmake \
    -DPLATFORM=OS64 \  # лише arm64
    -DLLAMA_METAL=ON \  # Прискорення Metal GPU
    -DLLAMA_STATIC=ON
cmake --build build-ios --config Release

Результат — статична бібліотека libllama.a. Створюємо Swift Package з C-bridging header:

// llama_bridge.h
#include "llama.h"
// Обгортки для Swift-сумісного API
void* llama_create_context(const char* model_path, int n_ctx, int n_gpu_layers);
const char* llama_generate_token(void* ctx, const char* prompt);
void llama_free_context(void* ctx);

n_gpu_layers — кількість шарів, загружених на Metal GPU. Значення -1 означає всі шари на GPU. На iPhone 14 з 6 ГБ unified memory встановіть -1. На пристроях з 3 ГБ експериментуйте: занадто багато шарів на GPU спричиняють OOM.

Swift-обгортка для потокового передачі токенів

import Foundation

actor LlamaSession {
    private var context: OpaquePointer?
    private var model: OpaquePointer?

    func load(modelPath: String, contextSize: Int32 = 2048, gpuLayers: Int32 = -1) throws {
        var params = llama_model_default_params()
        params.n_gpu_layers = gpuLayers

        model = llama_load_model_from_file(modelPath, params)
        guard model != nil else { throw LlamaError.modelLoadFailed }

        var ctxParams = llama_context_default_params()
        ctxParams.n_ctx = UInt32(contextSize)
        ctxParams.n_batch = 512

        context = llama_new_context_with_model(model, ctxParams)
    }

    func generate(prompt: String) -> AsyncThrowingStream<String, Error> {
        AsyncThrowingStream { continuation in
            Task.detached(priority: .userInitiated) {
                // Токенізація
                var tokens = [llama_token](repeating: 0, count: 4096)
                let nTokens = llama_tokenize(self.model, prompt, Int32(prompt.utf8.count),
                                              &tokens, 4096, true, false)

                // Інференс — по одному токену
                for i in 0..<nTokens {
                    llama_batch_add(&batch, tokens[Int(i)], llama_pos(i), [0], false)
                }

                while true {
                    llama_decode(self.context, batch)
                    let nextToken = llama_sample_token_greedy(self.context, &candidates)

                    if nextToken == llama_token_eos(self.model) { break }

                    // Конвертація токена в рядок
                    var buf = [Int8](repeating: 0, count: 64)
                    llama_token_to_piece(self.model, nextToken, &buf, 64, 0, true)
                    let piece = String(cString: buf)

                    continuation.yield(piece)
                }
                continuation.finish()
            }
        }
    }
}

Потокова передача токенів через AsyncThrowingStream — користувачі бачать текст по мірі його генерування, не чекаючи повної відповіді. Критично для UX: 10 токенів за секунду сприймається природно, коли текст з'являється поступово.

Android: Llama.cpp через NDK

// CMakeLists.txt в jni/
add_library(llama_jni SHARED llama_jni.cpp)
target_link_libraries(llama_jni llama ggml)

// Kotlin сторона
class LlamaEngine {
    init { System.loadLibrary("llama_jni") }

    external fun loadModel(modelPath: String, nGpuLayers: Int): Long  // повертає handle
    external fun generateNext(handle: Long, tokens: IntArray): String
    external fun freeModel(handle: Long)
}

На Android — Vulkan backend замість Metal: увімкніть LLAMA_VULKAN=ON в CMakeLists. Підтримується на пристроях з Vulkan 1.1+, по суті на всіх Android 10+.

Проблема Android: процес не має жорсткого обмеження пам'яті як пула — система може вбити додаток (SIGKILL) за нестачі RAM без попередження. ComponentCallbacks2.onTrimMemory(TRIM_MEMORY_RUNNING_CRITICAL) — останній шанс звільнити контекст перед завершенням процесу.

Завантаження моделі: прогрес та верифікація

Файли GGUF важать 1–4 ГБ. Завантажуйте через URLSession (iOS) або WorkManager з DownloadManager (Android):

// iOS: Фоновий URLSession для фонового завантаження
let config = URLSessionConfiguration.background(withIdentifier: "model-download")
config.isDiscretionary = false
let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)

let task = session.downloadTask(with: modelURL)
task.resume()

// Верифікація SHA256 після завантаження
func verify(fileURL: URL, expectedHash: String) -> Bool {
    guard let data = try? Data(contentsOf: fileURL) else { return false }
    let hash = SHA256.hash(data: data)
    return hash.compactMap { String(format: "%02x", $0) }.joined() == expectedHash
}

Хеші SHA256 моделей публікуються в репозиторіях HuggingFace — перевірте перед завантаженням в пам'ять. Пошкоджена GGUF спричиняє крахи під час парсингу заголовка або пізніше під час інференсу — краще помітити при верифікації.

Теплові обмеження

Llama.cpp на iPhone розігріває пристрій під час довгої генерації. iOS throttling: при перегріванні система знижує тактову частоту, швидкість генерації падає з 25 t/s до 8–10 t/s. Це очікувана поведінка системи.

Практичне рішення: обмежте максимальний контекст (n_ctx) до 1024–2048 для коротких сеансів. Робіть паузи між запитами. Слідкуйте за ProcessInfo.processInfo.thermalState на iOS:

NotificationCenter.default.addObserver(forName: ProcessInfo.thermalStateDidChangeNotification, ...) { _ in
    let state = ProcessInfo.processInfo.thermalState
    if state == .critical || state == .serious {
        // Призупиніть генерацію, сповістіть користувача
    }
}

Процес

Вибір моделі для цільових пристроїв → збирання llama.cpp для платформ → Swift/Kotlin обгортка з асинхронною потоковою передачею → завантаження та верифікація → чат-інтерфейс → тепловий стрес-тест.

Орієнтири за часом

Одна платформа, базовий чат-інтерфейс з вибраною моделлю — 3–5 тижнів. Обидві платформи, кілька моделей на вибір, фонове завантаження, управління контекстом — 7–12 тижнів.