第 3 章 快速上手:离线推理 + OpenAI 兼容服务(实践强化版)

目标:用最短时间打通 离线推理脚本OpenAI 兼容在线服务 的最小闭环;理解 SamplingParams 的关键项;掌握 vllm serve 常用启动参数;基于官方 OpenAI Python SDK 完成聊天与流式连通性测试;综合给出健康检查与限流(节流)建议与 Runbook。


3.1 两条最短路径

3.1.1 离线推理(Python 脚本)

vLLM 的离线推理入口是 LLM 类;采样与解码行为由 SamplingParams 控制。官方文档明确这两者的角色分工与最小示例(不同版本文档表述略有差异,但核心一致):LLM 提供批量离线推理接口,SamplingParams 提供温度、top-p、max_tokens 等参数;示例脚本通常以 facebook/opt-125m 为演示模型开箱可跑。(nm-vllm.readthedocs.io)

最小脚本(可直接粘贴运行)

# offline_minimal.py
from vllm import LLM, SamplingParams

prompts = [
    "用 2 句话解释什么是 vLLM:",
    "给出一个 Python 读取文件并统计行数的示例:",
]

sampling = SamplingParams(
    temperature=0.7,
    top_p=0.95,
    max_tokens=128,
    stop=None,                # 可选,字符串或列表
    presence_penalty=0.0,     # vLLM 兼容 OpenAI 同名语义
    frequency_penalty=0.0,
)

llm = LLM(model="facebook/opt-125m")  # 可替换任意 HF 模型仓库名或本地路径
outputs = llm.generate(prompts, sampling_params=sampling)

for i, out in enumerate(outputs):
    print(f"--- Prompt {i} ---")
    print(out.outputs[0].text.strip())

上面的示例对应文档里的最小离线推理用法;LLM.generate() 返回与输入 prompt 顺序对齐的输出列表,每个元素里还可取 outputs[k].logprobs/token_ids 等细节用于调试。(nm-vllm.readthedocs.io)

进一步:LLM 也支持多 GPU 的张量并行(tensor_parallel_size),以及更多引擎参数(KV Cache 精度、最大序列长度、显存利用率等),详见 “Engine/Serve 参数总览”。(nm-vllm.readthedocs.io)


3.1.2 在线服务(OpenAI 兼容)

vLLM 自带一个 OpenAI 兼容 HTTP 服务器,实现了 Chat / Completions API 的主要参数与接口;可直接用官方 openai Python 客户端连接。文档明确:支持绝大多数 OpenAI 参数,例外包括 Chat 的 tools/tool_choice 与 Completions 的 suffix;并提供了 vLLM 特有扩展参数(如 guided_* 系列用于结构化输出)。(nm-vllm.readthedocs.io)

一条命令启动:

python -m vllm.entrypoints.openai.api_server \
  --model NousResearch/Meta-Llama-3-8B-Instruct \
  --dtype auto \
  --api-key token-abc123
# 默认监听 0.0.0.0:8000,base_url 将是 http://<host>:8000/v1

用 OpenAI 官方 SDK 直连(聊天)

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="token-abc123")
resp = client.chat.completions.create(
    model="NousResearch/Meta-Llama-3-8B-Instruct",
    messages=[{"role":"user","content":"用 1 句话介绍 vLLM 是什么?"}],
)
print(resp.choices[0].message.content)

流式(server-sent events)回传示例

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="token-abc123")
stream = client.chat.completions.create(
    model="NousResearch/Meta-Llama-3-8B-Instruct",
    messages=[{"role":"user","content":"逐步回答:如何在容器中部署 vLLM?"}],
    stream=True,
)
for chunk in stream:
    delta = chunk.choices[0].delta
    if delta and delta.content:
        print(delta.content, end="", flush=True)

以上代码/参数与文档一致:通过 api_server 启动;使用官方客户端设置 base_url 指向 /v1;返回对象字段与 OpenAI 对齐;扩展参数通过 extra_body 传递。(nm-vllm.readthedocs.io)


3.2 SamplingParams:必会即用

vLLM 的采样参数设计遵循 OpenAI Completion/Chat 的语义,外加若干增强(beam search、min_pguided_* 等)。常见字段及说明(综合 vLLM 文档多个版本页面信息,以下为实用汇总):(docs.vllm.ai)

