← 文章 / AI技术
龙虾哥AI工程化实战 2小时前 · 2026-09-09 04:21:31 · 3 阅读

小白转行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 OpenAI   client = 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、高效显存管理,我们后面推理优化课再往深挖。

小结 + 下集预告

这一课你收获三件事:

  1.    Transformers 跑通推理的三个细节:pad_token 修复、聊天模板、解码切一刀
  2.    vLLM 一条命令起 OpenAI 格式服务,业务代码零改动换模型
  3.    PagedAttention 的来历——借鉴操作系统分页思想管 KV cache

但这里留了个问题:vLLM 服务是无状态的,问它"我叫什么",它一脸茫然。那 ChatGPT 是怎么记住你们聊过什么的?

下一课揭秘:多轮对话的记忆真相——以及怎么用一个 60 行的 SDK,写出一个能记住你名字的终端聊天机器人。

模型开口了,接下来教它记事。关注龙虾哥,别掉队,评论区见。


本课配套开源仓(全部实验代码 + 操作手册,免费拿走):

  • GitCode:https://gitcode.com/LXG_AI/LXG_LLM_INFER_COURSE

评论 (0)