训练和推理必须用同一个 `template`,这是 LlamaFactory 最容易翻车的一条

2026-08-09

本文所有事实以 hiyouga/LlamaFactory 官方仓库 2026-08-09 的内容为准。我们没有安装、训练或部署过任何模型,文中数字与配置均为仓库文档与源码里写着的值。

LlamaFactory 的 README 在支持模型表下面挂了六条注解,其中一条把一个单词整个大写了,原文是:Remember to use the SAME template in training and inference。README 为什么把这个词写成大写,我们无从得知,也不打算替它解释;能确认的只是它就是这么写的,而且这条注解和其余五条一样,是一条硬规则。

这篇不讲 template 内部是怎么拼 prompt 的——那属于我们没读过的实现代码。这篇只回答三个可核查的问题:这个参数到底出现在哪几个文件里、三份官方示例是怎么对齐的、以及你怀疑自己踩了这条时该按什么顺序去比对。

先说清楚这条规则不承诺什么

README 给的是一条指令:训练和推理要用同一个 template。它没有写”不一致会表现成什么样”。

所以本文不会告诉你”选错了输出就会乱码""回答会变得很奇怪”这类描述——那需要我们真的跑过训练和推理,而我们一次都没跑过。你能从仓库里拿到的确定信息只有一条:官方要求这两侧取值一致,并且在自己的示例配置里严格做到了。后面这半句才是这篇文章真正有用的部分,因为示例配置里那几行是可以逐字比对的。

template 不是”一个参数”,它在三个文件里各出现一次

README 的 Quickstart 位置放的是一条完整闭环,对应三条命令:

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

三个文件在三个不同的目录下,template 在每一份里都出现了一次,取值全是 qwen3_nothink

训练那份 examples/train_lora/qwen3_lora_sft.yaml### 注释切成 model / method / dataset / output / train 五个块,template### dataset里,和数据集、截断长度放在一起:

### dataset
dataset: identity,alpaca_en_demo
template: qwen3_nothink
cutoff_len: 2048
max_samples: 1000

推理那份 examples/inference/qwen3_lora_sft.yaml 一共只有 5 行,template 是第 3 行:

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

合并导出那份 examples/merge_lora/qwen3_lora_sft.yaml 同样带着这一行,而且它的首行是一句全大写的禁令注释,原样抄在这里:

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

三份配置共享的不止 template:基座都是 Qwen/Qwen3-4B-Instruct-2507;训练配置里的 output_dir: saves/qwen3-4b/lora/sft,正是推理与合并两份里 adapter_name_or_path 的取值;合并产物落到 export_dir: saves/qwen3_sft_merged。这条”训练 → 推理 → 合并导出”的链路,是仓库里唯一被 README 抬到 Quickstart 位置的完整闭环,字段是严格对齐的。

结构上为什么容易漏

把上面三段并排看,有三处结构性的事实值得先记下来(下面第一句都是仓库里可核对的,后半句是我们的看法,不是官方说法):

第一,template 在训练配置里归在 ### dataset 块,不在 ### model 块,也不在 ### method 块。换模型时改的是 ### model 块里的 model_name_or_path,跟 template 隔着两个块。

第二,三份配置分属 examples/train_lora/examples/inference/examples/merge_lora/ 三个目录,中间隔着一次完整训练。改训练配置和写推理配置未必是同一天做的事。

第三,推理那份只有 5 行,其中一行就是 template。文件短到这个程度,反而容易被当成”随手填一下就能跑”的东西。

怀疑自己踩了这条时,按这个顺序比对

第一步,把三处取值抄到一起看。 不要凭印象,逐个打开 examples/train_lora/ 下你实际用的那份、examples/inference/ 下那份、examples/merge_lora/ 下那份(或者你从它们复制出去改的版本),只看 template: 那一行,把三个值写在同一张纸上。比对要求是字面完全相同,包括后缀。

第二步,回 README 的模型表查你这个模型那一行。 模型表里 Template 列的取值就是 template 参数该填的值。跟本文示例直接相关的是这两行:

ModelModel sizeTemplate
Qwen3 (MoE/Instruct/Thinking/Next)0.6B/1.7B/4B/8B/14B/32B/80B/235Bqwen3/qwen3_nothink
Qwen3-VL2B/4B/8B/30B/32B/235Bqwen3_vl

引这两行是因为官方示例用的基座就是 Qwen3-4B-Instruct,而 examples/train_lora/ 下同时存在 qwen3_lora_sft.yamlqwen3vl_lora_sft.yaml 两条线——多模态那条在表里是另一个独立的 template 名 qwen3_vl,不是加个开关。整张 53 行模型表怎么读,我们另有一篇专门讲,这里不铺开。

