小白转行AI大模型系列(三)让 Qwen 开口说话——”玩具跑法”和”生产跑法”
上一课我们把 15GB 的 Qwen2.5-7B 下载到了本地,还拆开看了模型的主要构成。但模型文件躺在那里不会自己说话,这一课我们就干最关键的一步:让它开口。
我会演示两种模型部署方式:一种是"玩具跑法"——Transformers 直接推理,适合你理解原理;一种是"生产跑法"——vLLM 起服务,对外提供可访问的 API 接口。这也是面试 AI 岗位的高频题:"Transformers 推理和 vLLM 推理有什么区别?"——学完这一课你就能答上来。
先跑通第一种:十几行代码的"玩具跑法"
代码在文章末尾仓库里(src/infer_transformers.py),可以复制运行:
from transformers import AutoModelForCausalLM, AutoTokenizerimport torchmodel_dir = ”/tmp/pretrainmodel/Qwen2.5-7B-Instruct/”# 1. 加载分词器tokenizer = AutoTokenizer.from_pretrained(model_dir)tokenizer.pad_token = tokenizer.eos_token# 2. 加载模型model = AutoModelForCausalLM.from_pretrained(model_dir,torch_dtype=”auto”,device_map=”auto”,)# 3. 应用聊天模板messages = [{”role”: ”user”, ”content”: ”用一句话介绍你自己”}]text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)# 4. 编码输入inputs = tokenizer(text, return_tensors=”pt”).to(model.device)# 5. 生成outputs = model.generate(**inputs,max_new_tokens=128,pad_token_id=tokenizer.eos_token_id)# 6. 解码(只取新生成的部分)response = tokenizer.decode(outputs[0][inputs[”input_ids”].shape[1]:],skip_special_tokens=True)print(”回复:”, response)
运行后等个三分钟左右(首次要加载权重到显存),你会看到:
回复: 我是Qwen,由阿里云研发的大规模语言模型,旨在提供信息和帮助。跑通了,但里面有三个细节,我逐个说一下。
细节 1:pad_token那两行是干什么的?
Qwen2.5 有个官方说明:要把填充符(pad)设成结束符(eos)。不设的话,批处理时会报错或者结果异常。这个坑不是我们瞎加的,是 Qwen 官方文档明确写的修复——跟模型相关的细节,永远以官方文档为准,这句话得记住,能帮你省下很多排查问题时间。
细节 2:为什么要"应用聊天模板"?
你大概率不知道:你跟模型说"用一句话介绍你自己",模型看到的其实不是这句话的原文,而是一段带特殊标记的文本,类似这样:
<|im_start|>user用一句话介绍你自己<|im_end|><|im_start|>assistant
这就是聊天模板(chat template)。它决定了模型在训练时是怎么"学听话"的,推理时就必须用一模一样的格式"喂话"。忘了套模板,模型也能输出,但可能会前言不搭后语——同一个模型,模板错了,效果天差地别。这也是为什么我们用 apply_chat_template 而不是手动拼字符串。
细节 3:解码时为什么要切一刀?
注意 outputs[0][inputs["input_ids"].shape[1]:] 这句——模型的输出里包含了你输入的那部分,我们要把输入长度切掉,只留新生成的 token。不切的话,打印出来你问题和回答都混在一起。
再上第二种:"生产跑法"
玩具跑法的问题很明显:跑一次加载一次模型,一个请求独占一份资源,吞吐量极低。真实业务里,一个模型服务要同时扛住成百上千个请求,这就轮到 vLLM 出场了。
vLLM 是 2023 年 UC Berkeley 的团队搞出来的项目,起源是一篇论文《Efficient Memory Management for LLM Serving with PagedAttention》。它最出名的贡献是 PagedAttention——思路借鉴了操作系统里的虚拟内存分页管理:以前推理框架给 KV cache 预留一大块连续显存,浪费严重;vLLM 把它切成一页一页的小块,按需分配,显存利用率直接翻倍,吞吐量随之暴涨。这个项目后来成了推理框架的事实标准之一,我们整门课的推理优化部分都会围绕它。
起服务只要一条命令:
# 起服务(占用 8000 端口)vllm serve /tmp/pretrainmodel/Qwen2.5-7B-Instruct/ --port 8000 --served-model-name qwen2.5-7b
看到日志里出现 Application startup complete,服务就绪。
然后另开一个终端,用标准的 OpenAI 格式接口调用它(src/call_vllm.py):
from openai import OpenAIclient = OpenAI(base_url=”http://localhost:8000/v1”, api_key=”EMPTY”)resp = client.chat.completions.create(model=”qwen2.5-7b”,messages=[{”role”: ”user”, ”content”: ”你好,请用一句话介绍你自己”}],)print(resp.choices[0].message.content)
预期返回:
你好,我叫Qwen,是来自阿里云的大规模语言模型,可以帮你回答问题、创作文字等。注意一个很有意思的点:我们用的是openai这个库,调的却是自己电脑上的开源模型。因为 OpenAI 的 Chat Completions 接口格式已经成了行业事实标准,vLLM、各家模型厂商全都兼容它。这意味着你写的业务代码换个模型服务,一行都不用改——这就是"标准"的力量。
两种跑法怎么选
| Transformers 直接推理 | vLLM 服务 | |
|---|---|---|
| 适用场景 | 调试、学习、跑脚本 | 对外提供服务、业务接入 |
| 吞吐量 | 低 | 高(continuous batching) |
| 接口 | Python 函数调用 | OpenAI 格式 HTTP API |
| 记忆 | 无状态 | 无状态(记忆靠客户端维护,下一课讲) |
一句话总结:自己玩用 Transformers,上线提供服务用 vLLM。不管是用豆包APP、DeepSeek APP,还是用他们的网页版本对话,其实都是在使用他们提供的API服务。而面试官想听到的,是你说得出 vLLM 为什么快——关键词就三个:PagedAttention、continuous batching、高效显存管理,我们后面推理优化课再往深挖。
小结 + 下集预告
这一课你收获三件事:
- Transformers 跑通推理的三个细节:pad_token 修复、聊天模板、解码切一刀
- vLLM 一条命令起 OpenAI 格式服务,业务代码零改动换模型
- PagedAttention 的来历——借鉴操作系统分页思想管 KV cache
但这里留了个问题:vLLM 服务是无状态的,问它"我叫什么",它一脸茫然。那 ChatGPT 是怎么记住你们聊过什么的?
下一课揭秘:多轮对话的记忆真相——以及怎么用一个 60 行的 SDK,写出一个能记住你名字的终端聊天机器人。
模型开口了,接下来教它记事。关注龙虾哥,别掉队,评论区见。
本课配套开源仓(全部实验代码 + 操作手册,免费拿走):
- GitCode:https://gitcode.com/LXG_AI/LXG_LLM_INFER_COURSE