
llama.cpp 在 Android 上的應用:Kotlin 整合指南
將 llama.cpp 整合到 Android 應用程式的分步指南,使用 Kotlin。JNI 繫結、Vulkan GPU 加速、模型載入以及跨 Android 裝置的記憶體管理。
llama.cpp 使用 CPU 多執行緒和 Vulkan GPU 加速在 Android 裝置上運行 GGUF 語言模型。llama.android 專案透過 JNI 提供預建置的 Kotlin 繫結,使 Kotlin 開發者能夠輕鬆整合。
本指南涵蓋從專案設定到正式環境部署的完整整合路徑。
整合選項
選項 1:llama.android 函式庫(推薦)
llama.cpp 儲存庫包含 llama.android,一個帶有 Kotlin 繫結的預建置 Android 函式庫。這是實現裝置端 AI 最快的途徑。
將其新增到您的專案:
- 從 llama.cpp 儲存庫克隆或下載 llama.android 模組
- 將其作為模組包含在您的 Android 專案中
- 在應用程式的
build.gradle.kts中新增相依性
dependencies {
implementation(project(":llama"))
}
選項 2:從原始碼建構
如需更多控制,使用 Android NDK 將 llama.cpp 建構為原生函式庫:
mkdir build-android && cd build-android
cmake .. \
-DCMAKE_TOOLCHAIN_FILE=$NDK_PATH/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a \
-DANDROID_PLATFORM=android-26 \
-DLLAMA_VULKAN=ON \
-DBUILD_SHARED_LIBS=ON
cmake --build . --config Release
這會產生 libllama.so,您需將其包含在 jniLibs 目錄中。
選項 3:預建置 AAR
部分社群專案將 llama.cpp 發佈為 AAR(Android Archive),您可以作為 Maven 相依性包含。請檢查最近且維護中的版本。
專案設定
最低需求
- Android API 26+(Android 8.0)
- ARM64(arm64-v8a)目標架構
- NDK r25+ 用於建構原生程式碼
- 目標裝置需 4GB+ RAM(用於 1B 模型)
建構組態
// app/build.gradle.kts
android {
defaultConfig {
ndk {
abiFilters += "arm64-v8a" // 僅 64 位元 ARM
}
}
}
權限
推論不需要特殊權限。模型下載需要:
<uses-permission android:name="android.permission.INTERNET" />
載入模型
class LlamaEngine(private val context: Context) {
private var model: Long = 0 // 原生指標
private var ctx: Long = 0 // 原生上下文指標
suspend fun loadModel(modelPath: String) = withContext(Dispatchers.Default) {
// 使用 GPU 加速載入模型
model = LlamaNative.loadModel(
modelPath = modelPath,
nGpuLayers = 99, // 將所有層卸載到 Vulkan
)
require(model != 0L) { "Failed to load model" }
// 建立推論上下文
ctx = LlamaNative.createContext(
model = model,
nCtx = 2048, // 上下文視窗
nThreads = 4, // CPU 執行緒
nBatch = 512, // 批次大小
)
require(ctx != 0L) { "Failed to create context" }
}
fun unload() {
if (ctx != 0L) {
LlamaNative.freeContext(ctx)
ctx = 0
}
if (model != 0L) {
LlamaNative.freeModel(model)
model = 0
}
}
}
Vulkan GPU 加速
Vulkan 是 Android 的 GPU 運算 API。llama.cpp 使用它來加速推論期間的矩陣運算。將 nGpuLayers 設為模型的層數即可啟用。
Vulkan 支援取決於裝置:
- Snapdragon 8 Gen 2+:完整 Vulkan 運算支援,最佳效能
- Tensor G3/G4:良好的 Vulkan 支援
- Snapdragon 7 Gen 3+:支援 Vulkan,中等加速
- 較舊/入門裝置:可能缺乏 Vulkan 運算支援。自動降級為 CPU。
執行時期檢查 Vulkan 可用性:
fun isVulkanAvailable(): Boolean {
return try {
val vk = android.hardware.HardwareBuffer::class.java
android.os.Build.VERSION.SDK_INT >= 26
// 更穩健的方式:嘗試建立 Vulkan 實例
} catch (e: Exception) {
false
}
}
生成文字
class LlamaEngine(private val context: Context) {
// ... 上方的 loadModel 和 unload
suspend fun generate(
prompt: String,
maxTokens: Int = 256,
temperature: Float = 0.7f,
onToken: (String) -> Unit = {}
): String = withContext(Dispatchers.Default) {
val result = StringBuilder()
LlamaNative.generate(
context = ctx,
prompt = prompt,
maxTokens = maxTokens,
temperature = temperature,
) { token ->
result.append(token)
// 分派到主執行緒進行 UI 更新
withContext(Dispatchers.Main) {
onToken(token)
}
}
result.toString()
}
}
ViewModel 整合
class AiViewModel(application: Application) : AndroidViewModel(application) {
private val engine = LlamaEngine(application)
private val _response = MutableStateFlow("")
val response: StateFlow<String> = _response
private val _isGenerating = MutableStateFlow(false)
val isGenerating: StateFlow<Boolean> = _isGenerating
fun loadModel(path: String) {
viewModelScope.launch {
engine.loadModel(path)
}
}
fun generate(prompt: String) {
viewModelScope.launch {
_isGenerating.value = true
_response.value = ""
engine.generate(prompt, maxTokens = 256) { token ->
_response.value += token
}
_isGenerating.value = false
}
}
override fun onCleared() {
engine.unload()
super.onCleared()
}
}
Jetpack Compose UI
@Composable
fun AiChatScreen(viewModel: AiViewModel = viewModel()) {
val response by viewModel.response.collectAsState()
val isGenerating by viewModel.isGenerating.collectAsState()
var input by remember { mutableStateOf("") }
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
// 回應區域
Text(
text = response,
modifier = Modifier.weight(1f).verticalScroll(rememberScrollState())
)
// 輸入區域
Row(modifier = Modifier.fillMaxWidth()) {
TextField(
value = input,
onValueChange = { input = it },
modifier = Modifier.weight(1f),
enabled = !isGenerating
)
Button(
onClick = {
viewModel.generate(input)
input = ""
},
enabled = !isGenerating
) {
Text("Send")
}
}
}
}
記憶體管理
Android 的記憶體管理相當積極。系統會終止背景程序以釋放 RAM,並在記憶體壓力下可能終止您的應用程式。
可用記憶體檢查
fun getAvailableMemoryMb(): Long {
val memInfo = ActivityManager.MemoryInfo()
val activityManager = getSystemService(ACTIVITY_SERVICE) as ActivityManager
activityManager.getMemoryInfo(memInfo)
return memInfo.availMem / (1024 * 1024)
}
fun canLoadModel(modelSizeMb: Long): Boolean {
val available = getAvailableMemoryMb()
// 為應用程式和作業系統保留 500MB
return available > modelSizeMb + 500
}
生命週期管理
class AiService : LifecycleObserver {
private var engine: LlamaEngine? = null
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume() {
// 如果 AI 畫面處於活躍狀態,考慮載入模型
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
// 卸載模型以釋放記憶體
engine?.unload()
}
}
onTrimMemory 處理
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW) {
engine?.unload()
}
}
模型交付
資源交付(Play Feature Delivery)
對於超過 150MB 的模型,使用 Play Asset Delivery 以避免 APK 大小限制:
// build.gradle.kts
assetPacks += ":model_pack"
// model_pack/build.gradle.kts
plugins {
id("com.android.asset-pack")
}
assetPack {
packName.set("model_pack")
dynamicDelivery {
deliveryType.set("install-time") // 或 "fast-follow" 或 "on-demand"
}
}
安裝後下載
安裝後下載模型:
suspend fun downloadModel(url: String, destination: File): Boolean {
return withContext(Dispatchers.IO) {
val client = OkHttpClient()
val request = Request.Builder().url(url).build()
val response = client.newCall(request).execute()
response.body?.let { body ->
val totalBytes = body.contentLength()
destination.outputStream().use { output ->
body.byteStream().use { input ->
val buffer = ByteArray(8192)
var bytesRead: Long = 0
var read: Int
while (input.read(buffer).also { read = it } != -1) {
output.write(buffer, 0, read)
bytesRead += read
val progress = bytesRead.toFloat() / totalBytes
// 更新進度 UI
}
}
}
true
} ?: false
}
}
使用 WorkManager 進行能在應用程式重啟後繼續的背景下載。
跨裝置測試
Android 裝置光譜非常廣泛。在以下裝置上測試:
- 旗艦機(SD 8 Gen 3,12GB):驗證最佳效能
- 中階機(SD 7 Gen 3,6-8GB):驗證 1B 模型流暢運行
- 入門機(SD 6 Gen 3,4GB):驗證模型無法載入時的優雅降級
- 舊旗艦機(SD 8 Gen 1,8GB):驗證 2 年前的旗艦機可正常運作
使用 Firebase Test Lab 或 BrowserStack 進行裝置覆蓋測試,無需擁有每一台裝置。
正式環境檢查清單
- 模型在最低規格裝置上正確載入和生成
- 可用時偵測並使用 Vulkan 加速
- Vulkan 不可用時 CPU 降級正常運作
- 記憶體檢查防止在低 RAM 裝置上載入
- 在 onPause/onTrimMemory 時卸載模型
- 安裝後交付的下載進度正確顯示
- 下載後驗證模型完整性(SHA256)
- 使用者可以取消生成
- 模型不可用時應用程式正常運作
GGUF 模型決定了品質。在您的領域資料上微調的模型(透過 Ertas 或類似平台)將產生針對應用程式目的的特定回應。無論使用哪個模型,llama.cpp 的整合方式都是相同的。
Ship AI that runs on your users' devices.
Early bird pricing starts at $14.50/mo — locked in for life. Plans for builders and agencies.
Keep reading

AI in Android Apps: ML Kit, Cloud APIs, and On-Device LLMs Compared
Three paths to AI in your Android app. Google ML Kit for common tasks, cloud APIs for full LLM capability, and on-device models via llama.cpp for cost and privacy. A practical comparison for Kotlin developers.

LLM Benchmarks on Android: Snapdragon, Tensor, and Exynos Compared
Real benchmark data for running LLMs on Android via llama.cpp. Token speeds across Snapdragon 8 Gen 2/3, Tensor G3/G4, Exynos 2400, and mid-range chipsets with practical deployment guidance.

llama.cpp on iOS: A Swift Integration Guide
Step-by-step guide to integrating llama.cpp into an iOS app. Project setup, Metal GPU acceleration, model loading, token streaming, and memory management for production deployment.