注意 Qwen3 那一行的 Template 列写的是两个值qwen3qwen3_nothink。README 的注解里说明了,若某个模型同时有推理版与非推理版,用 _nothink 后缀区分。也就是说,训练写 qwen3、推理写 qwen3_nothink 同样属于”两侧不一致”,哪怕你觉得它们只差一个后缀。_nothink 这个后缀在表里出现在哪三处、它到底在区分什么,我们另有一篇专门讲。

第三步,确认你的模型属于 base 还是 instruct/chat。 注解的第一条把这两类分开处理:对 base 模型,template 可以从 defaultalpacavicuna 之类里选;对 instruct/chat 模型,务必使用对应的 template。这条分叉另有专篇,这里只提醒它会影响第二步的查表结果。

第四步,如果你自定义过 template,注解第六条给了两个位置:完整模型清单在 src/llamafactory/extras/constants.py,自定义 chat template 加在 src/llamafactory/data/template.py。自己加的名字同样受”三处一致”这条约束。注解只交代了在哪两个文件里加,没有提到任何自动校验;至于代码里到底有没有校验,那是实现细节,我们没有读过,不做断言。

改完之后怎么验证

验证动作只有两条,都不需要跑训练:

一是三份配置里的 template 字面一致。二是 adapter_name_or_path 确实指向训练时的 output_dir——官方示例里这两个值都是 saves/qwen3-4b/lora/sft。这两条是”配置层面对齐”的全部内容,能不能得到你想要的结果是另一回事,本文不做承诺。

顺带说一个跟合并有关的边界:合并导出那份配置也带 template,但它首行那句大写注释管的是另一件事——合并 LoRA 适配器时不要使用量化模型或 quantization_bit。这两件事别混起来记。

什么情况说明问题不在这条

这是排查文里最容易被省掉、但价值最高的一步。以下几种情况,可以把”template 不一致”排除掉:

  • 三处字面已经完全一致。那这条就到此为止了,继续在这上面纠结是浪费时间。数据格式那一侧(dataset_info.json 的字段怎么填)我们另有一篇专门讲。
  • 你的模型在表里 Template 列写的是 -。表里有 4 个是这样:BLOOM/BLOOMZ、GPT-2、Llama(初代)、StarCoder 2。它们本来就没有”对应 template”,走的是注解第一条 base 模型那条路径。
  • 你的模型带 *** 标记。README 的注解写明:* 表示需要从 main 分支安装 transformers,并用 DISABLE_VERSION_CHECK=1 跳过版本检查;** 表示需要安装特定版本的 transformers。这两条是依赖版本问题,不是 template 问题,改 template 改不动它们。

Windows 和 Linux/macOS 的差别在哪一段

上面那三条 llamafactory-cli 命令本身两个平台写法一样,差别出在需要设环境变量的时候。比如 README 给的切换下载源那一步:

# Linux / macOS
export USE_MODELSCOPE_HUB=1
:: Windows
set USE_MODELSCOPE_HUB=1

这里要留一个心眼:切换 Hub 之后要改的是 model_name_or_path 那一行(换成对应 Hub 的 model ID),template 和它是两件事,别顺手一起改掉,也别因为模型 ID 的写法变了就以为 template 该跟着变。

另外提两处仓库内部的字符串差异,跟这条规则没有因果关系,但会影响你搜资料:一是仓库内新旧写法并存,src/llamafactory/launcher.py 的欢迎语里写的项目主页仍是带连字符的旧名 LLaMA-Factory,README 正文里两种写法也混用——翻 issue 时两种拼法都试一遍。二是上面三份 YAML 都带着 trust_remote_code: true 这一行,它在源码里的默认值与示例 YAML 的口径是两个不同的层,这个差异我们另有一篇专门讲,这里只陈述它存在。

最后一句

这条规则之所以值得单独写一篇,不是因为它复杂,而是因为它跨文件。跨文件的约束在任何工程里都是最容易腐化的一类:每一处单看都合理,合起来才不一致。官方示例的做法很朴素——三份配置共享同一组标识符,改一处就得同步另外两处。你从示例复制出去做自己的项目时,继承的是这份对齐责任,而不只是那几行 YAML。

至于 lora_rankcutoff_len 这些该设多少,官方没有给通用值,取决于你的数据和硬件,本文不给建议。


本文依据 LlamaFactory 官方仓库(github.com/hiyouga/LlamaFactory)的 README、data/README.mdexamples/ 下的配置与 src/llamafactory/hparams/ 的参数定义整理,核对日 2026-08-09。本文内容为仓库源码与文档口径,我们没有安装、训练或部署过任何模型,文中显存数字均为官方标注的估算值(README 原文标 * estimated)而非实测占用。参数与默认值随版本变动,请以 llamafactory-cli train -h 的实际输出为准。安全相关做法请结合自身环境评估,本文不构成安全方案建议。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。