LLaMA Factory微調后的大模型Chat對話效果,與該模型使用vLLM推理架構中的對話效果,可能會出現不一致的情況。
下圖是LLaMA Factory中的Chat的對話
下圖是vLLM中的對話效果。
模型回答不穩定:有一半是對的,有一半是無關的。
1、未收斂;
模型回答與LLaMA Factory訓練chat界面的不一致。
1、對話模版chat_template不一致。
本文來講解下對話模版不一致的情況的解決方法。
一、原因分析
1、LLaMA Factory在微調訓練需要選擇模型名稱,自動帶出對話模版,比如qwen。這個對話模版是LLaMA Factory項目根據qwen官方提供的對話模版改編,與大模型自身的對話模版并不相等。
2、LLaMA Factory的對話模版的源碼在LLaMA-Factory/src/llamafactory/data/template.py這個類里。獲取對話模版的方法(私有方法)_get_jinja_template ,可以用公共方法fix_jinja_template來調用該私有方法。
大模型的默認對話模版在?tokenizer_config.json里chat_template字段。
3、可以看到LLaMA Factory微調訓練時的對話模版與大模型的默認對話模版并不相同。
二、解決方案
既然是因為兩邊不一致,那么只要保證兩邊一致即可。也就是模版對話對齊。
我們可以將LLaMA Factory中的模版修改掉,需要修改源碼;也可以在vLLM、ollama或LMDeploy等推理框架在運行大模型時候手動指定對話模版。兩種方法都可以,這里我們先使用后者來操作。
1、獲取LLaMA Factory中的對話模版
在微調訓練中,界面中選擇大模型后,自定帶出對話模版,記住名稱,比如qwen 。
寫一個python代碼,獲取對話模版,get_chat_template.py 。
# get_chat_template.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("/root/autodl-tmp/llm/Qwen/Qwen2.5-0.5B-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)
需要修改2個地方,(1)初始化分詞器,地址要寫本地存在的大模型;?(2)獲取模版對象,template_name一定要寫你微調界面上選擇的對話模版名稱,比如qwen? 。
將該文件放在目錄LLaMA-Factory/src/llamafactory/data下。
運行該文件。
python get_chat_template.py
結果如下:?
將內容復制,從====的下一行{% 開始復制。保存到一個文件中,格式為.jinja? ?,比如? qwen.jinja 。
2、vLLM運行大模型指定jinja文件
為了使語言模型支持聊天協議,vLLM 要求模型在其 tokenizer 配置中包含一個聊天模板。聊天模板是一個 Jinja2 模板,它指定了角色、消息和其他特定于聊天對 tokens 如何在輸入中編碼。
可以在?--chat-template
?參數中手動指定聊天模板的文件路徑或字符串形式。
https://vllm.hyper.ai/docs/serving/openai-compatible-server#%E8%81%8A%E5%A4%A9%E6%A8%A1%E6%9D%BF
vllm serve <model> --chat-template ./path-to-chat-template.jinja
比如:
vllm serve /root/autodl-tmp/llm/Qwen/Qwen2.5-0.5B-Instruct-merge --chat-template /root/autodl-tmp/project/day07/qwen.jinja
這樣就可以保證對話模版一致了。
3、ollama創建ModelFile的內容
創建一個python文件,獲取內容:get_ollama_modelfile.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, get_template_and_fix_tokenizer
from transformers import AutoTokenizer
from llamafactory.hparams import DataArguments# 1. 初始化分詞器(任意支持的分詞器均可)
tokenizer = AutoTokenizer.from_pretrained("/root/autodl-tmp/llm/Qwen/Qwen2.5-0.5B-Instruct")# 2. 獲取模板對象
template_name = "qwen" # 替換為你需要查看的模板名稱
template = TEMPLATES[template_name]# 3. 修復分詞器的 Jinja 模板
template.fix_jinja_template(tokenizer)# 4. ollama制作ModelFile的內容template = get_template_and_fix_tokenizer(tokenizer, DataArguments(template=template_name))
# template.get_ollama_modelfile(tokenizer)
print("=" * 40)
print(f"Template [{template_name}] 的 Modelfile 格式:")
print("=" * 40)
print(template.get_ollama_modelfile(tokenizer))
3、LMDeploy框架指定對話模版
https://lmdeploy.readthedocs.io/zh-cn/latest/advance/chat_template.html
LMDeploy支持json格式的對話模版,需要將jinja2格式的轉成json格式。我們可以使用AI搜索來做。比如我們使用DeepSeek來轉換。
打開https://chat.deepseek.com/? ,上傳jinja2文件,并且輸入文字:
文件中是一個jinja2格式的qwen的對話模版,我需要轉成lmdeploy框架支持的的json格式的對話模版,json模版格式如下:{"model_name": "your awesome chat template name","system": "<|im_start|>system\n","meta_instruction": "You are a robot developed by LMDeploy.","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|>"]
}
返回結果:
{"model_name": "qwen","system": "<|im_start|>system\n","meta_instruction": "You are Qwen, created by Alibaba Cloud. You are a helpful assistant.","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|>", "</tool_call>", "<|im_start|>", "<|im_end|>\n"],"tool_spec": {"tool_call_start": "<tool_call>","tool_call_end": "</tool_call>","tool_response_start": "<tool_response>","tool_response_end": "</tool_response>"}
}
字段說明:
system
/eosys
:對應系統消息的開始和結束標記。user
/eoh
:用戶消息的起止標記。assistant
/eoa
:助理消息的起止標記。meta_instruction
:使用原模板中的默認系統提示。separator
:消息間的換行符(\n
)。stop_words
:添加?<|im_end|>
?和其他可能的終止標記(如工具調用相關標簽)。
工具調用擴展:
-
雖然 LMDeploy 基礎模板不直接支持工具調用,但通過?
tool_spec
?字段擴展了工具調用的起止標記,以兼容原模板中的?<tool_call>
?和?<tool_response>
?邏輯。
注意事項:
-
若 LMDeploy 嚴格限制字段,需移除?
tool_spec
?字段。 -
若需要動態系統消息(根據輸入切換),需在 LMDeploy 框架中額外處理,此 JSON 模板僅保留靜態默認值。
三、Open WebUI對話模版說明
Open WebUI有自己的一套對話模版,所以微調后的大模型在使用推理框架(vLLM,ollama,LMDeploy)+Open WebUI,結果可能會產生偏差。所以一般不建議微調后的大模型使用Open WebUI來做界面。