4、基础推理:加载模型、单次推理、流式输出、参数调优

好,咱们进入正题。前面几章我们把环境搭好了,也把 vLLM 的核心架构捋了一遍。现在,是时候让模型真正跑起来了。

这一章,我会带你走一遍基础推理的完整流程。从加载模型开始,到单次推理,再到流式输出,最后聊聊参数调优。说白了,就是让你能立刻上手,把模型用起来。

4.1 加载模型:没那么简单

加载模型,听起来就是一行代码的事。但我在项目中踩过不少坑,这里给你提个醒。

注意: 模型加载时,显存占用会瞬间飙升。如果你的 GPU 显存不够大,建议先设置 max_model_lengpu_memory_utilization

我个人习惯用 LLM 类来加载模型。它封装了大部分细节,用起来很顺手。看代码:

from vllm import LLM, SamplingParams

# 加载模型
llm = LLM(
    model="Qwen/Qwen2.5-7B-Instruct",
    tensor_parallel_size=1,  # 单卡就用1
    max_model_len=4096,      # 限制最大上下文长度
    gpu_memory_utilization=0.9,  # 显存利用率
    trust_remote_code=True   # 有些模型需要这个
)

这里有几个关键点:

  • tensor_parallel_size:如果你有多张卡,可以设成 2、4 等。vLLM 会自动做张量并行。
  • max_model_len:我建议设小一点。比如 4096,既能满足大部分场景,又不会把显存撑爆。
  • gpu_memory_utilization:默认是 0.9。如果你还要跑其他任务,可以降到 0.7。
小技巧: 加载模型时,vLLM 会打印日志。注意看 "Loading model weights took ..." 这一行。如果时间太长,可能是磁盘 I/O 瓶颈。我曾经遇到过 HDD 加载 7B 模型花了 5 分钟,换成 SSD 后只要 30 秒。

4.2 单次推理:最简单的调用

模型加载好了,接下来就是推理。单次推理,说白了就是给模型一个输入,它给你一个输出。

看这个例子:

# 准备输入
prompts = ["什么是人工智能?"]

# 设置采样参数
sampling_params = SamplingParams(
    temperature=0.7,
    max_tokens=512,
    top_p=0.9
)

# 执行推理
outputs = llm.generate(prompts, sampling_params)

# 打印结果
for output in outputs:
    print(output.outputs[0].text)

嗯,这里要注意:llm.generate 返回的是一个列表。即使你只传了一个 prompt,它也会返回一个列表。所以要用 outputs[0] 来取结果。

我曾经犯过一个低级错误:直接打印 outputs,结果看到一堆对象地址,还以为模型坏了。后来才发现要取 .outputs[0].text

4.3 流式输出:让用户不再等待

单次推理有个问题:如果模型生成的内容很长,用户要等很久才能看到结果。流式输出就是为了解决这个问题。

vLLM 支持两种流式方式:

  • 同步流式:用 generate 方法,设置 stream=True
  • 异步流式:用 AsyncLLMEngine,配合 asyncio

我个人更推荐同步流式,因为它简单,而且大多数场景够用了。看代码:

from vllm import LLM, SamplingParams

llm = LLM(model="Qwen/Qwen2.5-7B-Instruct")
sampling_params = SamplingParams(temperature=0.7, max_tokens=1024)

# 流式输出
for output in llm.generate("讲个笑话", sampling_params, stream=True):
    # output 是一个 RequestOutput 对象
    if output.outputs[0].text:
        print(output.outputs[0].text, end="", flush=True)

这里的关键是 stream=True。vLLM 会逐 token 返回结果。你想想看,用户看到文字一个字一个字地蹦出来,体验是不是好很多?

核心要点: 流式输出时,每次返回的 output.outputs[0].text增量文本,不是完整结果。所以你要用 end="" 来拼接,而不是每次都换行。

4.4 参数调优:控制模型的行为

模型推理时,有几个参数能显著影响输出质量。我重点讲两个:max_tokenstemperature

4.4.1 max_tokens:控制输出长度

max_tokens 决定了模型最多生成多少个 token。注意,是 token,不是汉字。一般来说,一个汉字对应 1-2 个 token。

场景 推荐 max_tokens 说明
短问答 128-256 比如“今天天气怎么样”
中等长度 512-1024 比如写一段代码或邮件
长文本生成 2048-4096 比如写文章或报告

我建议不要设得太大。一方面,显存占用会线性增长;另一方面,模型生成太长容易跑偏。我在项目中遇到过,设了 4096,结果模型写到后面开始胡言乱语。

4.4.2 temperature:控制随机性

temperature 控制模型输出的随机性。值越高,输出越多样;值越低,输出越确定。

  • temperature=0:完全确定,每次输出都一样。适合代码生成、数学计算。
  • temperature=0.7:平衡模式。适合大多数对话场景。
  • temperature=1.0:高随机性。适合创意写作、头脑风暴。
注意: temperature 不能和 top_ktop_p 同时使用。如果你设置了 temperature,就不要设 top_k 和 top_p。否则模型行为会变得不可控。

我曾经犯过一个错:把 temperature 设成 2.0,结果模型输出了一堆乱码。后来查文档才知道,temperature 一般建议在 0-1 之间。超过 1 会让概率分布过于平滑,模型几乎是在随机选词。

4.5 完整示例:一个可运行的脚本

说了这么多,不如直接给你一个完整的脚本。你复制到本地就能跑:

from vllm import LLM, SamplingParams

def main():
    # 1. 加载模型
    print("正在加载模型...")
    llm = LLM(
        model="Qwen/Qwen2.5-7B-Instruct",
        max_model_len=2048,
        gpu_memory_utilization=0.8
    )
    
    # 2. 设置参数
    sampling_params = SamplingParams(
        temperature=0.7,
        max_tokens=512,
        top_p=0.9
    )
    
    # 3. 单次推理
    prompts = ["用Python写一个快速排序算法"]
    outputs = llm.generate(prompts, sampling_params)
    print("单次推理结果:")
    print(outputs[0].outputs[0].text)
    
    # 4. 流式输出
    print("\n流式输出结果:")
    for output in llm.generate(prompts, sampling_params, stream=True):
        if output.outputs[0].text:
            print(output.outputs[0].text, end="", flush=True)

if __name__ == "__main__":
    main()

这个脚本涵盖了加载模型、单次推理、流式输出三个核心步骤。你跑一遍,就能直观感受到 vLLM 的推理速度。

4.6 知识体系图

为了让你更直观地理解本章内容,我画了一张流程图:

vLLM 基础推理流程 加载模型 设置采样参数 流式? 流式输出 单次推理 输出结果

这张图清晰地展示了推理流程:加载模型 → 设置参数 → 选择流式或单次 → 输出结果。你跟着这个流程走,基本不会出错。

我的建议: 刚开始学的时候,先用单次推理。等熟悉了,再切换到流式输出。一口吃不成胖子,对吧?

公众号:蓝海资料掘金营,微信deep3321