LLaMA Factory微调中的模版在vLLM或LMDeploy框架部署中对齐

主要解决的问题:训练推理不一致根源与多框架对齐实操方案

很多开发者都会遇到一个典型痛点:在 LlamaFactory 完成 LoRA 微调后,在网页上内对话效果完全符合预期;但把合并后的模型迁移至 vLLM、LMDeploy、Ollama、OpenWebUI 等框架部署时,模型输出风格、回答逻辑、停止时机全部跑偏,甚至出现无限生成、角色认知丢失、问答答非所问。 绝大多数人会怀疑权重导出、量化流程出错,而真正的核心诱因是对话模板不统一。本文完整拆解对话模板底层逻辑、各框架模板差异,给出标准化导出、对齐、自定义落地全流程,彻底解决微调与部署效果割裂问题。

LLaMA Factory在微调训练需要选择模型名称,自动带出对话模版,比如qwen。这个对话模版是LLaMA Factory项目根据qwen官方提供的对话模版改编,与大模型自身的对话模版并不相等

LLaMA Factory的对话模版的源码在LLaMA-Factory/src/llamafactory/data/template.py这个类里。获取对话模版的方法(私有方法)_get_jinja_template ,可以用公共方法fix_jinja_template来调用该私有方法。

大模型的默认对话模版在 tokenizer_config.json里chat_template字段。

可以看到LLaMA Factory微调训练时的对话模版与大模型的默认对话模版有时并不相同。因为大模型更新后 LLaMA Factory才会更新这个文件,有滞后性

一、对话模板基础概念与核心作用

1.1 什么是对话模板

对话模板(Chat Template/Prompt Template)是一套标准化文本拼接规则,通过固定标记区分system系统指令、user用户提问、assistant模型回复三类角色,将多轮对话消息列表,拼接成模型可识别的完整输入文本。 大模型在 SFT 监督微调阶段,数据集会严格按照固定模板格式化;推理阶段如果拼接规则与训练时不一致,模型无法识别角色边界,输出会完全偏离训练预期。

1.2 通用 ChatML 标准示例

ChatML 是行业通用消息结构,以 JSON 数组承载多轮对话:

复制代码
[
  {"role": "system", "content": "你是专业领域AI助手,回答简洁精准"},
  {"role": "user", "content": "介绍Qwen2.5模型"},
  {"role": "assistant", "content": "Qwen2.5是阿里开源轻量化大模型"},
  {"role": "user", "content": "支持微调吗?"}
]

经过模板渲染后,会转换为带专属起止标记的连续文本,以 Qwen 系列为例渲染结果:

复制代码
<|im_start|>system
你是专业领域AI助手,回答简洁精准<|im_end|>
<|im_start|>user
介绍Qwen2.5模型<|im_end|>
<|im_start|>assistant
Qwen2.5是阿里开源轻量化大模型<|im_end|>
<|im_start|>user
支持微调吗?<|im_end|>
<|im_start|>assistant

末尾<|im_start|>assistant是生成提示符,告诉模型从此处开始输出回答。

1.3 三类核心角色定义

  1. system:全局系统提示,定义模型人设、能力约束,仅出现在对话最开头;
  2. user:用户输入提问,多轮对话可重复出现;
  3. assistant:模型历史回答,训练阶段作为标签参与损失计算,推理阶段作为上下文。

1.4 模板底层存储形式

主流模型、框架统一采用Jinja2 模板字符串 存储拼接规则,存放在tokenizer_config.jsonchat_template字段,分词器apply_chat_template方法会自动执行渲染拼接。

二、训练与推理(部署后的模型)效果不一致:根源 ---多框架对话模板割裂

我们使用LlamaFactory微调模型之后,在它的chat界面做对话测试的时候,它的答复是没有问题的,然后用微调后的模型合并后去做部署,结果发现:在LlamaFactory里面测试它的答复是没有问题的,但是把它单独使用vllm或 lmdeploy推理框架部署后,它的回答就不一样了,这其实是对话模板导致的

不同的框架用的话模板是不一样的,这种对话模板的差异性就导致了模型的答复不一致。

2.1 四大环节模板来源完全独立

一套完整微调部署链路,会涉及 4 套完全独立的对话模板体系,任意两者不匹配都会造成输出异常:

  1. 基座原生模板 :模型出厂内置,存放于tokenizer_config.json
  2. LlamaFactory 微调模板:框架内置独立模板库,训练格式化数据完全依靠该规则,会覆盖原生模板逻辑;
  3. 推理引擎模板:vLLM/LMDeploy/Ollama 默认读取模型原生模板,不会自动识别 LlamaFactory 训练规则;
  4. 前端界面模板:OpenWebUI 等前端自带消息拼接逻辑,会覆盖后端推理引擎配置。

2.2 分模块模板机制详解

2.2.1 基座模型原生模板

