6. 导出与部署
这是什么:导出(export)= 把训练好的 LoRA 补丁和基座模型揉成一个完整的模型目录;部署 = 用 vLLM 起一个 OpenAI 格式的 HTTP 服务。
为什么用:训练产物是个几十 MB 的「补丁」,推理时还得背着基座模型一起加载。合并成一个目录才能丢给 vLLM、量化工具或者别的框架随便用。
如何用:本章按「合并 → 量化 → 起服务 → 验证」四步走,最后给你一张上线检查清单。
6.1 为什么要先合并
LoRA 训完产出的是一个适配器(adapter),几十 MB 到几百 MB:
saves/qwen3-4b/lora/sft/
├── adapter_config.json
├── adapter_model.safetensors
└── ...
它本身不是模型,离开基座就没意义。合并之后得到的是一个自包含的目录:
saves/qwen3_sft_merged/
├── config.json
├── generation_config.json
├── model-00001-of-00002.safetensors
├── model-00002-of-00002.safetensors
├── model.safetensors.index.json
├── tokenizer.json
└── ...
合并的好处:推理端只需要一个目录、加载快一步、能直接给 vLLM / SGLang / Transformers 用,也方便上传到 HuggingFace 分享。
6.2 第一步:合并权重
官方示例 examples/merge_lora/qwen3_lora_sft.yaml:
### model
model_name_or_path: Qwen/Qwen3-4B-Instruct-2507
adapter_name_or_path: saves/qwen3-4b/lora/sft
template: qwen3_nothink
trust_remote_code: true
### export
export_dir: saves/qwen3_sft_merged
export_size: 5
export_device: cpu # choices: [cpu, auto]
export_legacy_format: false
跑起来:
llamafactory-cli export examples/merge_lora/qwen3_lora_sft.yaml
你会看到(示意):
[INFO] Merging LoRA adapters to model: saves/qwen3_sft_merged
[INFO] Saving model to disk... Done.
四个导出参数的意思:
| 配置项 | 含义 |
|---|---|
export_dir |
合并后模型放哪儿 |
export_size |
每个分片文件多大(GB)。5 表示按 5GB 切;填 0 表示不切分 |
export_device |
cpu 更稳(不占显存),auto 会用 GPU 快一点 |
export_legacy_format |
是否导出旧格式权重,保持 false 即可 |
⚠️ 官方明确警告:合并 LoRA 时不要用量化模型,也不要设
quantization_bit。量化底座 + LoRA 合并出来的权重会有精度损失。要量化请走 6.3 的导出流程。
6.3 第二步:导出量化版(可选)
想要一个更小的模型,可以顺手导出一份 GPTQ 4bit 版本:
### model
model_name_or_path: Qwen/Qwen3-4B-Instruct-2507
template: qwen3_nothink
trust_remote_code: true
### export
export_dir: saves/qwen3_gptq
export_quantization_bit: 4
export_quantization_dataset: data/c4_demo.jsonl
export_size: 5
export_device: cpu
export_legacy_format: false
llamafactory-cli export examples/merge_lora/qwen3_gptq.yaml
export_quantization_dataset 是量化时用来校准的语料,几百条样本就够了,仓库里的 data/c4_demo.jsonl 可以直接用。量化后体积大概是原来的四分之一。
6.4 第三步:起一个 OpenAI 兼容 API
LLaMA-Factory 自带 API 服务,后端可以选 vLLM 或 SGLang:
API_PORT=8000 llamafactory-cli api examples/inference/qwen3.yaml infer_backend=vllm vllm_enforce_eager=true
你会看到(示意):
INFO: Started server process [1]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000
Visit http://localhost:8000/docs for API document.
几个要点:
| 项目 | 说明 |
|---|---|
API_PORT |
监听端口,默认 8000 |
API_HOST |
监听地址,默认 0.0.0.0(所有网卡) |
API_KEY |
设了就必须带 Authorization: Bearer <key>,适合公网暴露时用 |
API_MODEL_NAME |
对外报告的模型名,默认 gpt-3.5-turbo,方便兼容 OpenAI SDK 的老代码 |
infer_backend 的可选值是 huggingface / vllm / sglang / ktransformers,生产环境用 vllm 并发能力最好。vllm_enforce_eager=true 会关掉 CUDA Graph 加速(省显存、启动快,但吞吐略低),显存紧张时很有用。其他可调项还有 vllm_maxlen、vllm_gpu_util、vllm_max_lora_rank、vllm_config。
也可以直接用自己的配置指向合并后的模型:
model_name_or_path: saves/qwen3_sft_merged
template: qwen3_nothink
infer_backend: vllm
trust_remote_code: true
6.5 第四步:验证
浏览器打开 http://localhost:8000/docs,那是自动生成的交互式接口文档(Swagger UI)。命令行测一发:
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "用一句话介绍你自己"}],
"max_tokens": 128
}'
你会看到(示意):
{
"id": "chatcmpl-8f2a...",
"object": "chat.completion",
"model": "gpt-3.5-turbo",
"choices": [{"index": 0, "message": {"role": "assistant", "content": "我是一个专注于回答问题的 AI 助手。"}, "finish_reason": "stop"}],
"usage": {"prompt_tokens": 21, "completion_tokens": 24, "total_tokens": 45}
}
因为接口是 OpenAI 格式,现成的 OpenAI SDK 改个 base_url 就能直接用:
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
resp = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "你好"}],
)
print(resp.choices[0].message.content)
你会看到(示意):
我是一个专注于回答问题的 AI 助手,可以帮你解答各类知识与生活问题。
6.6 上线检查清单
| 检查项 | 怎么确认 |
|---|---|
| 合并用的基座和训练时是同一个 | model_name_or_path 对得上 |
推理的 template 和训练一致 |
两份 YAML 都检查一遍 |
| 合并时没用量化底座 | 合并配置里没有 quantization_bit |
| 服务能扛住并发 | 压测一下,或换 infer_backend: vllm |
公网暴露要设 API_KEY |
API_KEY=xxx llamafactory-cli api ... |
| 显存够 vLLM 用 | vllm_gpu_util 调小一点试试 |
动手改
- 把合并配置里的
export_device从cpu改成auto,对比耗时差别 - 用
llamafactory-cli export examples/merge_lora/qwen3_gptq.yaml导一份 GPTQ 版,然后看看两个目录各有多大 - 给 API 加一个
API_KEY,不带 key 再 curl 一次,看看是不是真的被拦住
小结
- LoRA 只是补丁,合并后才能当完整模型用
- 合并配置只有四个关键项:
export_dir/export_size/export_device/export_legacy_format - 合并时绝对不要用量化底座或
quantization_bit - 要量化就单独导一份:
export_quantization_bit+export_quantization_dataset - 起服务:
API_PORT=8000 llamafactory-cli api examples/inference/qwen3.yaml infer_backend=vllm,文档在/docs - 环境变量
API_PORT/API_HOST/API_KEY/API_MODEL_NAME控制监听和鉴权
全书完结
从「微调是什么」到「API 上线」,六章走完了一条完整链路:
理解原理 → 算清显存 → 备好数据 → 跑通 SFT → 偏好对齐 → 合并部署
接下来你可以做的事:把自己的业务数据按第 3 章的格式整理一份,跑一遍第 4 章的 LoRA,再用第 6 章把结果发成一个 API。提示词能解决的事就别微调,微调解决不了的事,记得先想想 RAG。
回到 教程总览 🐸