Back to blog
    应用开发者的微调指南:不需要ML工程师背景
    fine-tuningmobile-developmentloraqloraggufon-device-aisegment:mobile-builder

    应用开发者的微调指南:不需要ML工程师背景

    面向移动应用开发者的AI模型微调实用指南。学习LoRA、QLoRA和GGUF导出,无需ML背景。

    EErtas Team·

    你能构建出色的应用。你懂Swift、Kotlin或React Native。你能打造精美的UI,对接REST API,在晚上11点调试竞态条件。现在你想添加一个AI功能:真正有用的东西,而不是GPT-4的简单封装。

    问题在于:每个微调教程都假设你知道"梯度"是什么。它们一开篇就导入PyTorch,提到"注意力头"时好像那是常识。你直接关掉了页面。

    这篇指南不一样。它以应用开发者真正需要理解的方式来解释微调:聚焦于流程、实际决策和成本。你不需要理解反向传播,但你需要理解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-bit量化结合,在训练期间压缩模型的数值以减少内存占用。结果是:你可以在6-10GB显存的消费级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显存):每次运行5-15美元
    • QLoRA成本(6-10GB显存):每次运行3-10美元

    你会在优化数据集的过程中多次运行训练。一个新功能的微调总成本通常在20-50美元之间,直到你获得满意的模型。

    为移动端选择基础模型

    对于iOS和Android上的端上部署,模型大小是主要约束。实际最优选择:

    • Llama 3.2 1B Q4_K_M:磁盘占用808MB,在iPhone 16 Pro上大约22 tokens每秒,内存开销不到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-bit浮点数存储每个数字,量化将其存储为4-bit整数。这将文件大小减少约75%并加速推理,代价是轻微的质量损失。

    理解Q4_K_M

    当你看到一个模型标记为Q4_K_M时,每个部分都有含义:

    • Q4:4-bit量化(相对于8-bit 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 tokens每秒运行。iPhone 17 Pro凭借改进的NPU(INT8运算),基准测试约为136 tokens每秒。对于大多数应用功能,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