字段 作用(直观解释) 取值建议/经验
max_tokens 最多生成多少新 token 压成本/稳定性时务必设上限(如 256/512/1024)
temperature 温度,越高越随机 0–0.7 信息密集;>0.7 创造性更强
top_p nucleus sampling 累积概率阈值 temperature 联动;常用 0.9–0.98
top_k 仅从前 k 个候选采样 大模型一般 -1(禁用)或 20–50
presence_penalty 存在惩罚(促使覆盖新词) 0–1 之间,小幅提升去重复
frequency_penalty 频率惩罚(抑制重复词) 0–1 之间,文本去复读利器
stop/stop_token_ids 早停控制(字符串/ID) 强约束格式常配合使用
use_beam_search/best_of 束搜索/候选数 需要更确定输出时考虑,注意吞吐影响
min_p Nucleus 的替代变种,罕见 token 更易入选 top_p 二择一即可
guided_* 结构化输出(JSON/Regex/Grammar/Choice) 复杂结构首选 guided_json/grammar

备注:Chat/Completions 的支持与例外见“OpenAI 兼容服务”页面;扩展参数通过 extra_body 传入,示例见下。(nm-vllm.readthedocs.io)

结构化输出(扩展参数示例)

from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="token-abc123")

schema = {
  "type": "object",
  "properties": {
    "title": {"type":"string"},
    "tags": {"type":"array","items":{"type":"string"}}
  },
  "required": ["title","tags"]
}

resp = client.chat.completions.create(
    model="NousResearch/Meta-Llama-3-8B-Instruct",
    messages=[{"role":"user","content":"以 JSON 输出:给本文拟一个标题并列 3 个标签"}],
    extra_body={"guided_json": schema, "temperature": 0},
)
print(resp.choices[0].message.content)  # 返回即符合 schema

该能力来自 vLLM 的“额外参数”设计,文档列出了 guided_json/regex/grammar/choice 及可选 guided_decoding_backend。(nm-vllm.readthedocs.io)


3.3 vllm serve:启动参数与开箱套路

虽然 api_server 已能跑,但生产/预生产建议使用命令式 vllm serve(或容器镜像)并搭配关键参数。Red Hat 的 vLLM 文档对关键四参给了清晰解释:

  • --tensor-parallel-size:按 GPU 拆分模型;
  • --gpu-memory-utilization:显存利用率上限(默认 0.9);
  • --max-model-len:限制上下文长度上限;
  • --max-num-batched-tokens:单步批处理 token 上限(吞吐关键)。(docs.redhat.com)

此外,“完整参数列表”涵盖模型、权重加载格式、KV Cache 精度、tokenizer 池、并行策略等,适合做模板化封装。(docs.redhat.com)

常用启动清单(NVIDIA 举例)

vllm serve meta-llama/Meta-Llama-3-8B-Instruct \
  --dtype auto \
  --tensor-parallel-size 1 \
  --gpu-memory-utilization 0.9 \
  --max-model-len 8192 \
  --max-num-batched-tokens 2048 \
  --api-key token-abc123 \
  --chat-template /path/to/template.jinja   # 部分模型需要

如果模型仓库未提供 Chat Template,可手工指定,否则 Chat 请求会报错。文档明确可通过 --chat-template 传入 Jinja 模板文本或文件路径。(nm-vllm.readthedocs.io)

量化/特性可用性提示(扩展)
官方与生态对 FP8/AWQ 等量化模型的 serve 命令保持一致(仅模型名不同),例如 Qwen 团队给出了 FP8/AWQ 的用法与硬件能力说明(FP8 需 Ada/Hopper 及以上架构)。(qwen.readthedocs.io)


3.4 最小可行 Runbook(含健康检查 / 限流建议)

下面给出一个自检友好的 Runbook,覆盖下载—启动—连通—观测—告警全链路。

3.4.1 启动前检查

  1. 模型可用性与 Chat Template

    • Hugging Face 模型是否需要申请访问?(私有/协议)
    • Chat 模型是否内置 chat_template?若无,准备好 --chat-template。(nm-vllm.readthedocs.io)
  2. GPU/驱动与内存预算

    • 预估 max_model_len × batch_token 组合是否会 OOM;必要时降低 --max-num-batched-tokens--max-model-len。官方优化页也建议通过这两项约束并行度以节省 KV Cache 空间。(docs.vllm.ai)
  3. 容器/进程形态

    • 容器启动请设置合适的 --shm-size、HF token(如需);Red Hat 文档给出了 Podman 示例与关键环境变量。(docs.redhat.com)

3.4.2 启动与连通

  • 服务启动vllm serve(或 python -m ...api_server)+ 关键参数。(nm-vllm.readthedocs.io)

  • 健康检查

    • 官方/社区对 /health 的讨论指出:该端点在模型加载后才返回 200(启动初期会不可用),因此就绪探针存活探针应分离,必要时自定义 /ready。(GitHub)
    • 指标端点/metrics(Prometheus),可观测运行/等待请求数、LoRA 请求信息等指标,Red Hat 文档列举了关键指标名。(docs.redhat.com)
  • 客户端连通:使用 OpenAI 官方 SDK(上节示例)完成 Chat 与流式校验。(nm-vllm.readthedocs.io)