以 Qwen2.5-3B 为例,原生 Jinja 模板内置在模型tokenizer_config.json,自带工具调用、多轮对话、起止标记逻辑。但经过 LlamaFactory 微调后,训练数据是按框架模板格式化,而非原生模板,直接用原生模板推理会产生格式错位。

2.2.2 LlamaFactory 内置模板

LlamaFactory 在src/llamafactory/data/template.py中注册全系列模型专属模板(qwen、llama3、chatglm 等),训练、WebUI 对话全部使用这套规则。 以 Qwen 模板注册代码片段:

复制代码
register_template(
    name="qwen",
    format_system=StringFormatter(slots=["<|im_start|>system\n{{content}}<|im_end|>\n"]),
    format_user=StringFormatter(slots=["<|im_start|>user\n{{content}}<|im_end|>\n<|im_start|>assistant\n"]),
    format_assistant=StringFormatter(slots=["{{content}}<|im_end|>\n"]),
    stop_words=["<|im_end|>"],
    default_system="You are a helpful assistant."
)

训练时所有数据集都会按照上述规则拼接;如果部署时不用完全相同 Jinja 规则,模型无法识别角色分隔符。

2.2.3 vLLM 推理引擎模板

vLLM 为了使语言模型支持聊天协议,vLLM 要求模型在其 tokenizer 配置中包含一个聊天模板。聊天模板是一个 Jinja2 模板,它指定了角色、消息和其他特定于聊天对 tokens 如何在输入中编码。默认读取模型目录tokenizer_config.json内的chat_template,若无合法 Jinja 模板会直接报错。支持手动通过--chat-template参数指定外部.jinja模板文件,必须使用 LlamaFactory 导出的模板,不能沿用基座原生模板 。也就是说vllm默认使用大模型自带的对话模版,若要使用自动以的对话模版,需要添加--chat-template参数。

LlamaFactory 用的是自定义的对话模板,如果模型微调合并后使用推理框架 vllm 部署后,由于vllm推理框架常规情况下用的是模型自带的对话模版,这就会导模型效果不一致。、

2.2.4 LMDeploy 推理引擎模板

LMDeploy 不直接支持 Jinja 文件,采用结构化 JSON 模板配置,拆分 system/user/assistant 起止标记、停止词等字段,可自定义载入外部模板 JSON 文件。

2.2.5 OpenWebUI 前端模板

OpenWebUI 内置独立消息拼接逻辑,会绕过后端推理引擎的模板配置,强制使用前端自带规则,这也是很多用户后端配置正确、前端测试依旧效果错乱的核心原因,该框架暂不支持自定义导入外部模板。

2.3 核心铁律

模型训练时使用哪一套对话模板,全链路推理、前端交互都必须统一使用同一套模板,任何环节混用原生 / 框架模板都会造成问答效果断层。各阶段使用的对话模版如下:

由于微调框架修改了大模型,故后续都要以微调框架的对话模版为主

三、标准流程:导出 LlamaFactory 训练用 Jinja 模板

想要实现多框架对齐,第一步是从 LlamaFactory 提取训练时完整 Jinja 模板字符串,保存为独立.jinja文件供推理引擎加载。

