Chapter 12

模型导出:merge、量化、推理服务

📌 本章基于 src/llamafactory/cli/export.py 与 examples/merge_lora/ · commit 01398eb18dd4 。

12.1 训完之后的三条路

flowchart LR Out["训练产物
(LoRA adapter / 全参 checkpoint)"] Out --> A["路径 A: 不 merge
带 adapter 直接推理"] Out --> B["路径 B: merge 成单一权重
给生态工具使用"] Out --> C["路径 C: merge + 量化
压缩到 GGUF / GPTQ / AWQ"] A --> A1["llamafactory-cli chat
+ adapter_name_or_path"] B --> B1["llamafactory-cli export
→ saves/.../merged"] C --> C1["llamafactory-cli export
+ export_quantization_bit=4"] B1 --> B2["transformers / vLLM / SGLang
直接加载"] C1 --> C2["llama.cpp / Ollama / TensorRT-LLM"]

三条路各自的场景:

路径适合场景缺点
A. 不 merge 线上挂多个 adapter,按 user 切换 有些推理引擎不支持 adapter
B. merge 给一份"普通 HF 模型"出去 占盘 / 显存大
C. merge + 量化 边缘设备 / CPU 推理 有微小精度损失

12.2 路径 A:带 adapter 推理

本身不"导出",但作为对比放在前面。第 3 章演示过:

llamafactory-cli chat \
  model_name_or_path=Qwen/Qwen3-4B-Instruct-2507 \
  adapter_name_or_path=saves/qwen3-4b/lora/sft \
  template=qwen3_nothink \
  finetuning_type=lora

或 OpenAI 兼容 API:

llamafactory-cli api \
  model_name_or_path=Qwen/Qwen3-4B-Instruct-2507 \
  adapter_name_or_path=saves/qwen3-4b/lora/sft \
  template=qwen3_nothink \
  finetuning_type=lora \
  infer_backend=vllm           # huggingface / vllm / sglang / ktransformers

多 adapter 切换(多个用逗号):

adapter_name_or_path: saves/qwen3-4b/lora/sft,saves/qwen3-4b/lora/legal

12.3 路径 B:merge LoRA

仓库自带 examples/merge_lora/qwen3_lora_sft.yaml

### Note: DO NOT use quantized model or quantization_bit when merging lora adapters

### 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                  # 每个 safetensors 分片 5 GB
export_device: cpu              # cpu / auto;显存不够选 cpu
export_legacy_format: false     # false → .safetensors;true → .bin

启动:

llamafactory-cli export examples/merge_lora/qwen3_lora_sft.yaml

得到的 saves/qwen3_sft_merged/ 是一个标准 HF 模型目录:

config.json
generation_config.json
model.safetensors.index.json
model-00001-of-00002.safetensors
model-00002-of-00002.safetensors
tokenizer.json
tokenizer_config.json
special_tokens_map.json

它可以被 transformers.AutoModelForCausalLM.from_pretrained() / vLLM / SGLang / Ollama 等所有支持 HF 格式的工具直接加载。

不能 merge 的情况
  • QLoRA:基座是 4-bit 量化的,merge 回去会有精度损失,框架会拒绝;
  • 已加载的是 GPTQ / AWQ 量化模型:同上;
  • 正确做法:训练用 QLoRA 节省显存,但推理时 base 模型用 fp16,adapter 仍可挂载(路径 A)。

12.4 路径 C:merge + 量化导出

导出阶段量化的官方例子 examples/merge_lora/qwen3_gptq.yaml

### 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                              # 4 / 8
export_quantization_dataset: data/c4_demo.jsonl         # ★ 量化校准数据
export_size: 5
export_device: cpu
export_legacy_format: false

校准数据怎么选

目标推荐校准数据
通用对话 c4_demo.jsonl 或自家通用 100-500 条
行业模型 用你训练数据的 100-500 条样本(必须代表实际分布)
多语言 混合中英文校准

导出选项对照

export_quantization_bit方法显存(7B)典型工具
null 不量化(fp16/bf16) 14 GB HF / vLLM
8 GPTQ 8-bit 8 GB HF / vLLM / AutoGPTQ
4 GPTQ 4-bit 4 GB HF / vLLM / Ollama

12.5 把模型转 GGUF(llama.cpp / Ollama)

LLaMA-Factory 自身不直接导 GGUF,但 merge 后的 HF 目录可以被 llama.cpp 转:

# 装好 llama.cpp 源码后
cd llama.cpp
python convert_hf_to_gguf.py \
  /Users/zjw/Documents/LLM/train/repos/llama-factory/saves/qwen3_sft_merged \
  --outfile saves/qwen3_sft.gguf \
  --outtype f16

# 进一步量化
./quantize saves/qwen3_sft.gguf saves/qwen3_sft.Q4_K_M.gguf Q4_K_M

# Ollama 直接装
ollama create my-qwen3 -f Modelfile

Modelfile 示例:

FROM saves/qwen3_sft.Q4_K_M.gguf
TEMPLATE """<|im_start|>system
{{ .System }}<|im_end|>
<|im_start|>user
{{ .Prompt }}<|im_end|>
<|im_start|>assistant
"""

12.6 部署到推理引擎

vLLM

vllm serve saves/qwen3_sft_merged \
  --port 8000 \
  --max-model-len 8192 \
  --gpu-memory-utilization 0.9

SGLang

python -m sglang.launch_server \
  --model-path saves/qwen3_sft_merged \
  --port 30000

TensorRT-LLM

需要先用 TensorRT-LLM 的 build 脚本把模型转成 .engine。这一步通常工程师在 GPU 服务器上手动做,仓库不直接覆盖。

HuggingFace Inference Server (TGI)

docker run --gpus all -p 8080:80 \
  -v $(pwd)/saves/qwen3_sft_merged:/data \
  ghcr.io/huggingface/text-generation-inference:latest \
  --model-id /data

12.7 SwanLab / W&B / TensorBoard:把训练全流程留痕

不是导出但常被一起问。三个 report_to 选项:

report_to本地查看
tensorboardtensorboard --logdir saves/.../runs
wandb wandb login 后自动同步到 wandb.ai
swanlab 本地 dashboard,国内访问友好
mlflow 对接现有 MLflow Tracking server

12.8 导出清单

正式发布模型前的最小检查:

  1. tokenizer_config.json 里的 chat_template 字段已生成;
  2. ✅ 跑一次 llamafactory-cli chat 用 merged 模型,确认不带 adapter 也能正常回答
  3. ✅ 跑一份评测(llamafactory-cli eval),打分对比 base model;
  4. ✅ 加 README.md:训练数据来源、训练 YAML、license、注意事项;
  5. ✅ 上传时压缩 .safetensors,不要 .bin
  6. ✅ 多模态模型还要把 preprocessor_config.json / processor_config.json 也带上。

12.9 export_model() 真实流程

"export"子命令落到代码:src/llamafactory/train/tuner.py:234 export_model()。整个流程拆 5 步:

动作关键 YAML 字段
1加载 base + tokenizer + 可能的 LoRA / PiSSA adapter(走 model/loader.py:load_model,但 is_trainable=Falsemodel_name_or_path / adapter_name_or_path / template
2merge_and_unload() 把 LoRA 增量融回基座(PEFT 调用)—(自动)
3export_quantization_bit 设了,按 GPTQ / AWQ 校准export_quantization_bit / export_quantization_dataset / export_quantization_nsamples / export_quantization_maxlen
4save_pretrained() 写 safetensors + HF configexport_dir / export_size / export_legacy_format
5可选:生成 Ollama modelfileexport_hub_model_id 或单独 --export_ollama

关键约束:

12.10 一份完整的 "训→merge→量化→部署" 实战序列

# Step 1: LoRA SFT
llamafactory-cli train examples/train_lora/qwen3_lora_sft.yaml

# Step 2: merge LoRA → 完整 fp16 模型
llamafactory-cli export examples/merge_lora/qwen3_lora_sft.yaml
# 出: saves/qwen3-4b/full/merged/

# Step 3: GPTQ 4-bit 量化(用校准集)
llamafactory-cli export \
  model_name_or_path=saves/qwen3-4b/full/merged \
  template=qwen3_nothink \
  export_dir=saves/qwen3-4b/full/merged_gptq \
  export_quantization_bit=4 \
  export_quantization_dataset=data/c4_demo.jsonl \
  export_quantization_nsamples=128

# Step 4: 出 Ollama modelfile(不量化)
llamafactory-cli export \
  model_name_or_path=saves/qwen3-4b/full/merged \
  template=qwen3_nothink \
  export_dir=saves/qwen3-4b/full/merged_ollama \
  export_legacy_format=true

# Step 5: 起 vLLM 服务
python -m vllm.entrypoints.openai.api_server \
  --model saves/qwen3-4b/full/merged_gptq \
  --quantization gptq \
  --max-model-len 8192

这 5 步串完,从训练到 OpenAI 兼容 API 一份完整 pipeline

12.11 Ollama 导出格式细节

Ollama modelfile 不是单一文件,而是 .modelfile + 一份完整的 GGUF。LLaMA-Factory 的 export 子命令只能出 .modelfile + safetensors 模型目录——真正的 GGUF 转换要另外调 llama.cpp 的 convert_hf_to_gguf.py。完整 Ollama 流程:

  1. LLaMA-Factory export → 出 HF safetensors 模型目录 + Modelfile
  2. 用 llama.cpp 的 convert_hf_to_gguf.py 把模型转 GGUF(fp16);
  3. 用 llama.cpp 的 quantize 工具量化到 Q4_K_M / Q5_K_M 等;
  4. 修改 Modelfile 里 FROM 指向 GGUF;
  5. ollama create my-model -f Modelfile

Modelfile 里 LLaMA-Factory 自动写好的 TEMPLATE / PARAMETER stop / SYSTEM 几行来自 YAML 的 template 字段——template 写错的话 Modelfile 跟着错,Ollama 推理出来全乱码。

12.12 SGLang vs vLLM 部署选型(2025-03 之后)

vLLM 不再是唯一选择。同样 llamafactory-cli api,通过 infer_backend 切换:

infer_backend实际后端典型场景
huggingface 原生 transformers(默认) 调试 / 小流量
vllm vLLM AsyncEngine 常规生产
sglang SGLang Engine 多轮工具调用、结构化生成、长 KV 场景;部分模型比 vLLM 快 25-270%

SGLang 在结构化输出(强制 JSON / 正则)和 prefix cache 复用上明显比 vLLM 优秀,适合 agent / 长对话场景。如果是单轮 chat 流量,vLLM 仍是首选(社区更成熟)。