3.4.3 限流 / 节流与错误处理(4xx/5xx)

现状与建议:

  • vLLM 原生“主动 429”能力有限(社区 issue 反馈尚未完备的“繁忙即 429”机制),更多应由网关/反向代理实现(如 NGINX/Envoy/Traefik 或云 API 网关),同时结合并发/令牌感知。(GitHub)
  • 运营实践建议采用token 维度配额(每分钟/小时的输入/输出 token限额)+ 并发会话上限。参考通用 LLM API 节流设计经验与文章。(compute.hivenet.com)
  • 对 vLLM 实例侧,使用 --max-num-batched-tokens--max-model-len--gpu-memory-utilization 进行物理层面的“吞吐边界”收敛,避免因超长上下文或巨大 batch 触发 OOM/抖动。(docs.redhat.com)

错误处理要点(对调用方)

  • 429 Too Many Requests:在 vLLM 侧未必触发(见上);如由网关返回,需指数退避并在 header 中读取限流窗口(若有);OpenAI 生态中也常见“平台繁忙导致 429”的情形,调用方按惯例做重试/降级。(OpenAI Developer Community)
  • 5xx:模型下载失败/冷启动超时/后端过载等可能导致 5xx,外层需熔断与重试策略;在 vLLM 侧配合 /metrics 进行突发观测与告警;另外,学术/实践报道亦提到 vLLM 在高压场景可能出现节流/抖动。(docs.redhat.com)

N×M 维度限流方案(参考蓝图)

  • 维度:每 API Key × 每路由 × 输入/输出 token × 并发连接
  • 策略:硬阈值(拒绝/429)、软阈值(排队/等待)、配额刷新(滑动窗口/令牌桶);
  • 位置:网关优先(负责绝大多数策略),应用层补充(例如在 FastAPI 中读取 /metrics 指标做自适应 backpressure)。参考 Runpod 的 vLLM 负载均衡与健康检查教程。(docs.runpod.io)

3.5 “常见问题”快速定位

  1. 启动后 Chat 报错:多半因缺少 chat template,用 --chat-template 指定模板文件或模板字符串。(nm-vllm.readthedocs.io)

  2. 吞吐上不去/TTFT 偏大

    • 先压低 --max-model-len 与提升 --max-num-batched-tokens 以增加并行度(权衡 TPOT/尾延迟);
    • 观察 /metrics 的队列与运行请求数,定位瓶颈。(docs.redhat.com)
  3. OOM 或波动:减少 --max-num-batched-tokens--max_num_seqs(后者在优化指南中同义地影响批并发),并将 --gpu-memory-utilization 设为安全阈值(如 0.85)。(docs.vllm.ai)

  4. SDK 连接失败:确认 base_url 指向 http://host:8000/v1,以及 --api-key 与请求 header 一致;端口是否暴露;容器网络是否允许入站。(nm-vllm.readthedocs.io)


3.6 实验:启动 vLLM 服务 + OpenAI 客户端连通性(含流式)

实验目的

  • 用任意 HF 指令模型启动 vllm serve
  • 用 OpenAI 官方 Python 客户端发起聊天流式请求,确认连通/回显;
  • 记录 TTFT(首 token 时间)与 QPS(可通过并发发压或外部压测器)。

步骤

  1. 拉起服务
vllm serve NousResearch/Meta-Llama-3-8B-Instruct \
  --dtype auto \
  --gpu-memory-utilization 0.9 \
  --max-model-len 8192 \
  --max-num-batched-tokens 2048 \
  --api-key token-abc123

若报 Chat 模板相关错误,追加 --chat-template。(nm-vllm.readthedocs.io)

  1. 功能连通(非流式)
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="token-abc123")
r = client.chat.completions.create(
    model="NousResearch/Meta-Llama-3-8B-Instruct",
    messages=[{"role":"user","content":"给出 3 条使用 vLLM 的最佳实践"}],
    temperature=0.2,
    max_tokens=200,
)
print(r.choices[0].message.content)
  1. 流式连通(SSE)
    见 3.1.2 的 streaming 代码(逐块打印)。(nm-vllm.readthedocs.io)

  2. 健康与指标

  • curl http://localhost:8000/metrics | head(确认指标输出);
  • 若需要就绪探针,在外层(如 K8s/自定义网关)实现 /ready 并校验 num_requests_running/ num_requests_waiting 等指标阈值。(docs.redhat.com)
  1. 限流演练(可选)
  • 在网关配置并发/令牌桶
  • 人为制造超并发,验证 429/队列行为与客户端重试策略。(Medium)

