3、vLLM核心API详解:LLM类与AsyncLLMEngine、SamplingParams参数配置、流式输出与批处理

好,咱们直接进入正题。vLLM 这个框架,说白了就是帮你把大模型跑得更快、更省显存。但光知道它快没用,你得会用它的核心 API。今天我就带你把这几个关键组件掰开揉碎讲清楚。

3.1 LLM类:最常用的同步接口

我个人习惯,在写脚本或者做快速验证的时候,首选就是 LLM 类。它是个同步接口,用起来特别直接。

核心要点:LLM 类封装了模型加载、推理、显存管理全流程。你只需要传一个模型路径,它就能跑起来。

from vllm import LLM, SamplingParams

# 加载模型
llm = LLM(model="meta-llama/Llama-2-7b-chat-hf")

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

# 单条推理
output = llm.generate("什么是注意力机制?", params)
print(output[0].outputs[0].text)

嗯,这里要注意。我第一次用的时候,以为 generate 返回的是字符串,结果发现是个对象列表。每个 output 里还包了一层 outputs。为什么这么设计?因为 vLLM 支持一次传多条 prompt,返回结构就得是嵌套的。

避坑指南:我曾经在批量生成时,忘了检查 outputs 列表的长度。如果某个 prompt 因为特殊 token 被截断了,它的 outputs 可能为空。记得加个 if output.outputs 判断。

3.2 AsyncLLMEngine:高性能异步引擎

如果你要搭一个在线服务,或者需要高并发处理请求,那 AsyncLLMEngine 才是你的菜。它底层用的是 asyncio 事件循环,能同时处理多个请求。

你想想看,同步接口一次只能处理一个请求,后面的都得排队。异步引擎就不一样了,它可以在等待 GPU 计算的时候,去处理其他请求的预处理工作。

from vllm import AsyncLLMEngine, SamplingParams
from vllm.engine.arg_utils import AsyncEngineArgs

# 配置引擎参数
engine_args = AsyncEngineArgs(
    model="meta-llama/Llama-2-7b-chat-hf",
    max_num_batched_tokens=4096,
    max_num_seqs=256
)

# 创建异步引擎
engine = AsyncLLMEngine.from_engine_args(engine_args)

# 异步生成
async def generate_async(prompt):
    params = SamplingParams(temperature=0.8, max_tokens=256)
    results = []
    async for output in engine.generate(prompt, params, request_id="req_001"):
        results.append(output)
    return results

重要提醒:AsyncLLMEngine 的 generate 方法返回的是一个异步生成器。你必须用 async for 来迭代,不能直接 await。我刚开始就犯过这个错,以为它返回的是完整结果。

3.3 SamplingParams:控制生成行为的核心参数

SamplingParams 是 vLLM 里最常用的配置类。它决定了模型怎么「选词」。我把它分成三组来讲:

参数类别 参数名 作用 我的建议值
多样性控制 temperature 控制随机性,值越高越随机 0.7(创意任务) / 0.1(精确任务)
多样性控制 top_p 核采样,只从概率和超过 p 的 token 中选 0.9
多样性控制 top_k 只从概率最高的 k 个 token 中选 40
长度控制 max_tokens 最大生成 token 数 根据任务定,别设太大浪费显存
长度控制 min_tokens 最小生成 token 数 0(除非你要强制生成长文本)
重复惩罚 repetition_penalty 惩罚重复出现的 token 1.1(轻度惩罚)
重复惩罚 frequency_penalty 根据 token 出现频率惩罚 0.0(一般不调)

实战经验:我在做代码生成任务时,会把 temperature 设到 0.1 以下,甚至直接用 0。因为代码需要确定性。但写文案或者故事时,我会用 0.8 到 1.0,让输出更有创意。

3.4 流式输出:让用户不再干等

流式输出,说白了就是一边生成一边返回结果。用户体验会好很多——用户不用盯着空白页面等十几秒。

vLLM 的流式输出实现得很优雅。你只需要在 SamplingParams 里设置 stream=True,然后迭代输出即可。

from vllm import LLM, SamplingParams

llm = LLM(model="Qwen/Qwen2-7B-Instruct")
params = SamplingParams(
    temperature=0.7,
    max_tokens=1024,
    stream=True  # 开启流式输出
)

# 流式生成
for output in llm.generate("写一首关于春天的诗", params):
    # output 是逐步返回的
    print(output.outputs[0].text, end="", flush=True)

小技巧:流式输出时,每个 output 对象里只有新生成的 token 文本。如果你想拿到完整结果,需要自己拼接。我一般会在循环外维护一个 full_text = "" 变量,每次迭代时 full_text += token

3.5 批处理:榨干 GPU 的每一分算力

批处理是 vLLM 的杀手锏。它利用 PagedAttention 技术,把多个请求打包在一起处理,显存利用率能提升好几倍。

你想想看,如果一次只处理一个请求,GPU 的算力大部分时间都在空转。批处理就能让 GPU 满负荷运转。

from vllm import LLM, SamplingParams

llm = LLM(model="mistralai/Mistral-7B-v0.1")

# 准备一批 prompt
prompts = [
    "解释一下量子纠缠",
    "写一段 Python 代码实现快速排序",
    "翻译成英文:今天天气真好",
    "总结一下深度学习的历史"
]

# 统一的采样参数
params = SamplingParams(temperature=0.7, max_tokens=512)

# 批量生成
outputs = llm.generate(prompts, params)

# 处理结果
for i, output in enumerate(outputs):
    print(f"Prompt {i+1}: {output.outputs[0].text[:50]}...")

性能陷阱:批处理不是越大越好。我曾经把 batch size 设到 256,结果显存直接爆了。vLLM 虽然做了显存优化,但每个请求的 max_tokens 和模型大小都会影响显存占用。建议从 32 开始试,逐步往上加。

3.6 知识体系总览

下面这张图是我自己画的,把今天讲的几个核心概念串起来了。你看一眼就能明白它们之间的关系。

vLLM 核心 API 知识体系 vLLM 推理引擎 LLM 类(同步接口) AsyncLLMEngine(异步引擎) SamplingParams(参数配置) 单条推理 / 批量推理 高并发 / 流式输出 温度 / Top-P / 长度控制 批处理 + 流式输出 = 高吞吐低延迟 PagedAttention 技术支撑高效显存管理

这张图里,LLM 类和 AsyncLLMEngine 是两种使用方式,SamplingParams 是它们的共同配置。批处理和流式输出是 vLLM 的两大特色功能,一个提升吞吐,一个改善体验。

总结一下:LLM 类适合脚本和快速验证,AsyncLLMEngine 适合生产环境。SamplingParams 是控制生成质量的关键,流式输出提升用户体验,批处理榨干 GPU 性能。把这几个点吃透了,vLLM 你就掌握了七八成。

最后说一句:API 文档写得再好,也不如自己跑一遍代码。我建议你打开 Jupyter Notebook,把上面的代码示例挨个跑一遍。遇到报错别慌,看看错误信息,八成是路径写错了或者显存不够。


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