大模型微调实战:从LLaMA Factory到Ollama本地部署全流程 这两年“大模型微调”这个词从论文里走进了开发者的日常但真正亲手把通用大模型变成自己专属助手的程序员其实不多。原因无非三个不知道数据怎么准备、怕显存不够、以及部署链路太长。我最近用 LLaMA Factory 配合 Ollama 完整跑过几轮项目可以负责任地说这条路径对普通开发者已经非常友好了。这篇文章按照我实际操作的顺序把微调实战拆开讲清楚从数据准备、参数设置到最终本地部署全程可以在消费级显卡上完成适合想做私有化助手、垂直领域问答、角色扮演对话的同学参考。1. 为什么是 LLaMA Factory Ollama 这套组合1.1 先想清楚微调到底解决什么问题很多同学一上来就问“我要不要微调”。我一般会反问你需要的到底是“记住新知识”还是“学会一种新的表达方式”如果你只是想让模型知道你们公司的产品文档那用 RAG检索增强生成就够了把文档切片、向量化、检索后塞进上下文成本低、更新也方便。但如果你希望模型在对话时始终保持某种语气、严格遵守某种业务规则、按照固定流程回答问题比如客服助手必须先用“您好”开头、遇到售后问题必须优先引导退款流程那光靠提示词是压不住的。这时候微调才有意义。微调的本质是让模型在原有能力基础上针对你的数据分布再做一次定向学习。它并不会把模型变成另一个人但会让模型在你给的样本空间内表现得越来越像“你想要的助手”。用 LLaMA Factory 做这件事最大的好处是它把数据格式、训练脚本、多卡支持、量化训练、WebUI 全部封装好了你不需要自己写 Trainer 循环也不需要在不同框架之间来回折腾。1.2 LLaMA Factory 解决了什么痛点LLaMA Factory 是一个开源的大模型训练框架名字里虽然带 LLaMA但实际支持很多主流模型架构。它把微调流程简化成了“准备数据 选参数 点开始”三个步骤尤其适合个人开发者和小团队。我对比过用原生 Transformers 脚本和 LLaMA Factory 的区别。原生的写法需要自己处理数据集类、tokenizer padding、label mask、梯度 checkpointing、混合精度、日志记录一套代码调下来至少半天。而 LLaMA Factory 把这些都内置了命令行工具和 WebUI 都只是调参入口底层基于成熟的训练生态可靠度足够高。它还内置了 LoRA、QLoRA、DoRA、全参微调等多种训练方式。对于大多数个人项目LoRA 和 QLoRA 就是最常用的两条路。LoRA 通过在注意力矩阵上插入低秩适配器大幅减少可训练参数量QLoRA 则进一步把基座模型量化到 4bit显存占用能压缩到 8GB 级别。这意味着普通人手里的显卡也能跑得动 7B 甚至更小参数的模型。1.3 Ollama 在部署环节的价值微调完模型只是第一步怎么把它变成能对外提供服务的东西往往是更麻烦的一步。Ollama 在这里的价值是让“本地部署模型”变成一条命令的事。ollama serve 启动后它会在本地暴露一个兼容 OpenAI 接口的服务你可以直接通过 HTTP 请求来对话。模型的管理也非常简单ollama list 查看本地模型ollama pull 拉取外部模型ollama create 用于导入自定义模型全程不需要手写推理服务、不需要维护 GPU 进程、不需要处理并行请求。我用 Ollama 最大的感受是它把“模型文件”和“运行环境”做了一个很干净的隔离。你只要把一个微调好的模型转成 GGUF 格式再写一个很小的 Modelfile就能让模型跑在统一的运行时里。后面不管是做命令行测试、接 Web 后端还是接客服系统都非常顺手。1.4 完整流程先混个脸熟为了不让你在后面的细节里迷路我先把整体链路摆出来原始语料 → 数据清洗 → 构建 Alpaca 格式数据集 → 放在 LLaMA Factory 的 data 目录并注册 → 命令行或 WebUI 发起 LoRA/QLoRA 训练 → 训练完成后导出合并权重 → 转换成 GGUF 格式 → 编写 Modelfile → 使用 ollama create 导入 → 通过 ollama run 或 API 测试。这个流程看起来长但每一步都有现成工具支撑。我自己第一次跑通时从零开始大约用了四个小时其中大部分时间花在数据准备和参数调试上。后面的项目如果数据已经是现成的半小时就能完成训练到部署。2. 准备阶段硬件、软件与数据集2.1 硬件门槛到底有多高先说结论一张 8GB 显存的 NVIDIA 显卡配合 QLoRA就能微调一个 7B 参数的中文模型如果你只有 CPU也能跑但训练速度会比较感人适合简单实验。具体来说微调 7B 模型时模型权重、梯度、优化器状态、中间激活共同决定显存占用。QLoRA 把基座模型量化到 4bit 后模型权重本身只需要 4GB 左右额外加上 LoRA 适配器参数和激活值8GB 显存可以勉强放下配合梯度检查点后效果更好。如果你有 12GB、16GB 显存那就能比较从容地调整批次大小和序列长度。Mac 用户也别慌M 系列芯片可以直接用 CPU/GPU 跑小模型4bit 量化后的 7B 模型推理速度还不错训练虽然慢但 1000 条以内的数据也能接受。我不建议新手一上来就追求 14B 或更大模型先用自己的数据在小模型上跑通链路比什么都重要。2.2 安装 LLaMA Factory安装过程没有什么黑魔法建议用 conda 隔离环境避免和项目依赖打架。示例命令如下git clone https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Factory conda create -n llama_factory python3.10 -y conda activate llama_factory pip install -e .[torch]如果 GPU 是 NVIDIA 且显存比较紧张推荐装带 flash attention 的版本会减少显存占用和加速训练。具体可以看项目 README 里的安装说明。安装完成后命令行里会有 llamafactory-cli 命令这是后续操作的主要入口。这一步常见的坑是 torch 版本和 CUDA 版本不匹配。我的习惯是先单独安装好 torch确认 GPU 能被识别再安装框架依赖这样排查问题会容易很多。2.3 数据集准备Alpaca 格式与数据质量LLaMA Factory 默认支持多种数据集格式最常见的是 Alpaca 格式。一条样本有两个关键字段instruction 表示指令output 表示期望输出。如果涉及上下文材料可以加 input 字段如果需要多轮对话可以用 conversations 字段。我举一个单轮问答的例子文件格式是 JSON每行一条{instruction: 请介绍一下贵公司的退款政策, input: , output: 我们支持7天无理由退款但定制类产品除外。您可以在订单页面提交申请审核通过后1-3个工作日到账。} {instruction: 我的订单已经发货如何修改收货地址, input: , output: 订单发货后地址无法直接修改建议您联系客服并提供新地址我们会尝试联系物流拦截。若拦截失败您可以在包裹送达后拒收系统会自动安排退款。}放好数据文件后需要把数据集登记到 data/dataset_info.json 里。比如文件名叫 my_qa.json就添加如下条目{ my_qa: { file_name: my_qa.json, columns: { prompt: instruction, query: input, response: output } } }数据质量方面我强调几点第一每条样本的业务答案必须准确因为模型学的是你的答案不是网上的通用知识第二要有足够的多样性不能一百条里都是退款问题第三要避免敏感内容和隐私信息模型会把这些内容学进去。我一般会拿 50 条种子数据先人工跑一遍确认标注口径统一再扩大规模。2.4 基座模型怎么选选基座模型的核心原则是中文任务优先中文语料强的模型代码任务优先代码能力强的模型英文场景可以选欧美的开源模型。如果显卡显存一般7B 参数左右是性价比最高的区间既保留了较强的语义能力又不会让显存爆掉。这里要特别注意用 Base 模型还是 Instruct 模型。Base 模型没有经过对话指令微调需要你用大量对话数据来“教会”它对话格式对数据量和质量要求较高。Instruct 模型已经具备聊天能力你继续微调是让它适配你的业务风格通常更容易出效果。我个人的推荐个人项目数据量少于 5000 条时使用指令微调过的开源模型作为起点把训练重点放在风格迁移和规则学习上如果数据量足够大又希望模型彻底去除通用对话痕迹再考虑从 Base 模型开始。3. 微调实操参数是灵魂3.1 命令行训练还是 WebUILLaMA Factory 提供了两种操作方式WebUI 适合第一次尝试的人页面里能直观地选择模型、数据集、训练参数还能实时看到损失曲线命令行适合需要批量复现和自动化流程的情况。我前两次用的 WebUI后来切换到了命令行原因是我经常需要记录参数组合命令可以完整保存到脚本里比页面截图方便。WebUI 的启动方式也很简单llamafactory-cli webui启动后在浏览器里按表单填写即可。下面我以命令行方式演示一次完整的 LoRA 训练这是最核心的环节。3.2 一次命令搞懂核心参数假设你已经把基座模型下载到本地目录路径为 /data/base_model数据集名为 my_qa训练命令可以写成这样llamafactory-cli train \ --model_name_or_path /data/base_model \ --dataset my_qa \ --template auto \ --finetuning_type lora \ --lora_rank 8 \ --lora_alpha 16 \ --output_dir outputs/my_lora \ --num_train_epochs 3 \ --per_device_train_batch_size 2 \ --gradient_accumulation_steps 4 \ --learning_rate 2e-4 \ --max_seq_length 2048 \ --bf16逐个看关键参数lora_rank 是低秩矩阵的秩。秩越高可学习的参数越多模型就越容易记住训练集中的细节但也越容易过拟合。8 到 32 是常见范围第一轮先用 8 是比较稳的。lora_alpha 是缩放系数通常设置为 lora_rank 的两倍左右。它和 lora_rank 的比例会影响实际学习幅度16/8 的组合在多数场景下表现均衡。per_device_train_batch_size 是每张卡的批次大小。显存不够就往下调比如 1 或 2。gradient_accumulation_steps 用来“虚拟地”增大批次大小每次累积若干个梯度步再更新一次参数。上面命令里 batch size 2 累计 4 步等效 global batch size 为 8。learning_rate 是微调里最值得调的参数。LoRA 通常使用 1e-4 到 5e-4比全参微调的 1e-5 到 3e-5 高一截因为只更新少量参数。如果你的模型是 Base 模型建议从 1e-4 开始如果是指令模型2e-4 到 3e-4 比较常见。max_seq_length 控制最大输入长度。训练数据如果普遍在几百字左右没必要设置得太长2048 够用太长会明显增加显存占用。bf16 是混合精度开关。在较新的 GPU 上推荐优先使用显卡不支持 bf16 时改用 fp16。Ampere 架构之前的卡对 bf16 支持不好需要留意。3.3 训练过程中盯哪些指标训练启动后终端会不断打印 loss 值。前几个 step loss 快速下降是正常的后面会在一个区间内波动。我一般会把日志保存下来训练结束后回看“最终 loss”和“验证集 loss”。如果训练集 loss 降得很快但验证集 loss 开始回升说明过拟合了。解决思路是减少 epoch、增大数据量、降低 lora_rank或者加入早停策略。如果训练 loss 一直下不去可能是数据格式问题、学习率太高或者模型输出长度和标签长度不匹配。LLaMA Factory 默认会保存多个 checkpoint 到 output_dir。你可以每隔一段时间中断训练加载最新 checkpoint 样例测试不必等全部跑完。这个“先测再练”的习惯能帮你少走很多弯路。3.4 模型导出合并 LoRA 权重训练完成后outputs/my_lora 里保存的是 LoRA 适配器权重它还不能直接部署需要和基座模型合并导出一个完整的模型文件。llamafactory-cli export \ --model_name_or_path /data/base_model \ --adapter_name_or_path outputs/my_lora \ --template auto \ --finetuning_type lora \ --export_dir /data/my_merged_model \ --export_size 5 \ --export_legacy_format falseexport_dir 就是合并后的模型目录可以直接用 Transformers 加载。如果你用的是 QLoRA 训练的模型导出的同样可以合并回原始精度不需要担心量化残留问题。导出的模型是 HuggingFace 格式Ollama 不能直接加载所以下一步要转换成 GGUF。我习惯了用 llama.cpp 提供的转换脚本建议单独建一个工作目录git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp pip install -r requirements.txt python convert_hf_to_gguf.py /data/my_merged_model --outfile /data/my_merged.gguf --outtype f16这样会先生成一个 fp16 的 GGUF 文件文件体积可能接近 14GB。如果我们希望部署时轻量一些再做一次量化生成 4bit 文件./llama-quantize /data/my_merged.gguf /data/my_merged_q4_k_m.gguf q4_k_m如果你的环境里没有编译过 llama.cpp可以先只编译 quantize 部分或者用系统里已有的 llama-quantize。这一步得到 q4_k_m 文件后就轮到 Ollama 登场了。4. 用 Ollama 把模型变成可对话的服务4.1 Ollama 安装与基本操作Ollama 的安装非常简单到官网下载对应的安装包或者用一键脚本安装。Linux 服务端场景下安装完成后先确认服务在跑ollama serve新开一个终端查看本地模型列表ollama list如果列表为空说明还没有导入任何模型。Ollama 也支持直接拉取社区里的模型但对于微调后的专属模型我们需要本地导入。4.2 Modelfile 编写与导入模型Ollama 导入自定义模型的载体是 Modelfile它定义了模型文件位置、对话模板和推理参数。为刚才的 GGUF 文件写一个 ModelfileFROM /data/my_merged_q4_k_m.gguf TEMPLATE {{- if .System }}|im_start|system {{ .System }}|im_end| {{- end }}|im_start|user {{ .Prompt }}|im_end| |im_start|assistant SYSTEM 你是小助手请用简洁、专业的中文回答用户问题。 PARAMETER temperature 0.7 PARAMETER top_p 0.9TEMPLATE 里的尖括号格式必须和基座模型原来的对话模板保持一致。如果基座模型用了其他模板比如包含特殊分隔符的模板就直接替换成那套模板否则模型输出的格式会变得非常奇怪。SYSTEM 是系统提示词可以根据业务需求调整。然后执行导入ollama create my-assistant -f Modelfile无报错后ollama list 里就会出现 my-assistant。4.3 对话测试与 API 接入命令行直接测试ollama run my-assistant --verbose输入几个和训练数据类似的问题看回答风格是否贴近预期。确认没问题后就可以接 API 了。ollama serve 默认监听 11434 端口并且兼容 OpenAI 的接口格式。curl http://localhost:11434/v1/chat/completions \ -H Content-Type: application/json \ -d {model: my-assistant, messages: [{role: user, content: 退款需要多久到账}]}Python 里也可以直接用 requestsimport requests resp requests.post( http://localhost:11434/v1/chat/completions, json{ model: my-assistant, messages: [{role: user, content: 退款需要多久到账}], temperature: 0.5 } ) print(resp.json()[choices][0][message][content])这样你的专属助手就已经具备对外服务能力了。后续无论是做前端聊天框、客服系统还是内部工具只需要调用这个接口即可。5. 常见问题与排查实录5.1 显存不够怎么办显存不足是最常见的问题。优先做三件事第一开启 QLoRA用 4bit 量化基座模型显存占用能下降一半以上第二开启 gradient checkpointing以少量训练时间换显存第三调小 per_device_train_batch_size 和 max_seq_length。如果 8GB 显存依然爆可以考虑把模型换成 3B 或 1.5B 参数然后在数据质量上下功夫。小模型在垂直任务上不一定比大模型差前提是你的数据分布足够集中。5.2 数据集格式报错很多新手会踩 dataset_info.json 配置坑。如果训练时提示找不到数据集字段先检查三处JSON 文件是否每一行都是合法 JSONdataset_info.json 中的 columns 是否和 JSON 字段名一致数据集中不能有空字符串或 null 值。我自己碰到过处理导出的 CSV 时把数字写成了整数导致模型把输出当成 token id这个一定要避免。5.3 中文能力变差或胡言乱语微调后模型开始说胡话通常是学习率过高或数据量过少。你可以把 learning_rate 从 2e-4 降到 1e-4同时增加 epoch 数时要谨慎。还有个常见原因是训练数据里混入了大量超出模型能力的复杂问题模型学不会就开始乱编。建议先人工喂几条简单问题确认模型能稳定回答再慢慢增加难度。5.4 Ollama 导入后回答格式错乱如果导入 Ollama 后回答缺少系统提示、出现多余特殊符号十有八九是 TEMPLATE 和模型原模板不一致。解决办法是回到微调前的模型把原始 tokenizer 里的 chat_template 打印出来照着写进 Modelfile。另外temperature 和 top_p 设置过高也会导致回答飘可以先调成 0.3 和 0.8 再观察。5.5 如何判断过拟合了想尽早发现过拟合最好把数据集分成训练集和验证集。LLaMA Factory 支持按比例切分训练日志里也会输出验证集指标。如果训练 loss 持续下降验证集 loss 却不降或反弹就要考虑降低 lora_rank、减少 epoch、增加数据多样性。微调不是“学得越狠越好”模型的通用能力如果被覆盖得太多反而会显得呆板。6. 实操心得与几个进阶玩法6.1 数据质量比数量重要做过三轮微调之后我最大的体会是500 条高质量数据的效果可能比 5000 条粗糙数据还好。高质量意味着答案准确、格式统一、覆盖典型场景。我见过身边的朋友为了凑数量从网上爬了一堆问答结果模型学到了大量错误信息和重复句式越调越差。数据清洗和人工抽检不是浪费时间而是整个项目里性价比最高的步骤。6.2 参数调试的几个小技巧第一先用 50100 条数据跑一个极短的训练比如 0.1 个 epoch确认链路没问题再上全量数据。第二每次实验只改一个参数并把参数记录到表格里否则你很难判断到底是哪个修改起了作用。第三尽量固定随机种子保证不同实验之间可比较。第四训练结束前在验证集上多试几个和业务强相关的问题不要只看 loss。6.3 后续可以怎么扩展如果你的专属助手已经稳定可以再往前走一步把多轮对话历史接进 API让模型具备上下文记忆结合外部知识库做 RAG让模型既能保持业务风格又能回答实时信息还可以在 Modelfile 里调整 system prompt快速切换客服、顾问、创作助手等不同人设。我个人比较推荐的做法是先做一个最小闭环也就是“小数据微调 本地 Ollama 部署”把训练、导出、导入、API 调用这条链路跑通。跑通之后你自然知道下一步该优化数据还是优化参数也更有底气去尝试更大的模型。微调这件事最大的门槛其实不是技术而是动手做的决心。照着这个流程试一试你也能拥有一个真正属于自己的 AI 助手。