Skip to content
Charles Shao
Go back

推理服务业界落地:从训练产物到推理服务怎么发布

Updated:
–views

落地不是再选一个框架。训练刚结束时,手里是带版本的权重;线上要的是一份热的推理服务——深度模型和 LLM 多半在 GPU 上,树模型、逻辑回归、中小 ONNX 也经常跑在 CPU 上。调用方用稳定的协议来打。中间若靠 scp、人手 kubectl apply、改完 Ingress 才切流量,换版节奏就会卡在「谁有权限登集群」。业界把这件事收成一条发布链路:产物进仓库,期望状态进 Git,集群对账,服务框架加载并攒批,网关和指标把灰度跑完。硬件是池子里的机型,不是另一套发版。

换版的最小动作,应当是改一个 URI。 镜像、协议、调用方客户端都不该跟着动。

Table of contents

Open Table of contents

一、先把发布链路搭起来

生产里最常见、也最经得起换版的一条链是:

发布链路全景。从左到右六段:注册表(MLflow / 内部,打版本记指标)→ 对象存储(S3 / GCS / OSS,权重与仓库目录)→ GitOps(ArgoCD / Flux,声明要上哪一版)→ 编排(KServe 或 Deployment,副本灰度探针)→ 服务框架(Triton / vLLM / ORT,加载攒批)→ 网关与监控(Istio + 指标)。箭头依次为推权重、改 URI、对账、拉起、观测。底部注明镜像不装权重,缺一环会退回人手发版。

按实施顺序看每一环在干什么。缺一环,不会立刻挂,但会退回「有人记得怎么发」:

环节落地时做什么缺了之后换版会怎样
注册表每次训练产物打版本,记下指标和来源线上说不清跑的是哪一版,回滚靠猜
对象存储按服务框架要求的目录放权重(Triton 还要 config.pbtxt)节点本地拷贝,发版变成 scp
GitOps集群只认 Git 里的声明,例如 storageUri人手 apply,环境和版本漂移
编排把声明变成副本、探针、流量切分扩缩和灰度各写一套,和业务发布对不齐
服务框架从仓库加载、动态批处理、多模型共资源硬件吃不满,或每个模型各起各的进程
网关与指标统一入口;看利用率、实际 batch、排队、P99、降级灰度靠改 DNS,调参靠感觉

训练侧产出之后,标准动作是:按仓库目录推进对象存储 → 注册表打 ctr-ranker/v4 → Git 里把 URI 指到新路径 → ArgoCD 同步 → 小流量金丝雀。权重不要打进镜像:镜像只装服务框架和运行环境,模型换版才不会变成一次镜像构建。

编排这一环可以是 KServe,也可以是已有的 K8s / 内部 PaaS。链路形状不变,变的是「谁来对账 Git 里的那份声明」。


二、先定落地形态,再买组件

同一条链路,团队成熟度不同,会落成不同形态。它们不是互斥标准,而是「你现在处在哪一档」。先问平台已经有什么,再决定 KServe 要不要上。

已经有 Kubeflow(或准备上 MLOps 平台)。 训练、Pipeline、Notebook 已经在同一套 RBAC 和命名空间里,KServe 就是它的服务组件,predictor 用 Triton(一次前向)或 vLLM(LLM)。算法从训练作业注册模型,到线上是同一条产品通路。适合模型种类多、要自助上线的团队。Kubeflow 本身重,服务就一两个、平台还没人养的,不要为了「全家桶」先背起来。

特征逻辑经常变,模型图要稳住。 用 KServe 把前处理 / 后处理放 Transformer(Python:拼特征、tokenize、截断),推理放 Predictor(Triton 挂 TensorRT、ONNX,GPU 或 CPU 后端)。对外仍是一个端点,两段可以各自扩缩:Transformer 吃 CPU,Predictor 按模型走 GPU 或 CPU。广告 / 推荐的特征拼装特别适合。

前处理与推理拆开。调用方(Bidder / 网关)把请求交给 Transformer(拼特征 / tokenize,吃 CPU,可单独扩),再把 tensor 交给 Predictor(Triton + TensorRT / ONNX,GPU 或 CPU,可单独扩),响应仍走同一个 V2 端点。底部注明特征加字段不必重编 engine;也可用 Triton ensemble / BLS 整条编进 Predictor 侧。

