
GGUF + llama.cpp:在你的行動應用程式中部署微調模型
將微調 AI 模型打包為 GGUF 檔案並在 iOS 和 Android 上使用 llama.cpp 運行的實用指南。包含檔案大小、效能基準和整合模式。
你的微調模型在筆電上運作得很好。回應速度快,品質正是你需要的,評估結果也很穩固。現在你需要讓它在 50,000 台 iPhone 上運行。
這是大多數行動開發者停下腳步的地方。將 AI 模型打包進應用程式二進位檔聽起來令人卻步:二進位檔大小、記憶體限制、熱節流、平台特定的建構系統。但工具已經成熟了。像 PocketPal AI 這樣的專案證明,一個完整的 llama.cpp 驅動的聊天介面可以在今天的旗艦手機上流暢運行。從微調權重到上架行動應用程式的路徑是明確的、可重複的,而且比 18 個月前輕鬆得多。
本指南將逐步說明每個環節:GGUF 格式、量化選擇、iOS 和 Android 整合、效能預期,以及交付策略。
GGUF 是什麼
GGUF(GGML Unified Format)是由 llama.cpp 專案維護的單一檔案模型格式。在 GGUF 之前,分發模型意味著要處理多個獨立的權重檔案、設定檔、分詞器詞彙表和特殊 token 檔案。GGUF 將所有內容打包成一個具有明確標頭結構的可攜式二進位檔。
一個 .gguf 檔案裡面包含什麼:
- 模型權重(量化或全精度)
- 架構中繼資料(層數、注意力頭數、上下文長度、rope 參數)
- 分詞器詞彙表和合併規則
- 特殊 token 定義(BOS、EOS、填充 token)
單一檔案設計使 GGUF 非常適合行動端部署。你引用一個路徑、載入一個檔案,推論就開始了。不需要多檔案設定。llama.cpp 原生讀取 GGUF,而 Ollama 也使用 GGUF 作為其內部儲存格式。
量化等級說明
量化將模型權重從 32 位或 16 位浮點數壓縮為較低精度的整數。這大幅減少了檔案大小和記憶體佔用,品質損失不大,對於領域特定任務通常感覺不到。
| 格式 | 每權重位元數 | 相對 FP16 品質 | 備註 |
|---|---|---|---|
| Q4_K_M | 約 4.5 位元 | 基準測試上 -2 至 4% | 行動端最佳大小-品質平衡 |
| Q5_K_M | 約 5.5 位元 | 基準測試上 -1 至 2% | 連貫性明顯更好,大約大 20% |
| Q8_0 | 8 位元 | 幾乎無損失 | 接近無損,Q4_K_M 的 2 倍大小 |
| F16 | 16 位元 | 基準線 | 對大多數行動目標太大 |
Q4_K_M 的具體檔案大小:
- Llama 3.2 1B:808 MB
- Llama 3.2 3B:2.02 GB
- Phi-3-mini 3.8B:約 2.3 GB
- Llama 3.1 8B:約 4.9 GB
對行動端而言,Q4_K_M 是預設建議。與 Q5_K_M 相比,對於領域特定微調模型(已經限制了輸出分布)的品質差異很小,而大小的節省很顯著。Q8_0 保留給桌面或離線功能平板電腦使用,在那裡儲存空間限制較小。
1B 模型的 Q4_K_M(808 MB)可以輕鬆放在任何現代手機上。3B 模型(2.02 GB)在旗艦裝置上運作良好。4.9 GB 的 8B 模型只適合作為具有 6 GB 以上記憶體裝置的可下載資源,不適合作為打包的二進位檔。
llama.cpp 如何在行動端運作
llama.cpp 是一個純 C/C++ 的 GGUF 模型推論引擎。核心函式庫除了 C++ 標準函式庫外沒有外部依賴,這就是為什麼它幾乎可以在每個平台上編譯。
加速方面,llama.cpp 使用:
- Metal(iOS/macOS)透過 Apple 的 Metal Performance Shaders 進行 GPU 運算
- OpenCL 或 Vulkan(Android)在 Qualcomm、ARM 和 MediaTek 晶片上進行 GPU 運算
- NEON SIMD 指令用於 ARM CPU 矩陣運算
- NNAPI(Android)作為較新晶片組上硬體 NPU 的委派路徑
專案提供了範例二進位檔,但對於行動端整合,你需要將它編譯為靜態函式庫,並透過平台綁定呼叫它。官方的 Swift 和 Kotlin 包裝器模式都已經存在,而 PocketPal AI 專案是兩個平台都有良好維護的開源參考。
iOS 整合
建構設定
llama.cpp 使用 CMake。對於 iOS,你需要交叉編譯一個針對 arm64-apple-ios 的靜態函式庫:
cmake -B build-ios \
-DCMAKE_TOOLCHAIN_FILE=ios.toolchain.cmake \
-DPLATFORM=OS64 \
-DGGML_METAL=ON \
-DBUILD_SHARED_LIBS=OFF \
-DLLAMA_BUILD_TESTS=OFF \
.
cmake --build build-ios --config Release
GGML_METAL=ON 旗標啟用 Metal GPU 加速。產生的 libllama.a 和 libggml.a 靜態函式庫連結到你的 Xcode 專案中。
或者,llama.cpp Swift Package Manager 套件提供了預建構的 XCFramework,位於 github.com/ggml-org/llama.cpp,它會為你處理 CMake 步驟。
Swift 綁定
SPM 套件暴露了一個 LlamaContext Swift 類別,具有 init(model: URL) 初始化器和一個非同步的 complete(prompt: String) -> AsyncStream<String> 方法用於串流 token。
最小化的整合看起來像這樣:
import llama
class ModelRunner {
private var context: LlamaContext?
func load(modelURL: URL) async throws {
context = try await LlamaContext.createContext(path: modelURL.path)
}
func stream(prompt: String) -> AsyncStream<String> {
guard let ctx = context else { return AsyncStream { $0.finish() } }
return AsyncStream { continuation in
Task {
for await token in ctx.completionStream(text: prompt) {
continuation.yield(token)
}
continuation.finish()
}
}
}
}
iOS 上的記憶體管理
iOS 會在沒有警告的情況下終止超出記憶體預算的程序。關鍵規則:
- 載入模型一次,在應用程式啟動時或在專用的背景執行緒上。不要每次請求都重新初始化。
- 保守設定
n_ctx。 上下文長度直接決定 KV 快取大小。2048 token 的上下文比 8192 token 的使用少得多的記憶體。大多數行動端使用場景需要少於 2048 個 token。 - 監控記憶體警告。 實作
applicationDidReceiveMemoryWarning,並透過清除 KV 快取(呼叫llama_kv_cache_clear)而不是卸載整個模型來回應。 - 使用
mmap載入旗標。 llama.cpp 支援記憶體映射檔案載入(--mmap),讓作業系統可以將模型權重分頁進出。在 iOS 上,這會降低峰值 RSS,代價是首個 token 延遲略高。
1B Q4_K_M 模型(808 MB)加上 2048 token 的 KV 快取,可以在 iPhone 12 及以後的裝置記憶體預算內舒適運行。3B 模型需要至少 6 GB 記憶體的裝置(iPhone 15 Pro 及以後)。
Android 整合
NDK 建構
Android 使用 NDK 工具鏈處理 C/C++ 程式碼。將 llama.cpp 作為子模組新增或將其原始碼複製到 app/src/main/cpp/,然後設定 CMakeLists.txt:
cmake_minimum_required(VERSION 3.22)
project(llama_android)
add_subdirectory(llama.cpp)
add_library(llama_jni SHARED jni_bridge.cpp)
target_link_libraries(llama_jni llama ggml android log)
在 build.gradle(app 模組)中:
android {
defaultConfig {
externalNativeBuild {
cmake {
cppFlags "-std=c++17"
arguments "-DGGML_OPENMP=OFF", "-DLLAMA_BUILD_TESTS=OFF"
}
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
}
要在 Android 上啟用 GPU 加速,傳遞 -DGGML_OPENCL=ON(需要 OpenCL 標頭)或 -DGGML_VULKAN=ON(需要 Vulkan SDK)。在 Snapdragon 裝置上,Qualcomm 的 QNN 後端透過 -DGGML_QNN=ON 提供 NPU 加速,但這需要 Qualcomm AI SDK。
JNI 包裝器和 Kotlin 橋接
在 jni_bridge.cpp 中建立一個精簡的 JNI 橋接,包裝 llama.cpp C API:
extern "C" JNIEXPORT jlong JNICALL
Java_com_yourapp_LlamaWrapper_loadModel(JNIEnv *env, jobject, jstring modelPath) {
const char *path = env->GetStringUTFChars(modelPath, nullptr);
llama_model_params mparams = llama_model_default_params();
llama_model *model = llama_load_model_from_file(path, mparams);
env->ReleaseStringUTFChars(modelPath, path);
return reinterpret_cast<jlong>(model);
}
在 Kotlin 端,一個精簡的包裝類別持有原生指標並暴露基於協程的 API:
class LlamaWrapper(private val modelPath: String) {
private var modelHandle: Long = 0
fun load() {
modelHandle = loadModel(modelPath)
}
fun complete(prompt: String, onToken: (String) -> Unit) {
generateTokens(modelHandle, prompt, onToken)
}
fun close() {
if (modelHandle != 0L) {
freeModel(modelHandle)
modelHandle = 0
}
}
private external fun loadModel(path: String): Long
private external fun generateTokens(handle: Long, prompt: String, cb: (String) -> Unit)
private external fun freeModel(handle: Long)
companion object {
init { System.loadLibrary("llama_jni") }
}
}
將模型載入保持在綁定到 Application 生命週期的單例中,而不是個別的 Activity。在每次畫面切換時重新建立模型會導致明顯延遲和過度的電池消耗。
效能基準
在當前旗艦硬體上運行 Q4 或 Q8 量化模型的實際吞吐量:
| 裝置 | 模型 | 量化 | Token/秒 | 後端 |
|---|---|---|---|---|
| iPhone 17 Pro | 1.5B | INT8 | 136 | NPU (Apple ANE) |
| Galaxy S25 Ultra | 2B | INT8 | 91 | NPU (Google Tensor) |
| iPhone 16 Pro | 1.5B | Q4 | 22(持續) | Metal GPU |
| Snapdragon 8 Elite | 13B | Q4 | 20+ | Hexagon NPU |
| iPhone 15 Pro | 1B | Q4 | 約 18 | Metal GPU |
| 中階 Android (SD 7s Gen 3) | 1B | Q4 | 8-12 | CPU NEON |
作為參考:人類的閱讀速度大約是每秒 5-7 個 token。上面列出的每一款旗艦裝置,搭配 1-3B 模型都超過了舒適的閱讀速度。即使是中階裝置每秒 8-12 個 token,對大多數使用場景也感覺流暢。
NPU 的數據(iPhone 17 Pro 每秒 136 個 token,Galaxy S25 Ultra 每秒 91 個 token)代表了能力的躍進。在 NPU 加速路徑上,延遲降至 CPU 基準線的大約 1-20%,而每兆運算的功耗效率顯著優於 GPU 或 CPU 推論。
這些數字對使用者體驗的意義: 在 iPhone 16 Pro 上每秒 22 個 token,200 個 token 的回應在不到 10 秒內呈現完成。首 token 延遲(串流開始前的時間)通常是 200-800ms,取決於提示詞長度。兩者對大多數應用程式內助手模式都是可接受的。
散熱管理和電池
持續的 LLM 推論是行動處理器處理的最耗熱工作負載之一。iPhone 16 Pro 在持續負載下會損失約 44% 的吞吐量,因為 SoC 會降頻以保護硬體溫度。基準測試顯示 22 tok/s 的裝置,在連續推論 5-10 分鐘後可能只能達到 12-14 tok/s。
實際的緩解策略:
限制推論時間。 對大多數使用場景,回應在 30 秒內完成。設定適合你使用場景的最大 token 數(n_predict)。這限制了每次請求的熱量影響。
增加請求間延遲。 對於背景處理任務,在完成之間插入短暫的暫停。即使短暫的暫停也能讓 SoC 在下一次推論之前散熱。
對持續任務選擇較小的模型。 1B 模型以更高的吞吐量生成 token,產生的熱量遠少於 3B 模型。對於分類、擷取或格式化任務,較小的模型通常能產生同等的結果。
在 Android 上監控裝置溫度。 ThermalManager API(Android 10+)以 0-6 的級距暴露熱狀態。註冊監聽器,並在裝置升溫時降低推論頻率或上下文長度。iOS 上沒有直接等效的 API,但你可以測量吞吐量下降作為替代指標。
電池指引: 1B 模型在 iPhone 16 Pro 上以全速持續運行,SoC 功耗比基準線大約多 2-3 瓦。活躍的推論工作階段相比典型應用程式使用,大約減少 20-30% 的電池續航力。對大多數應用程式內助手模式(使用者發起的短暫請求,中間有暫停),影響要小得多。
模型交付策略
如何將 GGUF 檔案送到 裝置上,和如何運行它一樣重要。
打包在應用程式二進位檔中
優點:零延遲的首次使用體驗,不需要網路,不需要下載 UX。 缺點:App Store 大小限制。Apple 允許不超過 200 MB 的無線下載無需使用者確認;超過 4 GB 的應用程式需要透過 Wi-Fi 下載。Google Play 有類似的限制。
適用於: 1B Q4_K_M 模型(808 MB)作為可下載資源,透過 iOS On-Demand Resources 或 Android App Bundle 資產套件。模型不在主要二進位檔中,但在安裝時自動下載。
首次啟動時下載
對較大模型最常見的模式。應用程式不帶模型出貨,在首次啟動時(或在「設定 AI 功能」選擇畫面上)從你的 CDN 下載 GGUF。
實作注意事項:
- 在 iOS 上使用
URLSession背景下載任務,這樣即使使用者將應用程式放到背景,下載仍會繼續。 - 在 Android 上使用
WorkManager搭配NETWORK_NOT_ROAMING或NETWORK_UNMETERED約束。 - 顯示進度並提供清楚的說明(「正在下載 AI 模型,2 GB,建議使用 Wi-Fi」)。
- 積極快取下載內容。如果檔案已存在且通過校驗碼驗證,不要重新下載。
- 考慮將 GGUF 儲存在應用程式的
Application Support目錄(iOS)或filesDir(Android),而不是共用位置,以避免在儲存空間不足時被作業系統清理。
差異更新
當你發布新的微調版本時,你可能不想每次更新都推送 2 GB 給每個使用者。差異更新模式:
- 僅 LoRA 適配器: 如果你的更新是對相同基礎模型的新微調,只發送 LoRA 適配器檔案(通常 20-200 MB),並在推論時將其載入到凍結的基礎模型上。llama.cpp 透過
--lora旗標或等效 API 呼叫支援 LoRA 適配器。這比替換整個 GGUF 更節省頻寬。 - GGUF 差異: 對於需要新基礎的架構變更,有工具可以計算 GGUF 版本之間的二進位差異。如果只有部分權重改變,補丁比完整重新下載小得多。
- 版本標記的 CDN 路徑: 將模型儲存在
/models/v2/model.Q4_K_M.gguf等路徑,並在應用程式啟動時檢查版本端點。只在遠端版本較新時才更新本地副本。
llama.cpp 的平台替代方案
在投入 llama.cpp 整合路徑之前,評估平台管理的 API 是否能滿足你的需求。
Apple Foundation Models API(iOS 18.4+ / WWDC 2025)
Apple 發布了一個用於裝置端推論的公開 Swift API,目標是其大約 3B 參數的裝置端模型。該 API 是高階的:你用 GenerationOptions 結構描述任務,然後接收文字、結構化 JSON 或工具呼叫。
優點: 不需要下載或維護模型,由 Apple 進行硬體最佳化,極其簡單的 Swift API,沒有記憶體管理煩惱。
缺點: 你無法載入自定義微調模型。你被限制在 Apple 的基礎模型及其能力範圍內。不適用於 Android。專業領域的模型品質可能不足。
在以下情況使用 Foundation Models API:你的任務夠通用,Apple 的基礎模型能很好地處理,而且你想在不管理模型檔案的情況下快速出貨。
在以下情況使用 llama.cpp 搭配自定義 GGUF:你需要領域特定品質、跨平台行為,或對模型精確輸出的控制。
Google Gemini Nano(Android,ML Kit GenAI APIs,Google I/O 2025)
Google 的 ML Kit 現在透過託管 API 暴露裝置端 Gemini Nano 推論。與 Apple 的方案類似,這運行的是由作業系統管理的固定模型,而非自定義模型。
優點: 簡單的 API,在支援的 Pixel 和合作夥伴裝置上不需要下載,與現有 ML Kit 模式整合。
缺點: 僅在 Pixel 9 和部分其他裝置上可用。不支援自定義模型。跨裝置一致性有限。
對於目標廣泛裝置支援且使用自定義微調模型的生產應用程式,llama.cpp 搭配 GGUF 仍然是最具可攜性的方案。
端到端檢查清單
出貨前,請確認:
- GGUF 以適合你目標裝置層級的量化匯出(Q4_K_M 適用於大多數行動目標)
- 檔案大小符合你的交付策略(低於 200 MB 適合即時 OTA,低於 4 GB 適合延遲下載)
- 上下文長度(
n_ctx)設定為所需最低值,而非模型的最大值 - 模型在應用程式啟動時或在專用背景佇列載入一次,而非每次請求
- 記憶體警告已處理:在卸載完整模型之前先清除 KV 快取
- 熱節流已測試:運行推論 10 分鐘以上,並驗證持續負載下的輸出品質
- 首次啟動模型交付的背景下載已實作,並有進度回饋
- 在嘗試載入之前已對下載的 GGUF 進行校驗碼驗證
- Token 限制(
n_predict)設定為合理上限,以限制最壞情況的推論時間
使用 Ertas 開始
上述整合工作假設你已經有了一個微調後的 GGUF。微調步驟就是 Ertas 的用武之地。
上傳你的領域資料,視覺化地設定訓練參數,然後以你目標量化等級匯出結果為 GGUF。Ertas 處理雲端 GPU 運算、資料集格式化和量化匯出。你會拿回一個 .gguf 檔案,準備好放入上述描述的 iOS 或 Android 整合中。
行動端推論層是開源基礎設施。差異化因素是裡面的模型:一個理解你的領域、你使用者的語言,以及你產品特定輸出需求的模型。這就是微調產生的,也是你擁有的部分。
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

Fine-Tuning for App Developers: A Non-ML-Engineer's Guide
A practical guide to fine-tuning AI models for mobile app developers. Learn LoRA, QLoRA, and GGUF export without needing an ML background.

GGUF Explained: The Open Format That Runs AI Anywhere
GGUF is the file format that made running AI models on consumer hardware practical. Here's what it is, how it works, and why every AI builder should understand it.

Shipping GGUF Models: App Store Bundling vs Post-Install Download
Two ways to get your GGUF model onto the user's device. Bundle it with the app for simplicity, or download post-install for flexibility. Architecture, size limits, and best practices for both.