3.7 实操补充:OpenAI 兼容的“扩展参数”

vLLM 允许通过 extra_body={...} 传递扩展字段,用于结构化输出特殊解码策略。文档给出了完整列表:guided_jsonguided_regexguided_choiceguided_grammarguided_decoding_backend 等;Chat/Completions 两侧均有对应支持集合。(nm-vllm.readthedocs.io)

例:受限多选(classification)

from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="token-abc123")

labels = ["正向","中性","负向"]
r = client.chat.completions.create(
  model="NousResearch/Meta-Llama-3-8B-Instruct",
  messages=[{"role":"user","content":"情感极性:我对新功能很期待,但担心稳定性。"}],
  extra_body={"guided_choice": labels, "temperature": 0},
)
print(r.choices[0].message.content)  # 必为上述三者之一

3.8 运行参数速查(常更易用)

下表对“快速上手阶段最容易用到”的 serve 参数做归纳(以稳定实践为导向;完整清单以 Red Hat 文档为准):(docs.redhat.com)

分组 参数 用途 备注
模型 --model / --revision / --trust-remote-code 指定模型与版本 私有/需协议模型要配置 HF token(环境变量)
精度 --dtype / --kv-cache-dtype 权重/激活与 KV Cache 精度 auto 常用;KV Cache 可选 FP8 等
并行 --tensor-parallel-size 多 GPU 张量并行 与拓扑绑定,单机多卡常用
内存/吞吐 --gpu-memory-utilization / --max-model-len / --max-num-batched-tokens 控制显存与批处理 三者联动决定吞吐与稳定
安全 --api-key 启用 API 鉴权 客户端需带 Authorization: Bearer
Chat --chat-template Chat 格式化 无模板的指令模型需要
监控 (内置)/metrics Prometheus 指标 观测队列、运行中请求等
生态 --lora-modules 装载 LoRA 适配器 详见第 4 章

3.9 可靠性与可观测性

  • Metrics:访问 /metrics 可获得 vllm:num_requests_running / waiting / swapped / lora_requests_info 等指标(不同版本可能有所增减),用于构建 Grafana 面板与 SLO。Red Hat 文档与 vLLM 早期/版本化文档对这些指标有说明。(docs.redhat.com)
  • 健康检查/health 在模型加载完后才 200,K8s 就绪探针需延迟/重试;社区也讨论过引入 /ready 的最佳实践。(GitHub)
  • 网关集成:参考 Runpod/社区教程以实现负载均衡与健康路由。(docs.runpod.io)

3.10 常见 4xx/5xx 与定位手册(浓缩)

状态码 场景 处理建议
400 参数非法(如 model 不匹配、max_tokens 过大) 校正采样参数;必要时降 max_model_lenmax_tokens
401 未带 Authorization 或 key 错误 确认 --api-key 和客户端一致
404 路由不对(应指向 /v1/...)或 model 名称不匹配 确认 base_urlmodel
409 资源状态冲突(极少见) 重试或清理任务
429 外层网关限流或平台繁忙 指数退避;对 vLLM 原生 429 不要过度依赖,转向网关/代理侧实现。(OpenAI Developer Community)
5xx 冷启动超时/下载失败/后端过载 /metrics + 日志定位;容器拉起/网络/HF token 检查;必要时降并发与 batch。(docs.redhat.com)

3.11 高阶一口气:从“脚本 → 服务 → 可观测”

  1. 脚本阶段:确认 LLM + SamplingParams 能在本机跑通(样例见 3.1.1)。(nm-vllm.readthedocs.io)
  2. 服务阶段vllm serve 融合关键四参;openai 客户端连通并校验流式。(docs.redhat.com)
  3. 可观测:拉 /metrics 指标,结合网关实现令牌感知限流并发上限,并针对 429/5xx 做降级/重试。(docs.vllm.ai)

3.12 最小可行推理脚本与服务启动 Runbook(可直接复用)

A. 离线脚本(含批量)

# offline_batch.py
from vllm import LLM, SamplingParams

prompts = ["总结:什么是 PagedAttention(50 字以内)?"] * 4  # 批量
sampling = SamplingParams(temperature=0.2, top_p=0.9, max_tokens=80)

llm = LLM(
    model="facebook/opt-125m",
    tensor_parallel_size=1,           # 单卡可设 1
)
outs = llm.generate(prompts, sampling_params=sampling)
print([o.outputs[0].text.strip() for o in outs])

