【机器学习深度学习】LLamaFactory微调效果与vllm部署效果不一致如何解决

目录

前言

一、问题本质

1.1 问题说明

1.2 问题本质示意

二、常见原因

LLaMAFactory对话模板规则定义

模型对话模板定义规则 

三、解决方法

 提取代码myset.py

创建jinja文件

安装VLLM

运行VLLM

安装运行open webui流程

四、流程梳理


前言

本文主要讲述的主要内容是关于在LLaMAFactory中微调后加载的模型测试效果和加载到其他推理框架(VLLM,LMDeploy)的测试效果不一致是什么原因导致的?又该如何解决?

主要原因是对话模板不一致所导致的


一、问题本质

1.1 问题说明

LLaMA-Factory 使用内置对话模板(chat_template)来格式化训练/推理数据,而 vLLMLMDeploy 等推理框架则可能使用自己的模板体系或根本不管模板
这就是导致微调效果与部署效果不一致的核心原因之一。

LLaMA-Factory 的微调过程使用的是 HuggingFace Transformers 格式,而 vLLM 在推理时,依赖精确的:

  • tokenizer 配置

  • 模型 config

  • 权重格式(尤其是 LoRA 或 QLoRA)

  • prompt 模板

如果这些配置在部署时和训练时不一致,模型生成效果就会发生偏差。


1.2 问题本质示意

在 LLaMA-Factory 中使用的训练模板(例如 chatml):

<|im_start|>system
你是一个智能助手<|im_end|>
<|im_start|>user
你好<|im_end|>
<|im_start|>assistant

 而 vLLM 默认可能认为只需要:

用户:你好
助手:

 或者根本不加模板,直接拼接文本。这会让模型生成完全跑偏。


二、常见原因

2.1 原因汇总

问题类别具体原因解决方案
Tokenizer 不一致tokenizer_config.jsonspecial_tokens_map.json 中信息缺失或被修改✅ 确保 tokenizer 跟随微调模型一起保存并部署到 vLLM
Prompt 模板不一致如使用 chatmlalpacabaichuan 模板不同会导致上下文格式变化✅ 明确使用的 prompt 格式,在 vLLM 推理端加上相同格式的 系统提示 + 用户输入 + assistant 结构
LoRA 权重未合并微调后未合并 LoRA 层,推理端加载的是 base 模型✅ 使用 merge_and_save 合并权重,再加载
Quantization 不一致训练中使用了 QLoRA 等量化策略,而部署端未支持或解码异常✅ 部署前使用 LLaMA-Factoryexport_model.py 导出标准 FP16 或 INT4 GGUF 权重
vLLM 加载错误配置vLLM 读取模型参数时未正确加载 config.jsongeneration_config.json✅ 检查是否带上 --tokenizer--trust-remote-code 等参数


2.2 LLaMAFactory对话模板规则定义

对话模板路径:LLaMA-Factory/src/llamafactory/data/template.py

在LLaMAFactory文件夹中有个template文件(LLaMA-Factory/src/llamafactory/data/template.py)定义了各个模型的对话模板规则,template.py中定义了大部分主流,通用的模型对话规则。

如下图展示的是qwen的几个对话模板

单独拿出一个对话示例模板,也就是【1.2】所展示的LLaMAFactory对话模板格式示例:

# copied from chatml template
register_template(name="qwen",format_user=StringFormatter(slots=["<|im_start|>user\n{{content}}<|im_end|>\n<|im_start|>assistant\n"]),format_assistant=StringFormatter(slots=["{{content}}<|im_end|>\n"]),format_system=StringFormatter(slots=["<|im_start|>system\n{{content}}<|im_end|>\n"]),format_function=FunctionFormatter(slots=["{{content}}<|im_end|>\n"], tool_format="qwen"),format_observation=StringFormatter(slots=["<|im_start|>user\n<tool_response>\n{{content}}\n</tool_response><|im_end|>\n<|im_start|>assistant\n"]),format_tools=ToolFormatter(tool_format="qwen"),default_system="You are Qwen, created by Alibaba Cloud. You are a helpful assistant.",stop_words=["<|im_end|>"],replace_eos=True,
)

2.3 模型对话模板定义规则 

模型对话模板路径:模型名称/tokenizer_config.json

如果LLaMAFactory的内置对话模板中定义了相同的对话模板规则,回复效果自然也就没有差异,但在大多数情况下,对话模板的规则一致的条件是很难满足的。


三、解决方法

把在LLaMAFactory微调时的那套对话模板规则模板导出。使用微调时的对话规则,再部署到其它推理框架上就能够保证模型的输出效果一致了。 

3.1  提取代码myset.py

