)
根据Qwen3的官方文档,qwen3的调用方式和之前版本基本相同,可以归纳为三种调用方式,分别是普通调用、API服务调用和vllm调用。
写在前面
根据官方文档说明,对环境要求如下:
transformers>=4.51.0
pytorch>=2.6
vllm>=0.8.5
python建议使用3.10以上版本
1、普通调用
普通调用的基本步骤基本包括:导入库、加载模型和分词器、准备模型输入、生成对话式输入、将输入转化为模型所需格式、生成文本以及处理生成的文本。首先放上官方的使用例程:
### 1、导入必要的库
from transformers import AutoModelForCausalLM, AutoTokenizer
# 指定我们要使用的模型名称
model_name = "Qwen/Qwen3-8B"
### 2、加载模型和分词器
# 加载模型和tokenizer
# AutoModelForCausalLM 用于加载因果语言模型(例如GPT-3)
# AutoTokenizer 用于加载与模型匹配的分词器
model = AutoModelForCausalLM.from_pretrained(
model_name, # 模型名称
torch_dtype="auto", # 自动推断数据类型(通常为 float16 或 float32)
device_map="auto" # 自动选择设备(例如 GPU 或 CPU)
)
tokenizer = AutoTokenizer.from_pretrained(model_name) # 加载与模型配套的tokenizer
### 3、准备模型输入
# 我们的输入是一个简单的prompt,让模型生成一段文本
prompt = "Give me a short introduction to large language models."
messages = [
{"role": "user", "content": prompt}, # 定义用户消息内容
]
### 4、生成对话式输入
# 使用tokenizer生成文本输入,apply_chat_template 是自定义方法,生成对话格式的输入
text = tokenizer.apply_chat_template(
messages, # 使用消息内容
tokenize=False, # 不对内容进行分词
add_generation_prompt=True, # 为生成的文本添加前置提示
enable_thinking=True, # 启用“思考”模式,模拟模型思考过程
)
### 5、将输入转化为模型所需格式
# 将文本转换为模型输入所需的格式,转换为tensor,并移动到适当的设备(GPU 或 CPU)
model_inputs = tokenizer([text], return_tensors="pt").to(model.device)
### 6、生成文本
# max_new_tokens 设置生成文本的最大长度
generated_ids = model.generate(
**model_inputs, # 输入模型
max_new_tokens=32768 # 设置最大生成的新token数量
)
### 7、处理生成的文本
# 获取生成的文本内容,排除掉输入的部分
output_ids = generated_ids[0][len(model_inputs.input_ids[0]):].tolist()
# 解析生成内容中的“思考”部分
try:
# 使用rindex查找特殊的结束符 (</think>),指示思考的结束
index = len(output_ids) - output_ids[::-1].index(151668)
except ValueError:
# 如果未找到结束符,则默认为 0
index = 0
# 解析“思考”部分内容
thinking_content = tokenizer.decode(output_ids[:index], skip_special_tokens=True).strip("\n")
# 解析实际生成的内容
content = tokenizer.decode(output_ids[index:], skip_special_tokens=True).strip("\n")
# 打印输出的思考内容和最终生成的内容
print("thinking content:", thinking_content)
print("content:", content)
1、导入库:
AutoModelForCausalLM
:用来加载一个语言模型(这类模型一般用于生成文本)。AutoTokenizer
:用来加载与模型对应的“分词器”,即将文本转化为模型可以理解的格式。
2、加载模型和分词器:
- 我们通过
model_name
指定要使用的模型,这里选择的是Qwen/Qwen3-8B
,这是一个预训练的语言模型。通过from_pretrained
方法加载模型和对应的分词器。 torch_dtype="auto"
和device_map="auto"
让代码能够自动选择合适的硬件(GPU或CPU)来运行模型。
3、准备模型的输入:
prompt
是我们提供给模型的输入文本,告诉模型我们想让它生成什么类型的内容(在这里是关于大型语言模型的介绍)。messages
是一个字典,指定了这条消息是由“用户”发出的。
4、生成对话格式的输入:
apply_chat_template
方法将用户消息包装成适合模型的对话格式,并启用了“思考”模式。这种模式是为了模拟模型在生成文本之前的“思考”过程。
5、将输入转化为模型所需格式:
- 使用
tokenizer([text], return_tensors="pt")
将文本转换为模型可以理解的“张量”格式,并将其移动到适当的设备上(如 GPU 或 CPU)。
6、生成文本:
- 使用
model.generate
方法,基于输入内容生成新的文本。这里设置了max_new_tokens=32768
,即生成的文本最多可以包含32768个新的标记(tokens)。
7、处理生成的文本:
-
由于生成的文本包括了输入的部分(例如“用户消息”),所以我们通过切割去掉了输入部分,保留生成的内容。
-
然后,我们使用
rindex
查找特殊的标记(例如</think>
),这个标记用来指示“思考”结束的位置。 -
如果找到了“思考”结束标记,就将其前面的部分视为“思考”内容,后面的部分是实际的生成结果。
-
最后,通过
tokenizer.decode
解码生成的 ID,得到可以读懂的文本,并去掉任何特殊符号。 -
最终将“思考内容”和生成的实际“内容”打印出来。
注意:
1、针对模型是否进行“思考”,即输出内容是否包含思考块<think>...</think>
,官方使用了硬开关和软开关两种方式。
(1)硬开关:为了严格禁用模型的思考行为,使其功能与之前的Qwen2.5-Instruct模型保持一致,您可以在格式化文本时设置enable_thinking=False
。
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
enable_thinking=False, # Setting enable_thinking=False disables thinking mode
)
普通调用和vllm调用都可以使用这种硬开关,使用起来也很方便。
(2)软开关:Qwen3 还能够理解用户对其思考行为的指令,特别是软开关 /think
和 /no_think
。您可以将这些指令添加到用户 (user) 或系统 (system) 消息中,以在对话轮次之间灵活切换模型的思考模式。在多轮对话中,模型将遵循最近的指令。
软开关的方式可以无视硬开关,即使enable_thinking=True,输入指令带有/no_think
,输出内容也不会包含思考。
2、API服务调用
通常,大模型都可以使用openai的方式启动一个服务,比如:
python -m vllm.entrypoints.openai.api_server --port 10110 --served-model-name Qwen3-0___6B --model /home/Model/Qwen/Qwen3-0___6B --tensor-parallel-size 2 --dtype auto --gpu-memory-utilization 0.9 --max-model-len 32768 --enforce-eager
当你希望大模型不要进行思考时,可以设置"enable_thinking": False
,详情如下,在调用时添加"chat_template_kwargs"说明:
from openai import OpenAI
# Set OpenAI's API key and API base to use vLLM's API server.
openai_api_key = "EMPTY"
openai_api_base = "http://localhost:8000/v1"
client = OpenAI(
api_key=openai_api_key,
base_url=openai_api_base,
)
chat_response = client.chat.completions.create(
model="Qwen/Qwen3-8B",
messages=[
{"role": "user", "content": "Give me a short introduction to large language models."},
],
max_tokens=8192,
temperature=0.7,
top_p=0.8,
presence_penalty=1.5,
extra_body={
"top_k": 20,
"chat_template_kwargs": {"enable_thinking": False},
},
)
print("Chat response:", chat_response)
通常思考内容与结果内容是一块输出的,官方还给出了分开输出的方法,在vllm启动服务命令后面添加--enable-reasoning --reasoning-parser deepseek_r1
,这样输出内容就是分开的了,可以使用下面程序分开获取:
response = msg.choices[0].message.reasoning_content # 获取思考内容
response = msg.choices[0].message.content # 获取结果内容
3、vllm调用
vLLM 也可以直接用作 Python 库,这对离线批量推理非常方便,但缺少一些仅限 API 的功能,例如将模型生成解析为结构化消息。
以下展示了将 vLLM 用作库的基本用法:
from transformers import AutoTokenizer
from vllm import LLM, SamplingParams
# Initialize the tokenizer
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-8B")
# Configurae the sampling parameters (for thinking mode)
sampling_params = SamplingParams(temperature=0.6, top_p=0.95, top_k=20, max_tokens=32768)
# Initialize the vLLM engine
llm = LLM(model="Qwen/Qwen3-8B")
# Prepare the input to the model
prompt = "Give me a short introduction to large language models."
messages = [
{"role": "user", "content": prompt}
]
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
)
# Generate outputs
outputs = llm.generate([text], sampling_params)
# Print the outputs.
for output in outputs:
prompt = output.prompt
generated_text = output.outputs[0].text
print(f"Prompt: {prompt!r}, Generated text: {generated_text!r}")
vllm调用逻辑和普通调用相似,注意如果需要设置是否启用思考,和普通调用方式一样,在tokenizer.apply_chat_template
中添加enable_thinking=False
,如下所示:
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
enable_thinking=enable_thinking_flag # Switches between thinking and non-thinking modes. Default is True.
)
注意:
1、我在使用时遇到报错:
RuntimeError:
An attempt has been made to start a new process before the
current process has finished its bootstrapping phase.
This probably means that you are not using fork to start your
child processes and you have forgotten to use the proper idiom
in the main module:
if __name__ == '__main__':
freeze_support()
...
The "freeze_support()" line can be omitted if the program
is not going to be frozen to produce an executable.
Traceback (most recent call last):
File "/home/ps/Project/Qwen3_0509/get_answer_qwen3.py", line 271, in <module>
llm = LLM(model=model_path)
File "/home/ps/miniconda3/envs/qwen3/lib/python3.10/site-packages/vllm/utils.py", line 1161, in inner
return fn(*args, **kwargs)
File "/home/ps/miniconda3/envs/qwen3/lib/python3.10/site-packages/vllm/entrypoints/llm.py", line 247, in __init__
self.llm_engine = LLMEngine.from_engine_args(
File "/home/ps/miniconda3/envs/qwen3/lib/python3.10/site-packages/vllm/engine/llm_engine.py", line 510, in from_engine_args
return engine_cls.from_vllm_config(
File "/home/ps/miniconda3/envs/qwen3/lib/python3.10/site-packages/vllm/v1/engine/llm_engine.py", line 112, in from_vllm_config
return cls(vllm_config=vllm_config,
File "/home/ps/miniconda3/envs/qwen3/lib/python3.10/site-packages/vllm/v1/engine/llm_engine.py", line 92, in __init__
self.engine_core = EngineCoreClient.make_client(
File "/home/ps/miniconda3/envs/qwen3/lib/python3.10/site-packages/vllm/v1/engine/core_client.py", line 73, in make_client
return SyncMPClient(vllm_config, executor_class, log_stats)
File "/home/ps/miniconda3/envs/qwen3/lib/python3.10/site-packages/vllm/v1/engine/core_client.py", line 494, in __init__
super().__init__(
File "/home/ps/miniconda3/envs/qwen3/lib/python3.10/site-packages/vllm/v1/engine/core_client.py", line 398, in __init__
self._wait_for_engine_startup()
File "/home/ps/miniconda3/envs/qwen3/lib/python3.10/site-packages/vllm/v1/engine/core_client.py", line 430, in _wait_for_engine_startup
raise RuntimeError("Engine core initialization failed. "
RuntimeError: Engine core initialization failed. See root cause above.
后来查到是多进程启用不当,在使用 multiprocessing
时,没有使用正确的 if __name__ == '__main__':
保护机制,导致在创建子进程时出现问题。后来搜解决方法的时候在官方文档中找到该错误解决方案:
查看了vllm文档的错误提示,可以知道,在代码前加入if __name__ == '__main__':
即可。
三花聚顶,合三为一
此外,我将三种方法归纳整理为统一的调用模式,可供大家参考:
### 使用不同的方式调用qwen3大模型回答问题
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
# from transformers import AutoTokenizer
from vllm import LLM, SamplingParams
from openai import OpenAI
import re
# 检查是否有可用的 GPU
if torch.cuda.is_available():
# 获取可用显卡数量
num_gpus = torch.cuda.device_count()
# 打印每个显卡的编号和名称
print(f"Found {num_gpus} GPU(s):")
for i in range(num_gpus):
print(f"GPU {i}: {torch.cuda.get_device_name(i)}")
# 选择使用所有 GPU
DEVICE = torch.device("cuda")
else:
# 如果没有 GPU,则使用 CPU
DEVICE = torch.device("cpu")
print("No GPU found, using CPU.")
### 大模型调用
# 拆分模型输出为思考部分和结果部分
def extract_text_after_think(input_text):
# 使用正则表达式提取<think>与</think>之间的内容
think_match = re.search(r"<think>(.*?)</think>", input_text, re.DOTALL)
# 使用正则表达式提取<think>后面的内容
result_match = re.search(r"</think>\s*(.*)", input_text, re.DOTALL)
if think_match:
# 提取思考内容并去掉前后的空白字符
think_content = think_match.group(1).strip()
# 提取匹配的部分并去掉前后的空白字符
result_content = result_match.group(1).strip()
return think_content, result_content
else:
return None, input_text
LLM_MODE = 2 # 0:本地普通调用 1:API调用 2:本地vllm调用
# 调用本地大模型进行推理----Qwen3
def chat_local_llm(messages, tokenizer, model, enable_thinking_flag=True, max_tokens=32768):
try:
if LLM_MODE == 0: # 本地用 # 普通加载
text = tokenizer.apply_chat_template(
messages, # 消息列表
tokenize=False, # 是否对文本进行分词
add_generation_prompt=True, # 是否添加生成提示符
enable_thinking=enable_thinking_flag # Switches between thinking and non-thinking modes. Default is True.
)
model_inputs = tokenizer([text], return_tensors="pt").to(DEVICE)
# 设置生成参数
if enable_thinking_flag:
generation_kwargs = {
"max_new_tokens": max_tokens,
"temperature": 0.6,
"top_p": 0.95,
"do_sample": True,
"top_k": 20,
}
else:
generation_kwargs = {
"max_new_tokens": max_tokens,
"temperature": 0.7,
"top_p": 0.8,
"do_sample": True,
"top_k": 20,
}
# conduct text completion
generated_ids = model.generate(
**model_inputs,
**generation_kwargs
)
output_ids = generated_ids[0][len(model_inputs.input_ids[0]):].tolist()
# parsing thinking content
try:
# rindex finding 151668 (</think>)
index = len(output_ids) - output_ids[::-1].index(151668)
except ValueError:
index = 0
thinking_content = tokenizer.decode(output_ids[:index], skip_special_tokens=True).strip("\n")
content = tokenizer.decode(output_ids[index:], skip_special_tokens=True).strip("\n")
elif LLM_MODE == 1: # API调用
# 使用大模型API 兼容:tokenizer----LLM_BASE_URL;model----LLM_MODEL_NAME
client = OpenAI(
api_key=model,
base_url=tokenizer,
)
if enable_thinking_flag:
msg = client.chat.completions.create(
model=model,
messages=messages,
max_tokens=max_tokens,
temperature=0.6,
top_p=0.95,
extra_body={
"top_k": 20,
}
)
else:
msg = client.chat.completions.create(
model=model,
messages=messages,
max_tokens=max_tokens,
temperature=0.7,
top_p=0.8,
presence_penalty=1.5,
extra_body={
"top_k": 20,
"chat_template_kwargs": {"enable_thinking": False},
},
)
# print(msg)
# response = msg.choices[0].message.reasoning_content # 设置了解析思考内容时--enable-reasoning --reasoning-parser deepseek_r1
response = msg.choices[0].message.content
# print(response)
# total_tokens = msg.usage.total_tokens
# print(total_tokens)
thinking_content, content = extract_text_after_think(response)
elif LLM_MODE == 2: # vllm调用
# Configurae the sampling parameters (for thinking mode)
if enable_thinking_flag:
sampling_params = SamplingParams(temperature=0.6, top_p=0.95, top_k=20, max_tokens=max_tokens)
else:
sampling_params = SamplingParams(temperature=0.7, top_p=0.8, top_k=20, max_tokens=max_tokens)
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
enable_thinking=enable_thinking_flag # Switches between thinking and non-thinking modes. Default is True.
)
# Generate outputs
outputs = llm.generate([text], sampling_params)
# Print the outputs.
for output in outputs:
prompt = output.prompt
generated_text = output.outputs[0].text
print(f"Prompt: {prompt!r}, Generated text: {generated_text!r}")
thinking_content, content = extract_text_after_think(generated_text)
else:
print("大模型调用模式错误!!!请重新检查!!!")
except RuntimeError as e:
raise e # 抛出
return thinking_content, content
if __name__ == '__main__':
### 设置输入
# prepare the model input
# prompt = "介绍一下北京有哪些好玩地方。 /no_think"
prompt = "介绍一下北京有哪些好玩地方。 "
messages = [
{"role": "user", "content": prompt}
]
model_path = "/home/Model/Qwen/Qwen3-0___6B"
if LLM_MODE == 0: # 本地用 # 普通加载
# load the tokenizer and the model
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(
model_path,
torch_dtype="auto",
device_map="auto"
)
thinking_content, content = chat_local_llm(messages, tokenizer, model, enable_thinking_flag=False, max_tokens=14336)
print(thinking_content)
print(content)
elif LLM_MODE == 1: # API
LLM_MODEL_NAME = "Qwen3-0___6B"
LLM_API_KEY = "Qwen3-0___6"
LLM_BASE_URL = "http://xxx.xxx.xxx.xxx:xxxxx/v1"
thinking_content, content = chat_local_llm(messages, LLM_BASE_URL, LLM_MODEL_NAME, enable_thinking_flag=False, max_tokens=14336)
print(thinking_content)
print(content)
elif LLM_MODE == 2: # vllm本地用
# Initialize the tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_path)
# Initialize the vLLM engine
llm = LLM(model=model_path)
thinking_content, content = chat_local_llm(messages, tokenizer, llm, enable_thinking_flag=True, max_tokens=14336)
print(thinking_content)
print(content)