Back to blog
    應用程式開發者的微調指南:非機器學習工程師版
    fine-tuningmobile-developmentloraqloraggufon-device-aisegment:mobile-builder

    應用程式開發者的微調指南:非機器學習工程師版

    為行動應用程式開發者準備的 AI 模型微調實用指南。學習 LoRA、QLoRA 和 GGUF 匯出,無需機器學習背景。

    EErtas Team·

    你能做出很棒的應用程式。你熟悉 Swift、Kotlin 或 React Native。你能打造精美的 UI、串接 REST API,還能在晚上 11 點除錯一個競態條件。現在你想加入一個 AI 功能:一些真正有用的東西,而不是 GPT-4 的薄薄包裝。

    問題是:每一篇微調教學都假設你知道什麼是「梯度」。它們一開始就寫 PyTorch 的 import。它們提到「注意力頭」好像這是常識一樣。你關掉了分頁。

    這篇指南不一樣。它用應用程式開發者真正需要理解的方式來解釋微調:聚焦在流程、實際的決策,以及成本。你不需要理解反向傳播。你需要理解 JSON。

    微調到底是什麼

    理解微調最簡單的方式,是想想你手機上的自動完成如何運作。

    你鍵盤的自動完成一開始是一個在數十億字上訓練的通用模型。隨著時間推移,它適應了你。它學到你在程式碼審查結尾會打「lgtm」,你總是在「Hey」後面接「so」,而且你有一種特定的拼錯「necessary」的方式。這種適應發生是因為模型看到了你的模式並進行了調整。

    微調 AI 模型是同樣的概念,只是有目的地進行。你拿一個通用模型(像 Llama 3.2,能寫文章、回答問題和生成程式碼),然後給它看數百個範例,展示你希望它在應用程式中的確切行為方式。訓練後,它就會以那種特定的方式回應,可靠地,每一次都是。

    結果是一個模型,它在你的任務上表現得比任何提示詞工程都好,在裝置端運行不需要 API 呼叫,而且每次推論成本為零。

    LoRA:為什麼你不需要重新訓練整個模型

    在微調對非 ML 團隊變得實用之前,唯一的選擇是完整微調:更新模型中的每一個參數。對於一個 70 億參數的模型,這意味著更新 70 億個數字。運算成本巨大。一次完整微調需要昂貴的硬體和數天的訓練時間。只有大型實驗室才負擔得起。

    2022 年,研究人員在 ICLR 發表了 LoRA(Low-Rank Adaptation,低秩適應,arXiv:2106.09685)。關鍵洞察:你不需要更新所有參數就能改變模型的行為。你可以完全凍結原始模型權重,只在上面新增一小組可訓練的層。這些新層稱為 LoRA 適配器。

    實際的結果如下:

    • LoRA 只訓練完整微調需要更新參數的 0.1-1%
    • 訓練速度大幅加快,成本大幅降低
    • 適配器檔案很小:7B 模型通常 50-200MB
    • 原始基礎模型完好無損且可重複使用

    把它想成模型的外掛。基礎模型是應用程式。你的 LoRA 適配器是讓它完全按照你使用場景所需行為的擴充功能。

    2023 年,QLoRA(arXiv:2305.14314,NeurIPS 2023)又將這推進了一步。QLoRA 將 LoRA 與 4 位元量化結合,在訓練期間壓縮模型的數字以減少記憶體佔用。結果:你可以在具有 6-10GB VRAM 的消費級 GPU 上微調一個 70 億參數的模型,或在每次執行成本 $3-$10 的雲端執行個體上進行。這在獨立應用程式開發者的預算範圍內。

    四步驟流程

    為你的應用程式微調模型遵循四個步驟。本指南的其餘部分將逐一說明每個步驟。

    1. 準備你的訓練資料為 JSONL 檔案
    2. 在雲端 GPU 上微調使用 LoRA 或 QLoRA
    3. 匯出為 GGUF並進行行動端量化
    4. 整合到你的 iOS 或 Android 應用程式使用 llama.cpp 綁定

    就這樣。任何步驟都不需要 ML 理論。

    步驟 1:準備你的訓練資料

    你的訓練資料是整個流程中最重要的部分。一個小而高品質的資料集每次都勝過大而混亂的資料集。史丹佛大學的 Alpaca 專案在 2023 年證明了這一點(arXiv:2303.16199):52,000 個合成範例和大約 $500 的運算成本,就足以讓 Llama 7B 在廣泛的任務上匹配 GPT-3.5。品質和格式比數量更重要。

    你需要多少範例?

    OpenAI 自己的指引建議在微調他們的模型時從 50-100 個範例開始。對於使用 LoRA 的開源模型,100-500 個範例是聚焦任務的實際起始範圍。更多資料有幫助,但一旦模型看到足夠的變化來進行泛化,邊際效益就會快速遞減。

    對於你的第一次微調執行,目標是 100-300 個範例。你隨時可以之後再增加。

    格式

    訓練範例儲存在 JSONL 檔案(JSON Lines)中,每一行是一個獨立的 JSON 物件。標準格式使用聊天風格的訊息:

    {"messages": [{"role": "system", "content": "You are a cooking assistant that suggests recipes based on available ingredients."}, {"role": "user", "content": "I have chicken, garlic, lemon, and rosemary."}, {"role": "assistant", "content": "Here are two recipes you can make right now:\n\n1. Lemon Garlic Roasted Chicken..."}]}
    {"messages": [{"role": "system", "content": "You are a cooking assistant that suggests recipes based on available ingredients."}, {"role": "user", "content": "I have eggs, spinach, and feta."}, {"role": "assistant", "content": "Three quick options:\n\n1. Greek Scrambled Eggs..."}]}

    每一行是一個訓練範例。system 訊息定義了模型的角色。user 訊息是輸入。assistant 訊息是你希望模型學習的理想輸出。

    高品質訓練資料的技巧

    匹配你的真實輸入。 如果你應用程式中的使用者發送簡短、隨意的訊息,你的訓練輸入應該看起來像簡短、隨意的訊息。如果他們發送結構化查詢,就用結構化查詢來訓練。

    保持輸出一致。 如果某些助理回應是兩個句子,而其他的是十個段落,模型將無法學到可靠的模式。選擇一種格式並堅持下去。

    涵蓋邊緣案例。 包含使用者詢問模型範圍之外內容的範例。教模型如何優雅地回應離題的請求,而不只是順利路徑。

    變化措辭。 十個用稍微不同措辭問同一個問題的範例,比十個每個都涵蓋不同場景的範例教給模型的要少。

    將你的檔案儲存為 training_data.jsonl。這就是下一步所需的一切。

    步驟 2:在雲端 GPU 上微調

    你不需要擁有任何 GPU 硬體。雲端 GPU 供應商按小時或按次出租算力。

    微調期間發生了什麼

    你上傳你的 JSONL 檔案並選擇一個基礎模型。訓練過程會反覆將你的範例通過模型運行,測量模型的輸出與你理想輸出的差距,並調整 LoRA 適配器權重來縮小這個差距。這個過程稱為一個訓練 epoch。

    對於 100-300 個範例的 LoRA,預期:

    • 訓練時間:在單個 GPU 上 10-30 分鐘
    • LoRA 成本(12-16GB VRAM):每次執行 $5-$15
    • QLoRA 成本(6-10GB VRAM):每次執行 $3-$10

    你會在改進資料集的過程中執行幾次訓練。新功能的微調總成本通常是 $20-$50,之後你就會得到一個滿意的模型。

    為行動端選擇基礎模型

    對於 iOS 和 Android 的裝置端部署,模型大小是主要限制。實際的最佳範圍:

    • Llama 3.2 1B Q4_K_M:磁碟上 808MB,在 iPhone 16 Pro 上大約每秒 22 個 token,記憶體開銷不到 100MB
    • Llama 3.2 3B Q4_K_M:磁碟上 2.02GB,能力明顯更強,仍然適合大多數現代裝置

    對於大多數應用程式功能(分類、短文生成、問答、摘要),1B 模型在你特定任務上微調後,將在該任務上超越一個通用 3B 模型。透過微調實現的專業化比單純的參數數量對窄任務更有效。

    Apple 的 Foundation Models API(在 WWDC 2025 宣布)讓第三方應用程式存取一個大約 3B 參數的裝置端模型,無需下載。如果你的使用場景在 Apple 模型支援的範圍內,值得探索。對於需要自定義行為或輸出格式的情況,微調你自己的模型能給你平台 API 無法提供的控制力。

    訓練期間要觀察什麼

    你不需要深入理解訓練指標,但有兩個數字很重要:

    訓練損失應該隨時間下降。如果它保持平坦,你的資料可能有品質問題。

    驗證損失是在你資料的一小部分保留子集上測量的。如果訓練損失下降但驗證損失上升,模型正在記憶你的訓練範例而不是學習泛化。這稱為過擬合。修正方法是增加更多多樣化的範例或減少訓練 epoch 數。

    步驟 3:匯出為帶量化的 GGUF

    微調後,你有了一個 LoRA 適配器。在你可以將它放入行動應用程式之前,你需要:

    1. 將適配器合併到基礎模型中
    2. 量化合併後的模型以縮小大小
    3. 匯出為 GGUF 檔案

    GGUF(GPT-Generated Unified Format)是 llama.cpp 使用的檔案格式,llama.cpp 是在 iOS 和 Android 上驅動裝置端 AI 的推論函式庫。它是一個包含運行模型所需一切的單一檔案。

    量化降低了模型數字的精度。量化不是將每個數字儲存為 32 位浮點數,而是將它們儲存為 4 位整數。這將檔案大小縮小約 75% 並加速推論,但會有少量品質損失。

    理解 Q4_K_M

    當你看到一個模型標記為 Q4_K_M 時,每個部分都有含義:

    • Q4:4 位元量化(相比 8 位元 Q8 或全精度 F16)
    • K:使用一種稱為 K-quant 的量化演算法,比更簡單的方法更精確
    • M:中等變體(在大小和品質之間取得平衡;還有 S 代表小型,L 代表大型)

    對於行動端部署,Q4_K_M 是建議的量化等級。它在消費級硬體上很好地平衡了大小、速度和品質。

    使用 Q4_K_M 量化後的檔案大小:

    • Llama 3.2 1B:808MB
    • Llama 3.2 3B:2.02GB

    兩者都適合放在應用程式下載中,不過 3B 模型可能需要在首次啟動後下載,而不是打包在初始安裝中。

    步驟 4:在 iOS 和 Android 中整合

    你有了一個 .gguf 檔案。現在你需要在應用程式中運行它。

    iOS (Swift)

    llama.cpp 專案透過 llama.cpp SPM 套件提供 Swift 綁定。將它加入你的 Package.swift

    .package(url: "https://github.com/ggerganov/llama.cpp", from: "b3000.0.0")

    將你的 GGUF 檔案打包在應用程式的資源中,或在首次啟動時下載到應用程式的 Documents 目錄。然後載入並運行模型:

    import llama
    
    let modelPath = Bundle.main.path(forResource: "my-model.Q4_K_M", ofType: "gguf")!
    let params = LlamaContextParams.default
    let context = try LlamaContext(modelPath: modelPath, params: params)
    
    let response = try await context.complete(prompt: "Summarize: \(userInput)")

    在 iPhone 16 Pro 上,1.5B 模型透過 CPU 路徑大約每秒運行 22 個 token。iPhone 17 Pro 配備改進的 NPU(INT8 運算),基準測試約每秒 136 個 token。對大多數應用程式功能而言,22 tok/s 足以讓串流回應感覺自然。

    Android (Kotlin/NDK)

    在 Android 上,llama.cpp 透過 JNI(Java Native Interface)或 NDK 整合。Google 的 MediaPipe LLM Inference API 提供了一個更高階的抽象層,包裝了 llama.cpp,對於不想直接管理 JNI 的 Android 開發者來說更容易整合:

    val options = LlmInference.LlmInferenceOptions.builder()
        .setModelPath("/data/local/tmp/my-model.Q4_K_M.gguf")
        .setMaxTokens(512)
        .build()
    
    val llmInference = LlmInference.createFromOptions(context, options)
    val result = llmInference.generateResponse(userPrompt)

    MediaPipe 在 Qualcomm 和 Mali GPU 可用時自動處理 GPU 加速。

    React Native

    對於 React Native 應用程式,llama.rn 函式庫為 iOS 和 Android 提供了一個跨平台的 llama.cpp 包裝器:

    npm install llama.rn
    import { initLlama } from 'llama.rn';
    
    const context = await initLlama({
      model: require('./assets/my-model.Q4_K_M.gguf'),
      n_ctx: 2048,
    });
    
    const result = await context.completion({
      prompt: userInput,
      n_predict: 256,
    });

    模型完全在裝置端運行。不需要 API 金鑰,不需要網路請求,沒有每次推論成本。

    微調能做什麼和不能做什麼

    這個章節將幫你避免浪費一次微調執行。微調是一個強大的工具,但它解決的是一組特定的問題。

    微調擅長的事

    學習格式。 如果你需要模型總是以 JSON 回應、總是遵循特定結構,或總是應用一致的風格,微調是正確的工具。幾百個目標格式的範例,模型就會可靠地遵循。

    領域特定語言。 如果你的應用程式在一個專業領域(醫療、法律、特定產業),微調會教模型該領域的術語和慣例。

    語氣和個性。 如果你希望你的 AI 功能以符合你應用程式品牌的特定聲音回應,微調比冗長的系統提示詞更可靠。

    任務專業化。 分類客服工單、從使用者輸入中擷取結構化資料、以特定風格生成短文內容。任何狹窄、定義明確的任務都能從微調中受益。

    微調無法新增事實

    這是最常見的誤解。微調不會教模型關於世界的新資訊。它教模型如何表現,而不是知道什麼。

    如果你想讓模型回答關於你的產品目錄、定價頁面或文件的問題,微調是錯誤的工具。在你的文件上微調不會可靠地讓模型回想起那些文件中的特定事實。它只會學習你文件的格式和風格。

    對於特定、會變動資訊的事實回想,請改用 RAG(檢索增強生成)。RAG 讓模型在推論時搜尋文件資料庫,並使用檢索到的文字作為上下文。微調和 RAG 互相補充:微調用於行為和格式,RAG 用於事實。

    微調無法擴展模型的推理能力

    一個在你任務上微調的 1B 模型,會在你的任務上表現得比一個通用 3B 模型更好。但它無法進行複雜的多步驟推理、生成長篇連貫文件,或解決只有更多參數才能帶來的能力所需的問題。了解你模型的上限,並在其範圍內設計你的功能。

    整合一切

    以下是完整流程的檢查清單:

    • 以 JSONL 聊天格式撰寫 100-300 個訓練範例
    • 檢查一致性:匹配的格式、多樣化的輸入、涵蓋邊緣案例
    • 上傳到微調平台或雲端 GPU 服務
    • 使用 LoRA 在 Llama 3.2 1B 或 3B 基礎模型上訓練
    • 檢查訓練和驗證損失;如需要則調整後重新執行
    • 合併適配器並匯出為 model.Q4_K_M.gguf
    • 新增 llama.cpp Swift 套件(iOS)、MediaPipe 或 llama.rn(Android/React Native)
    • 在首次啟動時打包或下載 GGUF
    • 在真實裝置硬體上以你的目標 token 吞吐量測試

    工具鏈已經成熟到一個沒有 ML 背景的 React Native 開發者可以在一個週末完成整個流程的程度。困難的部分不是訓練或整合。而是收集和清理好的資料集。

    從你的訓練資料開始。其他一切都從那裡展開。

    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