3.1 导出完整代码(mytest.py

复制代码
import sys
import os
# 导入LlamaFactory项目根目录
root_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(root_dir)
from llamafactory.data.template import TEMPLATES
from transformers import AutoTokenizer

# 1. 加载任意同系列分词器(基座/合并模型均可)
tokenizer = AutoTokenizer.from_pretrained("/mnt/llm/qwen2.5-3b")
# 2. 指定训练使用的模板名(qwen/llama3等)
template_name = "qwen"
template = TEMPLATES[template_name]
# 3. 转换为标准Jinja模板
template.fix_jinja_template(tokenizer)
# 4. 打印并保存模板
jinja_content = tokenizer.chat_template
print("===== 导出Jinja对话模板 =====")
print(jinja_content)
# 写入文件,后续vLLM直接调用
with open("train_chat_template.jinja", "w", encoding="utf-8") as f:
    f.write(jinja_content)

3.2 执行导出

复制代码
python mytest.py

执行完成后,目录生成train_chat_template.jinja,该文件就是训练阶段完整拼接规则,所有推理框架统一加载此文件即可对齐效果。

四、各推理框架模板对齐实操

4.1 vLLM 加载自定义 Jinja 模板

启动命令增加--chat-template参数指定导出文件:

复制代码
vllm serve /mnt/llm/qwen2.5-3b-qlora4bit \
--chat-template ./train_chat_template.jinja \
--port 8000

进阶方案:直接修改合并模型tokenizer_config.jsonchat_template字段,替换为导出的 Jinja 全文,后续启动 vLLM 无需额外传参,永久对齐模板。

4.2 LMDeploy 自定义模板配置

LMDeploy 不支持 Jinja,需将模板转换为结构化 JSON 配置,示例template.json

复制代码
{
	"model_name": "qwen-finetune",
	"system": "<|im_start|>system\n",
	"meta_instruction": "你是小聚,由Aron开发的AI助手",
	"eosys": "<|im_end|>\n",
	"user": "<|im_start|>user\n",
	"eoh": "<|im_end|>\n",
	"assistant": "<|im_start|>assistant\n",
	"eoa": "<|im_end|>",
	"separator": "\n",
	"capability": "chat",
	"stop_words": ["<|im_end|>"]
}

启动 API 服务指定模板:

复制代码
lmdeploy serve api_server /mnt/llm/qwen2.5-3b-qlora4bit \
--chat-template ./template.json --server-port 8888

4.3 Ollama 模板适配

Ollama 依靠 Modelfile 配置对话系统提示与停止标记,在 Modelfile 中补充训练对应的停止符,匹配模板终止规则:

Modelfile

复制代码
FROM ./qwen3b-q4_K_M.gguf
SYSTEM "你是小聚,由Aron开发的AI助手"
PARAMETER stop "<|im_end|>"
PARAMETER num_ctx 8192

构建模型后运行,停止规则与训练模板保持一致,不会无限生成。

4.4 OpenWebUI 避坑方案

OpenWebUI 无法自定义导入外部 Jinja 模板,两种解决思路:

  1. 优先后端单独调用 API 测试,规避前端模板覆盖;
  2. 替换 OpenWebUI 内置模板源码,修改消息拼接逻辑为 LlamaFactory 导出规则(改动成本高,不推荐生产环境)。

五、自定义对话模板通用方法

5.1 自定义 Jinja 模板(vLLM/llama.cpp 适用)

直接修改导出的.jinja文件,调整 system 默认人设、起止标记、工具调用逻辑,保存后重启推理服务即可生效,无需重新导出模型权重。

5.2 自定义 JSON 模板(LMDeploy 适用)

修改 template.json 内meta_instruction全局人设、stop_words停止标记,适配垂直领域微调需求,如客服、法律、医疗专用模型。

六、落地标准化流程(企业级最佳实践)

  1. 微调阶段:记录 LlamaFactory 使用的模板名称(如 qwen);
  2. 导出权重 :合并 LoRA 至完整模型,运行导出脚本生成.jinja模板文件;
  3. 推理部署
    • vLLM:启动参数挂载 jinja 模板 / 直接写入 tokenizer_config.json;
    • LMDeploy:转换为 JSON 模板文件并指定加载;
    • Ollama:Modelfile 配置对应 stop 停止符;
  4. 效果校验:同一组测试问答,分别在 LlamaFactory WebUI、推理 API 调用,输出完全一致即模板对齐成功;
  5. 交付归档 :模型包配套存放.jinja模板文件,后续二次部署直接复用,避免模板丢失导致效果错乱。

七、常见问题排查

  1. 模型无限生成,不会停止 模板缺少训练对应的停止标记stop_words,在启动参数 / Modelfile 补充<|im_end|>等 EOS 符。
  2. 人设完全失效,不识别微调角色 推理使用了基座原生模板,未加载 LlamaFactory 导出的训练 Jinja 模板。
  3. 多轮对话上下文丢失 Jinja 模板循环遍历 messages 逻辑缺失,重新导出完整模板文件。
  4. OpenWebUI 和后端 API 回答不一样 前端自带模板覆盖后端配置,优先使用 curl 直接调用后端 API 验证。

结语

对话模板只是一套文本拼接规则,不会改变模型底层权重与推理能力,但直接决定模型能否读懂训练时的对话格式。绝大多数微调部署翻车问题,根源都在于忽略模板对齐。 遵循「训练模板统一导出、全推理框架同步挂载」的标准流程,就能彻底解决 LlamaFactory 微调后跨框架输出不一致的行业常见痛点,保障从训练、量化、API 部署到前端交互全链路效果统一。

相关推荐
晓子文集7 小时前
Tushare接口文档:现金流量表(cashflow)
大数据·数据库·大模型·金融数据·量化投资·tushare
牧子川8 小时前
何时拒绝使用工具:Agent 不是万能钥匙
人工智能·大模型·agent·tools·functioncalling
菩提小狗18 小时前
AI每日资讯|AI落地|最新情报|skill精选|2026年07月21日(11案例+10爆款Skill)
大模型·agent·skill·ai资讯·ai落地
@Mr_LiuYang1 天前
从聊天框到空间智能:GIS接入大模型的5种架构模式
大模型·空间智能·geoai·架构方案·时空大模型·gis智能体
星核0penstarry1 天前
Coding Plan vs 运营商Token Plan:先选对赛道,再谈性价比
大模型·api
audyxiao0011 天前
人工智能顶会AAAI 2026论文分享|SlideBot:用于生成信息丰富、可靠、多模态幻灯片的多智能体框架
人工智能·大模型·aaai·智能体·幻灯片
时空无限1 天前
vllm 大模型启动缓存相关环境变量 export
linux·缓存·vllm
做个文艺程序员1 天前
Linux第27篇:在Linux服务器部署本地大模型:Ollama+开源LLM实战
linux·服务器·开源·大模型·ollama