
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