若前后处理能用 Triton 的 ensemble / BLS 表达,也可以整条编进 Predictor 侧,少一次 Pod 内跳转,灵活度会差一些。

微服务发布体系已经成熟。 发现、灰度、限流、降级是公司标准,再套 KServe(以及它常带的 Knative / Istio)等于两套流量规则。这时用 Deployment 跑 Triton 或 ONNX Runtime,扩缩和灰度接自研平台,模型仓库仍走对象存储。广告工程团队很常见。这不是落后,是编排能力已经有了,不必再买一层。

多种模型要共用上线流程。 注册表 → 存储 → GitOps 可以共用。LLM 把 predictor 换成 vLLM;深度 CTR 用 Triton 挂 GPU;树模型 / LR 用 ONNX Runtime、Triton CPU 或 JPMML。不要为每类模型另起一套发版。

你现在的情况落地形态
有 Kubeflow,要自助上线Kubeflow + KServe + Triton / vLLM
特征常变,模型要独立发KServe:Transformer + Predictor(Triton)
已有 PaaS / 服务网格裸 K8s Deployment + Triton / ORT
LLM、深度 CTR、CPU 粗排同一套发布同一条 GitOps,换 runtime 和机型

三、实施按四条工作流推进

组件名单定了之后,落地是四条并行的工作流。缺哪条,链路上对应的那一环就会在发版时露馅。

1. 产物:版本在注册表,字节在对象存储

镜像只装服务框架和依赖(Triton / vLLM / ONNX Runtime,Java 侧则是 JPMML),不装权重。权重按服务框架的仓库规范进对象存储,例如 Triton 的 model_name/version/config.pbtxt + engine。注册表记下「v4 对应哪条路径、离线指标是多少、从哪次训练来」。回滚 = 把 URI 指回上一版路径,而不是翻备份盘。

上一篇里的格式选择在这里落地:深度一次前向常用 TensorRT engine 或 ONNX(GPU);树模型 / LR 常用 ONNX 或 PMML 跑在 CPU 上;LLM 常用 safetensors。仓库目录是服务框架的契约,换版只换目录,不换契约。

2. 发布:Git 是唯一的期望状态

换版路径固定写成:

声明式换版流程。训练产出 ctr-ranker/v4 → 推对象存储 …/v4 → Git 改 storageUri → ArgoCD 同步 → 金丝雀 10% → 按 P99 与线上 CTR 放大或回滚。底部红色虚线从「放大或回滚」折回训练产出,标注指标变差则指回上一版 URI。

广告 / 推荐经常天级甚至小时级换模型,登机器改配置跟不上。金丝雀必须看两套数:服务健康(错误率、超时、P99),以及模型有没有变差(线上 CTR / AUC 偏移、降级次数)。进程没挂,不等于这个 URI 能上全量。

3. 容量:推理池要热着,GPU 和 CPU 分开规划

深度模型和 LLM 吃 GPU:卡贵,不要一模型一张卡。服务框架里多模型共卡(Triton 的实例数、显存上限),再靠 K8s 把一张卡切开(MIG / MPS / time-slicing)。长尾吃切片;主力深度 CTR 往往独占一张卡保延迟。副本按并发或队列扩,不要按 CPU——GPU 打满时 CPU 可以仍然很低。

树模型、逻辑回归、中小 ONNX 经常跑在 CPU 上:机型按核数和内存规划,HPA 可以看 CPU 利用率。不要把它们和 vLLM 挤在同一张 GPU 节点上「顺便跑」——调度、隔离和成本账都会乱。Java 风控 / 粗排用 JPMML 吃 PMML,也是这条 CPU 路径,发布链路(注册表 → 存储 → Git)仍然适用。

延迟敏感的在线服务无论 GPU 还是 CPU,都留最小热副本(minReplicas ≥ 1)。缩到零对长尾、离线打分很香,但加载可能要几秒到几十秒,第一次请求会打崩 P99。上一篇里「同可用区内网 RPC + 超时降级」能成立,前提就是推理池一直是热的。调用方和推理池放同一可用区,是容量规划的一部分,不是网络优化彩蛋。