关键点:离线 LLM 也支持 tensor_parallel_size 等配置,便于在脚本中做多卡测试。(vllm.readthedocs.io)

B. 服务启动(生产友好默认)

# 预设:NVIDIA 单机单卡;端口 8000;需要鉴权
export HF_HUB_ENABLE_HF_TRANSFER=1

vllm serve NousResearch/Meta-Llama-3-8B-Instruct \
  --dtype auto \
  --gpu-memory-utilization 0.9 \
  --max-model-len 8192 \
  --max-num-batched-tokens 2048 \
  --tensor-parallel-size 1 \
  --api-key ${VLLM_API_KEY:?missing} \
  --chat-template /path/to/template.jinja

C. 健康检查/限流建议(可复制到平台手册)

  • 存活探针:TCP/HTTP 200(/health),注:加载完成前不返回 200。

  • 就绪探针:自定义 /ready(由网关/sidecar 提供),条件:

    • /metricsvllm:num_requests_running < 阈值,vllm:num_requests_waiting < 阈值;
    • 最近 1 分钟 5xx 比例 < X%。(GitHub)
  • 限流

    • 每 Key:并发连接 ≤ N;输入/输出 token 每分钟限额;
    • 每实例:合适的 --max-num-batched-tokens--max-model-len
    • 返回码:建议在网关层实现 429,并带 Retry-After。(compute.hivenet.com)

3.13 FAQ 速解卡

  • 为何我用 OpenAI SDK 直连就能通?
    因为 vLLM 的服务实现了 OpenAI Chat/Completions API 的兼容层,SDK 只需改 base_urlapi_key 即可。(nm-vllm.readthedocs.io)

  • 哪些 OpenAI 参数暂不支持?
    Chat 的 tools/tool_choice、Completions 的 suffix 不支持,其它大多支持。(nm-vllm.readthedocs.io)

  • 如何做 JSON/Regex/Grammar 约束?
    通过扩展参数 guided_json/regex/grammar/choiceextra_body 传入)。(nm-vllm.readthedocs.io)

  • 如何观察吞吐与排队?
    /metrics 里有当前运行/等待请求等;结合 Grafana/Prometheus 做可视化。(docs.vllm.ai)

  • 限流/429 为什么说要靠网关?
    vLLM 侧对“繁忙返回 429”的支持并不完备(社区 issue 反馈),而网关天然适合做配额与并发控制。(GitHub)


3.14 小结与本章 Checklist

你应该已经能够:

  • LLM + SamplingParams 在本地完成离线批量推理;(nm-vllm.readthedocs.io)
  • 启动 vllm serve 并通过 OpenAI 官方 SDK 完成聊天流式连通性测试;(nm-vllm.readthedocs.io)
  • 掌握关键四参(gpu_memory_utilization / max_model_len / max_num_batched_tokens / tensor_parallel_size)的调节方向;(docs.redhat.com)
  • 在外层网关实现token 感知 + 并发限流,配合 /metrics 做健康/就绪判断与告警。(docs.vllm.ai)

附:可复制的“服务启动 Runbook(健康检查/限流版)”

  1. 准备

    • 选择模型并确认 Chat Template;
    • 估算 max context / batch tokens,结合显存给出首版参数。(nm-vllm.readthedocs.io)
  2. 启动

    • vllm serve <model> --dtype auto --gpu-memory-utilization 0.9 --max-model-len 8192 --max-num-batched-tokens 2048 --api-key ...
    • 记录启动日志里显存分配与 tokenizer 加载信息。(docs.redhat.com)
  3. 探活与连通

    • curl /metrics 应有 vLLM 指标;
    • openai SDK 跑一条 Chat + 一条 Streaming。(docs.redhat.com)
  4. 网关策略

    • 并发上限(每 key、全局);
    • token 限额(输入/输出/总);
    • 默认重试与 Retry-After
    • 429/5xx 的熔断/灰度。(compute.hivenet.com)
  5. 监控与告警

    • 队列/运行中请求、TTFT/TPOT(可由客户端埋点上报)、OOM/异常日志;
    • 根据服务 SLA 设阈值(如 num_requests_waiting 连续 > X 触发扩容/流量调度)。(docs.redhat.com)

参考与延伸

——至此,你已经完成 “第 3 章:快速上手:离线推理 + OpenAI 兼容服务” 的全部学习与实践闭环。下一步建议在你的机型/模型上沉淀一份参数基线表(含 max_model_len / max_num_batched_tokens / gpu_memory_utilization 三元组),并持续根据 /metrics 与压测数据微调。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