# mytest.py
import sys
import os# 将项目根目录添加到 Python 路径
root_dir = os.path.dirname(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/workspace/model/qwen/Qwen2.5-7B-Instruct")# 2. 获取模板对象
template_name = "qwen"  # 替换为你需要查看的模板名称
template = TEMPLATES[template_name]# 3. 修复分词器的 Jinja 模板
template.fix_jinja_template(tokenizer)# 4. 直接输出模板的 Jinja 格式
print("=" * 40)
print(f"Template [{template_name}] 的 Jinja 格式:")
print("=" * 40)
print(tokenizer.chat_template)

【替换片段】

# 1. 初始化分词器(任意支持的分词器均可)
tokenizer = AutoTokenizer.from_pretrained("/mnt/workspace/model/qwen/Qwen2.5-7B-Instruct")

/mnt/workspace/model/qwen/Qwen2.5-7B-Instruct:模型路径,里面必须包含分词器tokenizers.json,下载的模型文件会自带这个文件;

template_name = "qwen"  # 替换为你需要查看的模板名称

qwen:在LLaMA-Factory/src/llamafactory/data/template.py中的内置对话模板规则,根据需求选择;

#


 【使用说明】

1、放置位置:LLaMA-Factory/src/llamafactory/data/mytest.py


2、创建虚拟环境配置

#创建虚拟环境llamafactory
conda create -n llamafactory python=3.11#激活虚拟环境
conda activate llamafactory

3、安装依赖

在虚拟环境内安装依赖

# 基础依赖
pip install transformers# 必须安装的依赖(LLamaFactory 相关)
pip install jinja2
pip install torch  # PyTorch 基础库# 安装 LLamaFactory 及其依赖(推荐从源码安装)
git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e .  # 可编辑模式安装# 可选但推荐的依赖(用于完整功能)
pip install datasets accelerate sentencepiece

4、运行提取程序mytest.py

python /mnt/workspace/LLaMA-Factory/src/llamafactory/data/mytest.py

/mnt/workspace/LLaMA-Factory/src/llamafactory/data/mytest.py:表示myset.py路径


5、运行结果

========================================
Template [qwen] 的 Jinja 格式:
========================================
{%- if tools %}{{- '<|im_start|>system\n' }}{%- if messages[0]['role'] == 'system' %}{{- messages[0]['content'] }}{%- else %}{{- 'You are Qwen, created by Alibaba Cloud. You are a helpful assistant.' }}{%- endif %}{{- "\n\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}{%- for tool in tools %}{{- "\n" }}{{- tool | tojson }}{%- endfor %}{{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }}
{%- else %}{%- if messages[0]['role'] == 'system' %}{{- '<|im_start|>system\n' + messages[0]['content'] + '<|im_end|>\n' }}{%- else %}{{- '<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\n' }}{%- endif %}
{%- endif %}
{%- for message in messages %}{%- if (message.role == "user") or (message.role == "system" and not loop.first) or (message.role == "assistant" and not message.tool_calls) %}{{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}{%- elif message.role == "assistant" %}{{- '<|im_start|>' + message.role }}{%- if message.content %}{{- '\n' + message.content }}{%- endif %}{%- for tool_call in message.tool_calls %}{%- if tool_call.function is defined %}{%- set tool_call = tool_call.function %}{%- endif %}{{- '\n<tool_call>\n{"name": "' }}{{- tool_call.name }}{{- '", "arguments": ' }}{{- tool_call.arguments | tojson }}{{- '}\n</tool_call>' }}{%- endfor %}{{- '<|im_end|>\n' }}{%- elif message.role == "tool" %}{%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != "tool") %}{{- '<|im_start|>user' }}{%- endif %}{{- '\n<tool_response>\n' }}{{- message.content }}{{- '\n</tool_response>' }}{%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}{{- '<|im_end|>\n' }}{%- endif %}{%- endif %}
{%- endfor %}
{%- if add_generation_prompt %}{{- '<|im_start|>assistant\n' }}
{%- endif %}


3.2 创建jinja文件

创建一个jinja文件,将执行结果复制进去


3.3 安装VLLM

参考文章:【VLLM】大模型本地化部署_vllm部署大模型-CSDN博客

直接看这篇文章的【三、部署VLLM】即可


3.4 运行VLLM

vllm serve <model> --chat-template ./path-to-chat-template.jinja

<model>:表示训练模型路径;

./path-to-chat-template.jinja:表示jinja文件的路径;

示例

vllm serve /mnt/workspace/model/qwen_7b --chat-template /mnt/workspace/model/jinja2/qwen.jinja


3.5 安装运行open webui流程

#创建一个open-webui的conda环境
conda activate open-webui
# 安装open-webui
pip install -U open-webui torch transformers# 切换到新建的环境
conda activate open-webui
#配置
export HF_ENDPOINT=https://hf-mirror.com
#因为open-webui默认为ollama框架,所以使用vllm框架启动大模型的话需要将这里改为false
export ENABLE_OLLAMA_API=false
#调用大模型的地址,vllm的默认启动端口为8000
export OPENAI_API_BASE_URL=http://127.0.0.1:8000/v1#启动openwebui
open-webui serve

四、流程梳理

具体部署流程可看:【VLLM】open-webui部署模型全流程-CSDN博客

1、下载模型到本地(可选):根据业务场景选择合适的模型即可;

3、安装vllm:用虚拟环境隔离安装,安装教程:【VLLM】大模型本地化部署_vllm部署大模型-CSDN博客;

4、安装open-webui:用虚拟环境隔离安装;

5、运行vllm和open-webui

方法1:vllm环境中启动下载的本地模型

vllm serve <模型存放路径>

方法2:vllm环境中启动微调后导出的本地模型

vllm serve /mnt/workspace/model/qwen_7b --chat-template /mnt/workspace/model/jinja2/qwen.jinja

/mnt/workspace/model/qwen_7b:表示微调后导出的模型的存放路径;

/mnt/workspace/model/jinja2/qwen.jinja:LLaMAFactory中提取的内置对话模板规则路径

加上LLaMAFactory导出的内置对话模板规则,随后开启open-webui服务,在vllm框架下,模型的回复效果就和在LLaMAFactory上测试的效果是一样的啦;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/93100.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/93100.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python入门构建网页

用纯 Python 构建 Web 应用 本教程将带你从零开始&#xff0c;构建一个交互式的待办事项清单。 fasthtml 的核心哲学是“回归初心&#xff0c;大道至简”。在当今复杂的前后端分离技术栈中 &#xff0c;它提供了一条返璞归真的路径&#xff0c;旨在让你能用纯粹的 Python 构建从…

开源 Arkts 鸿蒙应用 开发(九)通讯--tcp客户端

文章的目的为了记录使用Arkts 进行Harmony app 开发学习的经历。本职为嵌入式软件开发&#xff0c;公司安排开发app&#xff0c;临时学习&#xff0c;完成app的开发。开发流程和要点有些记忆模糊&#xff0c;赶紧记录&#xff0c;防止忘记。 相关链接&#xff1a; 开源 Arkts …

Go的defer和recover

在 Go 语言中&#xff0c;defer 和 recover 是两个紧密相关的关键字&#xff0c;主要用于错误处理和资源清理。它们通常一起使用&#xff0c;特别是在处理panic&#xff08;运行时崩溃&#xff09;时&#xff0c;确保程序不会直接崩溃&#xff0c;而是能够优雅地恢复并继续执行…

Spring Boot 配置文件常用配置属性详解(application.properties / application.yml)

前言 Spring Boot 的一大优势就是通过简单的配置文件即可快速定制应用行为&#xff0c;而无需编写大量 XML 配置或 Java 代码。Spring Boot 使用 application.properties 或 application.yml 作为核心配置文件&#xff0c;支持丰富的配置属性。 本文将详细介绍 Spring Boot 常用…

uni-appDay02

1.首页-通用轮播组件 轮播图组件需要再首页和分类页使用&#xff0c;封装成通用组件 准备组件自动导入组件 <script setup lang"ts"> import XtxSwiper from /components/XtxSwiper.vue import CustomNavbar from ./components/CustomNavbar.vue </scrip…

FastAPI入门:请求体、查询参数和字符串校验、路径参数和数值校验

请求体 FastAPI 使用请求体从客户端&#xff08;例如浏览器&#xff09;向 API 发送数据。请求体是客户端发送给 API 的数据。响应体是 API 发送给客户端的数据。 使用 Pydantic 模型声明请求体&#xff0c;能充分利用它的功能和优点 from fastapi import FastAPI from pydanti…

Docker的docker-compose类比Spring的ApplicationContext

总一句话是&#xff1a;Docker Compose&#xff1a;集中化管理多个容器及其依赖的资源环境&#xff1b;ApplicationContext&#xff1a;集中化管理 多个Bean 及其运行所需的资源和依赖关系。 1. 整体概念 Docker Compose&#xff1a;用于定义和运行多容器 Docker 应用程序&…

Reason-before-Retrieve(CVPR 2025)

研究方向&#xff1a;Image Captioning论文全名&#xff1a;《Reason-before-Retrieve: One-Stage Reflective Chain-of-Thoughts for Training-Free Zero-Shot Composed Image Retrieval》1. 论文介绍组合图像检索&#xff08;CIR&#xff09;旨在检索与参考图像密切相似的目标…

Idefics2:构建视觉-语言模型时,什么是重要的

温馨提示&#xff1a; 本篇文章已同步至"AI专题精讲" Idefics2&#xff1a;构建视觉-语言模型时&#xff0c;什么是重要的 摘要 随着large language models和vision transformers的进步&#xff0c;视觉-语言模型&#xff08;VLMs&#xff09;受到了越来越多的关注…

再谈fpga开发(fpga调试方法)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】我们之前在学校学习c、c的时候&#xff0c;其实学校漏掉了很重要的一个教学环节&#xff0c;那就是调试、测试。很多时候我们代码写出来了&#xff…

C语言中的数据结构--栈和队列(1)

前言本届开始我们将对数据结构中栈的内容进行讲解,那么废话不多说,我们正式进入今天的学习栈栈是一种很特殊的线性表&#xff0c;它只能在固定的一端进行插入和删除操作&#xff0c;进行数据的插入和删除的一端叫做栈顶&#xff0c;另外一端叫做栈底&#xff0c;栈中的元素遵守…

字符串是数据结构还是数据类型?

比较纠结的一个问题&#xff0c;以下是在网上查到后总结的&#xff0c;不知道对不对&#xff0c;欢迎讨论。这是个触及计算机科学核心概念的精妙问题&#xff01;字符串既可以被视为一种数据类型&#xff0c;也可以被视为一种数据结构&#xff0c;这取决于你观察的视角和讨论的…

Cline与Cursor深度实战指南:AI编程助手的革命性应用

引言 在AI编程工具快速发展的今天&#xff0c;Cline和Cursor作为两款备受瞩目的AI编程助手&#xff0c;正在重新定义开发者的工作方式。作为一名深度使用这两款工具的开发者&#xff0c;我在过去一年的实践中积累了丰富的经验和独到的见解。本文将从技术角度深入分析Cline和Cur…

根本是什么

根本是什么 根本没有了&#xff0c;枝叶还在么&#xff1f; 没有了内涵&#xff0c;外延还有么&#xff1f; 丢弃了根本&#xff0c;再嗨也是无意义&#xff0c;无根据空虚之乐罢了。 人之所行所言所思所想所念皆欲念、历程感怀&#xff0c;情思。所谓得失过往&#xff0c;时空…

springboot基于Java的人力资源管理系统设计与实现

管理员&#xff1a;登录&#xff0c;个人中心&#xff0c;部门管理&#xff0c;员工管理&#xff0c;培训信息管理&#xff0c;员工奖励管理&#xff0c;员工惩罚管理员工考核管理&#xff0c;调薪信息管理&#xff0c;员工调动管理&#xff0c;员工工资管理员工&#xff1a;注…

金字塔降低采样

文章目录image_scale.hppimage_scale.cppmainimage_scale.hpp #ifndef IMAGE_SCALE_HPP #define IMAGE_SCALE_HPP#include <vector> #include <cstdint> #include <utility> // for std::pair #include <algorithm> #include <string> enum cl…

Filament引擎(四)——光照渲染Froxelizer实现分析

Froxelizer主要是用于filament光照效果的实现&#xff0c;生成光照渲染时所需的必要信息&#xff0c;帮助渲染过程中明确哪些区域受哪些光源所影响&#xff0c;是Filament中保证光照效果渲染效率的核心所在。这部分的源码&#xff0c;可以结合filament官方文档中Light Path部分…

2025 环法对决,VELO Angel Glide 坐垫轻装上阵

2025环法第16赛段的风秃山之巅&#xff0c;当最后一缕夕阳沉入云层&#xff0c;山风裹挟着砾石的气息掠过赛道&#xff0c;一场足以载入史册的激战正酣。帕雷-潘特的肌肉在汗水里贲张&#xff0c;链条与齿轮的咬合声混着粗重喘息&#xff0c;在171.5公里赛程的最后3公里陡坡上&…

Linux程序->进度条

进度条最终效果&#xff1a; 目录 进度条最终效果&#xff1a; 一&#xff1a;两个须知 1&#xff1a;缓冲区 ①&#xff1a;C语言自带缓冲区 ②&#xff1a;缓冲区的刷新策略 2&#xff1a;回车和换行的区别 二&#xff1a;倒计时程序 三&#xff1a;入门板进度条的实…

Python爬虫实战:研究tldextract库相关技术构建新闻网站域名分析爬虫系统

1. 引言 网络爬虫作为一种自动获取互联网信息的技术,在数据挖掘、信息检索、舆情分析等领域有着广泛的应用。Python 因其丰富的库和简洁的语法,成为了开发爬虫的首选语言。tldextract 是 Python 中一个强大的域名解析库,能够准确地从 URL 中提取顶级域名、二级域名等关键信…