第44章 模型部署¶
某次 NL2SQL 批量任务突然失败。排查后发现模型能力没有退化,GPU 也没有故障,而是 Agent Runtime 直接连接了 vLLM Pod 的内网 IP;HPA 缩容后 Pod 重建,地址变化,Runtime 配置却仍指向旧地址。
模型服务层的价值,是把权重、Runtime、GPU 节点、探针、版本和发布策略收敛成稳定 API。上层 Agent 只知道服务名和契约,不应知道 Pod IP、节点位置或权重目录。
第6章解决单机推理引擎,第43章解决算力供给,本章解决模型怎样成为可发布、可扩缩、可灰度、可回滚的生产服务;第45章再在服务之上统一做路由、租户和配额。
44.1 模型服务层:算力之上的第一个稳定 API¶
企业平台通常同时运行多类模型:通用 LLM、代码模型、Embedding、Rerank、视觉模型。它们的资源画像、发布频率和风险并不一样,因此不应被塞进同一个推理进程或同一套发布周期。
表44-1:典型模型服务目录。来源:本书整理。
| 服务名 | 引擎 | 用途 | 默认副本 |
|---|---|---|---|
llm-general-32b |
vLLM | 通用对话、Planner | 4 |
llm-code-7b |
SGLang | SQL/Python 生成 | 2 |
embed-bge-m3 |
Triton | Embedding | 2 |
rerank-bge-v2 |
Triton | Rerank | 1 |
这里的服务名是发布单元和稳定契约。每个服务拥有自己的 Runtime、权重版本、资源画像、SLO、灰度策略和回滚窗口。第45章网关只映射这些稳定服务名,不能把底层 vLLM/SGLang 进程地址暴露给 Agent。
图44-1:模型服务层是 GPU 算力与 Agent 调用之间的稳定 API 边界。来源:本书自绘。Alt text:中间模型服务层向下对接 GPU 资源、向上为 Agent 提供稳定 API,箭头表示底层算力或模型变化被服务层屏蔽、不影响上层调用。
在线、批、Embedding 为什么要拆服务¶
表44-2:不同服务形态的负载与发布策略。来源:本书整理。
| 服务形态 | 资源特征 | 典型场景 | 发布策略 |
|---|---|---|---|
| 在线 LLM | 长连接、KV Cache、尾延迟敏感 | 对话、DataAgent | 金丝雀 + 快速回滚 |
| 批推理 | 高吞吐、可排队 | Eval、离线报告 | 滚动或蓝绿 |
| Embedding | 高 QPS、固定输出维度 | RAG 索引 | 双版本并行后切流 |
| Rerank | 小模型、高频 | 检索排序 | 滚动发布 |
Embedding 和生成式 LLM 混在一张卡上,表面上能提高平均利用率,却容易让小 batch 的高 QPS 与长上下文生成争抢显存和 CUDA 执行资源。服务拆分首先是资源隔离和故障隔离,其次才是组织结构。
四个容易混淆的对象¶
- Serving Runtime:模型怎么运行,例如 vLLM/SGLang 镜像和启动参数;
- Predictor:怎样接收请求并把流量交给 Runtime;
- 模型版本:权重 digest + Runtime 镜像 + 关键启动参数;
- Revision:一次可发布、可回滚的服务版本实例。
Git 里改一行 YAML 不自动等于新模型版本;只有权重、镜像与关键参数形成不可变组合,并产生新 Revision,才真正改变生产模型服务。
44.2 部署框架:按负载选,不追求一套框架包打天下¶
表44-3:主流模型 Serving 框架的定位。来源:本书整理。
| 方案 | 强项 | 适合 | 主要代价 |
|---|---|---|---|
| KServe | Kubernetes 原生、Revision、流量分割、扩缩 | 主 LLM 在线服务 | 依赖 K8s 能力 |
| BentoML | 模型打包与开发体验 | 实验到服务化 | 企业流量治理仍需补齐 |
| Triton | 动态 batching、多模型、高性能 | Embedding/Rerank | 原型迭代不如 Python 框架轻 |
| Ray Serve | Python 原生分布式编排 | 复杂分析、Ray 生态 | 运维体系更重 |
图44-2:部署框架按负载类型选型,而非单一框架包打天下。来源:本书自绘。Alt text:在线推理、批推理、多模型并存等负载分别连向更合适的框架(KServe、BentoML、Triton),体现按负载选型而非一刀切。
本书主路径是:LLM 在线服务使用 KServe + vLLM/SGLang,Embedding/Rerank 使用 Triton,重批分析按需使用 Ray Serve。选择依据不是框架热度,而是是否和第43章 GPU 调度、第45章网关、第46章 GitOps 形成统一运行边界。
KServe 启动链路¶
一次模型 Pod 启动至少经历:
- 获取不可变模型 URI;
- 拉取权重;
- 初始化 Runtime/CUDA/KV Cache;
- readiness 通过;
- Service/Revision 才开始接流量。
表44-4:Serving 组件与典型失败。来源:本书整理。
| 组件 | 职责 | 典型失败 |
|---|---|---|
| Storage Init | 拉取权重 | URI 404、IAM 拒绝、网络失败 |
| Serving Runtime | 加载并推理 | CUDA 不兼容、OOM |
| Predictor | 接请求 | Runtime 未 Ready 就接流量 |
| Scaler | 扩缩副本 | 冷启动期间错误判断容量 |
图44-3:权重加载、Runtime 就绪与流量接入是三个不同控制点。来源:本书自绘。Alt text:部署流程上标出三个独立门控。权重加载完成、Runtime 健康就绪、流量正式接入,箭头表示前一步通过才进入下一步,避免未就绪即接流量。
进程活着、模型加载完成、应该接真实流量,是三个不同状态。 把 liveness /health 当成 readiness,是大模型上线最常见的“半启动接流量”问题之一。
44.3 资源画像与服务接口契约¶
大模型服务的资源画像不能只写“1 张 GPU”。权重、量化、上下文长度、KV Cache、tokenizer CPU、host memory 和 tensor parallel 都会影响是否能稳定服务。
表44-5:典型资源画像。来源:本书整理。
| 维度 | llm-general-32b 示例 |
说明 |
|---|---|---|
| GPU | 1 × A100-80G | 在线整卡 |
| CPU | request 8 / limit 12 | tokenizer 与调度线程 |
| Memory | request 32Gi / limit 48Gi | 避免 host OOM |
| 权重 | AWQ | 约 20GB+,按实际模型测算 |
| KV 余量 | 至少 20% | 长上下文与并发峰值 |
| 冷启动 | 数分钟级 | 权重下载 + CUDA 初始化 |
同样权重在 4k 和 32k context 下的容量完全不同。上线前要用真实输入/输出 token 分布压测,而不是只用短 prompt 做健康检查。
稳定 API 契约¶
上层 Runtime 和网关最好只依赖一个稳定的 OpenAI 兼容子集:
GET /v1/models
GET /health
GET /ready
POST /v1/chat/completions
Request:
{ model, messages, stream, max_tokens, ... }
Errors:
{ error: { code, message, type }, retryable: bool }
/v1/models 返回的模型名必须和服务目录、第45章网关路由一致。错误也要区分可重试和不可重试:队列过载、临时上游失败可以退避;上下文超限、参数非法不应反复重试。
优雅下线¶
LLM 是长连接服务。滚动发布时,如果 Pod 收到 SIGTERM 立即退出,用户会看到半截流式回答。应先停止接收新连接,等待 in-flight 请求完成,再终止进程。
livenessProbe:
httpGet:
path: /health
port: 8000
readinessProbe:
httpGet:
path: /ready
port: 8000
initialDelaySeconds: 120
periodSeconds: 10
terminationGracePeriodSeconds 应参考真实流式请求 P99 设置,而不是沿用普通 Web 服务默认值。
44.4 版本管理:Staging、Canary、蓝绿与回滚¶
模型发布和普通应用发布最大的差异,是权重、Runtime 参数和模型行为都可能改变质量与资源画像。因此,一次模型发布应绑定:
- 权重 URI/digest;
- Runtime 镜像 digest;
- 量化方式;
- TP/PP;
max_model_len;- 资源声明;
- 评测版本;
- Revision 与流量比例。
表44-6:常见发布策略。来源:本书整理。
| 策略 | 优势 | 代价 | 适合 |
|---|---|---|---|
| 滚动 | 简单、省资源 | 短暂混合版本 | Embedding、低风险服务 |
| 金丝雀 | 风险可控 | 需要流量和观测 | 主 LLM |
| 蓝绿 | 回滚最快 | 双倍资源 | 大版本窗口 |
| A/B | 长期比较业务 KPI | 治理复杂 | 模型实验 |
发布状态可以统一成:
图44-4:金丝雀发布把“全量切换”拆成可观测、可回滚的多个门禁。来源:本书自绘。Alt text:流量从 1%、5%、25% 到 100% 分阶段放量,每阶段设观测与回滚门禁,箭头表示指标达标才进入下一档,异常即回滚。
Canary 的价值不在“先放 5%”,而在于每一档都绑定明确的质量、延迟、错误率、GPU 资源和回滚条件。 如果 5% 流量没有覆盖长上下文、高并发和关键租户,它并不能证明全量安全。
KServe 发布示例¶
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: llm-general-32b
namespace: model-serving
spec:
predictor:
minReplicas: 2
maxReplicas: 8
model:
modelFormat:
name: vllm
storageUri: oss://agent-platform-models/llm/qwen2.5-32b-awq/v20260301/
resources:
limits:
nvidia.com/gpu: "1"
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: nodepool
operator: In
values: ["gpu-inference"]
canaryTrafficPercent: 5
权重 URI 必须不可变,禁止使用 latest/ 覆盖上传。上一 Stable Revision 应保留明确回滚窗口,且旧权重、旧镜像和旧 Secret 在窗口内必须仍可访问。
回滚不是 git revert 的同义词¶
真正的回滚要验证:
- 旧 Revision 仍存在;
- 旧权重可拉取;
- 旧 Runtime 与当前节点驱动兼容;
- 网关仍能发现旧服务;
- 旧版本的关键评测仍有效;
- 切流能在目标时间内完成。
季度回滚演练比事故发生时第一次点击“Rollback”可靠得多。
44.5 从本地验证到生产:三阶发布链路¶
Docker Compose 适合本地开发,不能直接充当生产发布系统。它可以验证模型能否启动、served-model-name 是否一致、OpenAI 字段是否兼容,但不覆盖 K8s readiness、GPU 节点亲和、Canary 和回滚。
本地 Compose¶
services:
vllm-general:
image: vllm/vllm-openai:latest
command: >
--model /models/qwen2.5-32b-awq
--served-model-name llm-general-32b
--tensor-parallel-size 1
ports:
- "8000:8000"
volumes:
- ./models:/models:ro
Staging¶
Staging 应尽量和生产使用相同的:
- 权重 digest;
- Runtime 参数;
- readiness;
- GPU 型号;
- 网关路径;
- 模型名。
可以缩小副本数,但不应拿 7B 权重替代 32B 来验证“大模型发布链路”,否则冷启动、显存和 KV Cache 问题仍会第一次出现在生产。
Prod Canary¶
生产前至少要组合三类证据:
- 离线评测:看模型质量和关键任务;
- 压测:看 TTFT、TPOT、并发、OOM、长上下文;
- Canary:看真实租户、真实路由、真实流式连接。
模型能启动,只证明 Runtime 可运行;模型能发布,需要证明加载、流量、质量、资源、回滚和上层契约同时成立。
Embedding 发布还有额外约束:模型版本必须和索引版本绑定。只升级 Embedding 服务却不重建索引,会造成向量空间不一致,属于最危险的静默退化之一。
44.6 生产运行:服务目录、故障降级与退役¶
模型服务上线后,平台需要一份机器可读的服务目录,而不是只保存 endpoint。目录至少应包含:
- 服务名、Revision、权重 URI、镜像 digest;
- 引擎、量化、TP/PP、context length;
- 支持 tool call / JSON / streaming 等能力;
- GPU/CPU/Memory 画像;
- SLO、owner、租户;
- 当前路由与 fallback;
- 发布、回滚、退役状态;
- 调用量、GPU 小时和成本。
能力声明必须由评测证明¶
服务目录声称“支持 JSON 输出”“适合 NL2SQL”“支持 32k context”,都应关联对应的评测样本和压测结果,而不是人工填写标签。第45章网关可以据此做能力路由,Runtime 可以据此判断某类任务是否允许调用。
高频故障¶
表44-7:模型部署高频故障。来源:本书整理。
| 故障 | 典型信号 | 处理方向 |
|---|---|---|
| 冷启动超时 | 长时间 Ready=False | 预热、调探针、加本地缓存 |
| 权重 URI 失败 | Init/Runtime 404/403 | 固定 URI + IAM 对账 |
| CUDA/驱动不匹配 | CrashLoop | 节点池版本治理 |
| Canary 样本不足 | 低流量正常、扩量 OOM | 增强离线/压力样本 |
| 流式连接被截断 | 499/502 | 优雅下线与网关排空 |
| Embedding 版本串扰 | 检索质量突然下降 | 绑定模型和索引版本 |
模型服务故障还要给第45章网关提供可执行降级信息:当前服务是否可重试、是否存在兼容备用模型、切换后有哪些能力差异、预计多久恢复。普通摘要可以降到小模型,高风险报告可以转异步或人工复核;工具调用格式不兼容的模型不能被随意当 fallback。
服务退役¶
模型目录不能只增不减。旧模型下线前应确认:
- 网关流量已经归零;
- 业务 Agent 不再依赖;
- 评测与 fallback 已迁移;
- 回滚窗口已经结束;
- 历史 Trace 仍能解释旧版本;
- GPU、副本、路由、监控和 Secret 已清理。
退役是生产承诺的结束,不是简单删除 Deployment。 长期低使用率、无人维护且存在等价替代的模型,应进入退役候选;高价值但低频模型则可以改成预热或按需启动,而不是机械清理。
本章小结¶
模型服务层屏蔽 Pod、节点、权重和推理引擎细节,为 Agent 和 LLM 网关提供稳定服务名与契约。在线 LLM、批推理、Embedding 和 Rerank 应按资源画像与发布风险拆服务。KServe 适合承载主 LLM 的 Revision、Canary 和回滚,Triton 更适合 Embedding/Rerank。liveness、readiness 与流量接入必须分开;大模型发布要同时版本化权重、镜像和关键 Runtime 参数。生产发布依赖离线评测、容量压测和线上 Canary 三类证据,回滚必须经过真实演练。服务目录则负责把能力、资源、路由、SLO、成本和退役状态变成可治理资产。
参考文献¶
KServe. (n.d.). Documentation.
BentoML. (n.d.). Documentation.
NVIDIA Triton Inference Server. (n.d.). Documentation.
Ray Serve. (n.d.). Documentation.



