把大语言模型接入生产环境,难点远不止启动一个推理服务。Netflix 分享的核心经验指向了更棘手的问题:模型尺寸不同、GPU 需求不同、推理引擎快速演进,而业务方仍然希望通过稳定、统一的平台调用模型。Triton 与 vLLM 的价值,正是在模型运行时与平台接口之间建立一个可治理的服务层。
一个推理平台为什么需要多种运行时
传统机器学习平台通常围绕相对稳定的模型格式、批处理策略和硬件配置建设。LLM 改变了这些前提。
小模型可能只占用一张 GPU,较大的模型则需要张量并行或流水线并行;有些任务强调首个 token 的响应时间,有些任务更关心整体吞吐量;量化模型、长上下文模型和带 LoRA 适配器的模型,也会产生不同的显存与调度要求。
这意味着平台不能把某个推理引擎直接等同于服务接口。更合理的分层方式是:
- 接入层负责认证、配额、模型命名、请求校验和流式响应。
- 调度层根据模型、显存、并行度和服务等级选择实例。
- 运行时层承载 Triton、vLLM 等推理引擎,并允许它们独立升级。
- 硬件层提供不同 GPU 型号、显存规格和节点拓扑。
Triton 适合纳入已有模型服务体系,统一管理不同后端和模型仓库;vLLM 则面向生成式模型,重点处理连续批处理、KV Cache 和高吞吐 token 生成。平台同时支持两者,并不意味着每个模型都要经过两套引擎,而是让部署控制面根据工作负载选择合适的运行时。
稳定接口比固定引擎更重要
推理引擎仍在高速变化。批处理算法、量化格式、并行策略和兼容 API 都可能在版本升级后改变。如果业务代码直接依赖某个引擎的请求格式,升级就会扩散到所有调用方。
平台可以定义自己的模型端点,例如:
POST /v1/generate
Content-Type: application/json
Authorization: Bearer $TOKEN
{
"model": "support-assistant-7b",
"prompt": "Summarize the customer issue in one sentence.",
"max_tokens": 128,
"temperature": 0.2,
"stream": false
}
网关再把这个稳定请求转换为 vLLM 的 OpenAI 兼容接口,或转换为 Triton 对应模型后端的输入张量。这样,运行时升级、模型迁移和硬件调整可以留在平台内部。
这层抽象不能过度追求“所有模型完全一致”。例如 logits、beam search、结构化输出和多模态输入可能只被部分运行时支持。务实的做法是维护一组稳定的公共能力,同时通过显式的 capabilities 元数据暴露运行时差异,避免静默忽略参数。
可以这样实践:启动一个可调用的 vLLM 服务
下面是一个独立的实践示例,并非 Netflix 内部配置。它适合用来验证模型加载、GPU 显存和 OpenAI 兼容接口。运行前需要安装 NVIDIA Container Toolkit,并把模型名替换为你有权访问的 Hugging Face 模型。
docker run --rm --gpus all \
-p 8000:8000 \
-e HUGGING_FACE_HUB_TOKEN="$HUGGING_FACE_HUB_TOKEN" \
vllm/vllm-openai:latest \
--model Qwen/Qwen2.5-1.5B-Instruct \
--served-model-name support-assistant \
--gpu-memory-utilization 0.90 \
--max-model-len 4096
服务就绪后,可以直接发送请求:
curl http://localhost:8000/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "support-assistant",
"messages": [
{"role": "user", "content": "用三点总结部署大模型推理服务时需要监控的指标。"}
],
"temperature": 0.2,
"max_tokens": 160
}'
如果要迁移到 Kubernetes,可以这样改造。以下 YAML 假设集群已经安装 NVIDIA device plugin,并且节点能够拉取模型:
apiVersion: apps/v1
kind: Deployment
metadata:
name: support-assistant-vllm
spec:
replicas: 1
selector:
matchLabels:
app: support-assistant-vllm
template:
metadata:
labels:
app: support-assistant-vllm
spec:
containers:
- name: server
image: vllm/vllm-openai:latest
args:
- --model
- Qwen/Qwen2.5-1.5B-Instruct
- --served-model-name
- support-assistant
- --max-model-len
- "4096"
- --gpu-memory-utilization
- "0.90"
ports:
- name: http
containerPort: 8000
resources:
limits:
nvidia.com/gpu: "1"
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 30
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: support-assistant-vllm
spec:
selector:
app: support-assistant-vllm
ports:
- name: http
port: 8000
targetPort: http
部署命令如下:
kubectl apply -f vllm.yaml
kubectl rollout status deployment/support-assistant-vllm
kubectl port-forward service/support-assistant-vllm 8000:8000
生产环境还应固定镜像版本和摘要,而不是长期使用 latest;模型权重也应通过受控缓存、对象存储或持久卷分发,避免每个 Pod 启动时重复下载。
容量规划不能只看每秒请求数
LLM 请求的成本与输入、输出 token 数直接相关。两个 HTTP 请求可能相差几十倍计算量,因此普通的 QPS 指标不足以驱动扩缩容。
平台至少应记录以下指标:
- 排队时间、首 token 延迟和完整请求延迟。
- 每秒输入 token、每秒输出 token及生成吞吐量。
- KV Cache 使用率、GPU 显存使用率和批次大小。
- 请求被拒绝、超时、取消与输出截断的数量。
- 按模型、版本、租户和优先级拆分的资源消耗。
自动扩缩容同样要谨慎。LLM Pod 启动时需要加载大量权重,冷启动可能远慢于普通 Web 服务。仅在队列变长后才增加实例,往往已经来不及。平台可以结合历史流量预热容量,并为交互式请求与离线任务设置不同队列和抢占策略。
上线前需要做出的决定
采用 Triton、vLLM 或其他运行时之前,先明确平台边界:统一的是认证与请求协议,还是连采样参数、流式语义和错误码也必须一致。抽象层越厚,迁移越容易,但运行时的新能力也越难及时开放。
落地时可以检查以下事项:
- 为模型版本、运行时版本、GPU 类型和量化方式建立可追踪的部署记录。
- 用固定提示词集测试质量、首 token 延迟、吞吐量和显存峰值。
- 对上下文长度、输出 token、并发数和租户配额设置硬限制。
- 保留运行时回滚路径,避免引擎升级与模型升级同时进行。
- 对提示词和输出日志执行脱敏、访问控制及保留期限管理。
Netflix 的生产经验说明,LLM 服务平台的长期价值不在于绑定某一个推理引擎,而在于吸收模型、硬件和运行时不断变化带来的复杂度。Triton 与 vLLM 可以成为执行层的重要组成部分,但稳定接口、容量治理、可观测性和升级机制才决定平台能否持续运行。