训练、推理、合并三条命令:README 唯一抬进 Quickstart 的闭环
本文所有事实以
hiyouga/LlamaFactory官方仓库 2026-08-09 的内容为准。我们没有安装、训练或部署过任何模型,文中出现的字段、默认值与命令原文均照抄仓库文件。
LlamaFactory 的 examples/ 目录下光是 train_lora/ 就有 12 个文件,extras/ 还铺了 18 个子目录。第一次点进去很容易迷路。但 README 的 Quickstart 一节其实只抬了三条命令上来,用它们分别完成 Qwen3-4B-Instruct 的 LoRA 微调、推理和合并:
llamafactory-cli train examples/train_lora/qwen3_lora_sft.yaml
llamafactory-cli chat examples/inference/qwen3_lora_sft.yaml
llamafactory-cli export examples/merge_lora/qwen3_lora_sft.yaml
值得注意的不是这三条命令本身,而是它们指向的三份 YAML 里的字段是严格对齐的。这个对齐关系是我们把三份文件逐行摆在一起读出来的,也是整个仓库里唯一一条被文档提到 Quickstart 位置的完整闭环。看懂这条链,比背下一百个参数名管用。
先定位这三个子命令在哪一层
src/llamafactory/launcher.py 里有一段 USAGE 常量,把 llamafactory-cli 的子命令逐行列了出来。Quickstart 用到的是其中三个,USAGE 里对它们的说明分别是 train models、launch a chat interface in CLI、merge LoRA adapters and export model。这三行就是这篇要讲的全部——USAGE 里其余几个子命令各自干什么,我们另有一篇按表讲,这里不铺开。
同一段里还有一条与这三条命令直接相关的信息:USAGE 的 Hint 行原文写着 “You can use lmf as a shortcut for llamafactory-cli.”,也就是说 lmf 是官方短别名,上面三条命令开头的 llamafactory-cli 都可以换成 lmf。这个别名同样另有一篇专门讲,你在这篇里只要知道换写法不影响后面的对齐关系就够了。
第一步 train:五个块加一个被注释掉的块
examples/train_lora/qwen3_lora_sft.yaml 用 ### 注释把自己切成了五块:model、method、dataset、output、train,末尾还有第六块 ### eval,但整块都被注释掉了。
这一点比它里面的任何一个数值都重要:这份被 README 抬到 Quickstart 的示例,默认不做验证集评估。判定动作很简单,打开文件看最后一块——eval_dataset、val_size、eval_strategy、eval_steps 这几行前面都带着 #,也就是没有任何一个验证相关字段是生效的。要不要把它们放开,取决于你的数据规模和目的,官方没有在这里给通用值。
其余几块里,与这条链直接相关的是这几行:
model_name_or_path: Qwen/Qwen3-4B-Instruct-2507
finetuning_type: lora
lora_rank: 8
lora_target: all
template: qwen3_nothink
output_dir: saves/qwen3-4b/lora/sft
lora_rank: 8 和 lora_target: all 与 finetuning_args.py 里读到的源码默认值(8 与 "all")是同一组取值,示例把它们显式写出来,等于顺手告诉你这两个旋钮在哪。真正决定后两步能不能接上的,是 output_dir 和 template 这两行。
另外一个提醒:这份配置里有 max_samples: 1000,它是一份演示用配置,只取 1000 条样本。别把它当成”官方推荐的训练规模”。
第二步 chat:只有五行,但两行是接口
examples/inference/qwen3_lora_sft.yaml 全文只有五行:
model_name_or_path: Qwen/Qwen3-4B-Instruct-2507
adapter_name_or_path: saves/qwen3-4b/lora/sft
template: qwen3_nothink
infer_backend: huggingface # choices: [huggingface, vllm, sglang, ktransformers]
trust_remote_code: true
把它跟上一份对照着看,链条就露出来了:adapter_name_or_path 填的正是训练配置里的 output_dir;model_name_or_path 是同一个基座;template 与训练时完全一致。
LoRA 这条路上,推理侧要同时拿到”基座 + 适配器”两样东西,所以前两行缺一不可。template 两侧必须一致这件事,展开讲能单独写一篇,我们另有一篇专门讲 template 体系;这里只需要记住一条可核查的判定动作:改了训练配置里的 template,就回头把推理和合并这两份配置里的同名字段一起改,三处对不上是最容易自己给自己挖的坑。
infer_backend 的四个可选值写在注释里:huggingface、vllm、sglang、ktransformers。示例给的是 huggingface,而 model_args.py 里 infer_backend 的源码默认值写作 EngineName.HF,两处指的是同一个后端。
第三步 export:首行那句全大写的禁令
examples/merge_lora/qwen3_lora_sft.yaml 的第一行不是配置,是一句注释:
### Note: DO NOT use quantized model or quantization_bit when merging lora adapters
原文就是这么写的:合并 LoRA 适配器时不要使用量化模型或 quantization_bit。这是一条明确禁令,不是”建议不要”,照抄给你,不加解释也不替它找理由。
正文部分前四行与推理配置一模一样(同基座、同适配器路径、同 template、同 trust_remote_code),新增的是导出块:
export_dir: saves/qwen3_sft_merged
export_size: 5
export_device: cpu # choices: [cpu, auto]
export_legacy_format: false
export_size: 5、export_device: "cpu"、export_legacy_format: False 都与 model_args.py 里的源码默认值对得上;export_device 的两个取值 [cpu, auto] 写在行内注释里。合并产物落到 saves/qwen3_sft_merged,与训练产物 saves/qwen3-4b/lora/sft 是两个目录,不会互相覆盖。
把三份配置的对齐关系摆成一张表
| 字段 | train | chat | export |
|---|---|---|---|
model_name_or_path | Qwen/Qwen3-4B-Instruct-2507 | 同左 | 同左 |
template | qwen3_nothink | 同左 | 同左 |
output_dir | saves/qwen3-4b/lora/sft | —— | —— |
adapter_name_or_path | —— | saves/qwen3-4b/lora/sft | saves/qwen3-4b/lora/sft |
export_dir | —— | —— | saves/qwen3_sft_merged |
这张表只放了与这条闭环直接相关的五行。仓库里那些更大的表——模型支持表、examples/README.md 的全量配方清单、hparams/ 下几十个参数的默认值——各有专门篇目在讲,这里不搬。
读这张表的方法是:竖着看是三条命令,横着看是同一份实验的三个阶段。第二列到第三列之间没有新增任何”新知识”,只是把适配器从”运行时加载”变成”写进权重文件”。
两处口径不一致,说到这儿就停
第一处是 trust_remote_code。 源码里 model_args.py 的默认值是 False,而 Quickstart 这三份示例 YAML 里全都显式写了 trust_remote_code: true。两处口径不一致,以你实际使用的那一份配置为准。这个字段涉及是否信任并执行模型仓库自带的远程代码,具体怎么取值请结合你自己的环境和来源判断,我们不给结论。
第二处是仓库名。 launcher.py 的 launch() 里构造了一个 WELCOME 横幅字符串,格式化后包含 | Welcome to LLaMA Factory, version {VERSION} 与 | Project page: https://github.com/hiyouga/LLaMA-Factory |——项目主页写的是带连字符的旧名,而仓库当前的真实路径是 hiyouga/LlamaFactory。README 正文里两种写法也是混用的。新旧写法在仓库里并存,如实说到这儿就够了,改名时间、原因、有没有重定向我们都没有核实。落到操作上就一句:搜 issue、搜资料时两种拼法都试一遍。
Windows 侧要单独说的两件事
一是切换下载源的写法。 README 设定的场景是 Hugging Face 下载有问题时切到 ModelScope Hub,环境变量的写法两个平台不一样:
# Linux / macOS
export USE_MODELSCOPE_HUB=1
:: Windows
set USE_MODELSCOPE_HUB=1
设完再把配置里的 model_name_or_path 换成对应 Hub 的 model ID。这一步在三条命令之前做,因为 train / chat / export 三步都要解析同一个基座标识。
二是 freeze_support()。 src/llamafactory/cli.py 的 if __name__ == "__main__": 分支里调了 from multiprocessing import freeze_support 并执行它——按 multiprocessing 的用法,这是把程序打包成可执行文件时 Windows 需要的那一步。它只写在 __main__ 分支里,所以它解释的是这个入口文件为什么比你想象的多几行,而不是你敲命令时会看到什么。
同一个 cli.py 里还有一个 USE_V1 环境变量,决定加载 llamafactory.v1.launcher 还是 llamafactory.launcher——仓库里同时存在旧实现和一套 v1/ 重写。这条岔路我们另有一篇专门讲,走 Quickstart 时不需要碰它。
走完这三步之后,最近的两条岔路
一条是命令行覆盖 YAML。 README 在讲 API 部署时给了这样一条原文:
API_PORT=8000 llamafactory-cli api examples/inference/qwen3.yaml infer_backend=vllm vllm_enforce_eager=true
这里有两个可写的事实:端口是通过 API_PORT 环境变量传的,不是命令行参数;infer_backend=vllm 这种 key=value 追加写法说明 YAML 里的字段可以在命令行被覆盖。对应到 Quickstart,你想临时换个推理后端试试,不必去改那份五行的 YAML。注意行首那种 VAR=value command 的写法是 POSIX shell 的语法,Windows 的 cmd / PowerShell 没有它,需要按各自 shell 的方式先设好变量再执行——这是 shell 层面的差异,不是 LlamaFactory 的功能。
另一条是多卡。 launcher.py 里触发分布式训练的条件很明确:命令是 train,并且要么 FORCE_TORCHRUN 被启用,要么检测到的设备数大于 1 且没在用 ray、没在用 kt。也就是说,你在一台多卡机器上原样敲第一条命令,它会自己走分布式路径,而不是报错让你换命令。这组环境变量的默认值(NNODES、MASTER_ADDR、MASTER_PORT 等)我们另有一篇按表列出来,这篇不展开,也不给”几张卡该设多少”的建议——那属于调参,我们没有实测依据。
最后一句
这三条命令的价值不在于它们能训出什么,而在于它们给了你一条可对照的基准链:三份配置字段对齐、路径首尾相接、每一步的产物都是下一步的输入。你后面无论换模型、换方法还是换后端,都可以拿这条链当模板去比对——哪一处对不上,问题多半就在那里。
以上命令与配置均为仓库文件原文照抄,未逐项实测,以官方文档与 llamafactory-cli train -h 的实际输出为准。
本文依据 LlamaFactory 官方仓库(github.com/hiyouga/LlamaFactory)的 README、data/README.md、examples/ 下的配置与 src/llamafactory/hparams/ 的参数定义整理,核对日 2026-08-09。本文内容为仓库源码与文档口径,我们没有安装、训练或部署过任何模型,文中显存数字均为官方标注的估算值(README 原文标 * estimated)而非实测占用。参数与默认值随版本变动,请以 llamafactory-cli train -h 的实际输出为准。安全相关做法请结合自身环境评估,本文不构成安全方案建议。