4. 路径与观测:协议稳定,数字能反过来调参

调用方(Bidder、对话网关)只认一种协议:一次前向用 Open Inference Protocol V2(或内部 gRPC),LLM 用兼容的流式 API。换引擎不该逼客户端升级。

前处理和推理能否拆开,决定发版节奏:特征加一个字段,不应迫使 TensorRT engine 重编。拆到 Transformer 或业务侧拼特征,CPU / GPU 也能分开扩。出了数值问题,才能分清是前处理没对齐,还是模型本身漂了。

指标至少要能回答三句话:硬件忙不忙(GPU 利用率 / 显存,或 CPU 与内存),柜台堵不堵(实际 batch、排队),用户侧崩没崩(P99、超时、降级)。攒批窗口和 HPA 阈值靠这组数调,不是靠感觉。


四、什么时候不必上 KServe

KServe 不是默认项。下面几种情况,裸 K8s 跑 Triton、vLLM 或 ONNX Runtime 通常更省事:

一句话:平台还没有「模型上线」这条产品能力时,KServe 能买来;已经有了,就把服务框架当成普通微服务接进去。


五、三套参考实现

骨架都是「注册表 → 存储 → Git 声明 → 推理池 → 网关 / 监控」。predictor、GPU 还是 CPU、要不要 KServe,按场景换,不要为了标准架构强行对齐。

LLM 对话。

LLM 对话参考实现。注册表中的 safetensors → 对象存储权重目录 → Git 声明 runtime 为 vLLM → KServe 管热副本与灰度 → vLLM 进程内完成 KV、连续批处理、兼容 API 与流式输出。底部注明按 KV 容量扩、不要缩到零。

注册表里的 safetensors 进对象存储;Git 里声明 runtime 为 vLLM;KServe(或现有平台)管热副本和灰度;网关暴露兼容 API。加机器按 KV 是否还够,不要按 QPS 乘平均耗时。首 token 延迟敏感,同样不要缩到零。不到瓶颈,不必换成 TensorRT-LLM。

广告深度 CTR / CVR。

广告深度 CTR 参考实现。竞价请求进入 Bidder(同区域同 AZ),经 gRPC 打到 Triton(排队、攒批、超时降级),再由 TensorRT / ONNX 在 GPU 上前向;编排用 K8s 或 KServe,minReplicas ≥ 1。底部注明必须独立成服务;粗排走 CPU。

多数大厂用裸 K8s + Triton 接自研发布;中台化团队用 KServe。Bidder 同可用区 gRPC 调用;最小副本常驻;换版改 URI,金丝雀同时看 P99 和线上 CTR;超时退回粗排(见竞价链路)。

CPU 上的粗排 / 树模型 / LR。

CPU 粗排参考实现。注册表中的 ONNX / PMML → 对象存储模型目录 → Git 改 URI → CPU 推理(ONNX Runtime / Triton CPU 或 JPMML)→ 调用方(Bidder 同 AZ,模型很轻也可嵌进进程)。底部注明发布链路与 GPU 相同,不要把 LR 塞进 GPU 节点。

发布链路不变,换的是机型和产物:ONNX 走 ONNX Runtime 或 Triton 的 CPU 后端;PMML 走 JPMML。可以独立成 CPU 推理服务(和 Bidder 同 AZ),模型很轻时也可以嵌进 Bidder 进程。不要为了「也有一条推理服务」把 LR 塞进 GPU 池。


一句话总结

落地是把训练产物声明式地推到推理服务上。 先搭发布链路:版本在注册表,字节在对象存储,期望状态在 Git,集群对账,服务框架加载并攒批。深度模型和 LLM 进 GPU 池,树模型 / LR / 中小 ONNX 进 CPU 池,发版方式相同。形态按平台已有能力选——有 MLOps 就用 KServe,有 PaaS 就把推理进程当普通微服务。

实施时四条工作流一起走:产物不进镜像、换版只改 URI、在线服务留热副本并同可用区、协议和指标能反过来调参。KServe 只在还缺「模型上线」能力时值得买。


–views
Share this post on:

Previous Post
VAST、MRAID与端上引擎:广告渲染协议解析
Next Post
推理运行时与服务框架选型:运行环境、服务框架、编排平台怎么分层