跳转到内容

BentoML — 模型打包部署

是什么

BentoML 是一套把训练好的模型变成”能直接跑的服务镜像”的 Python 框架。日常类比:你做了一份饭(模型),它替你装进便当盒(Bento)——里头连饭、菜(依赖)、筷子(API)一起打包好,外卖小哥(K8s / Serverless)拿走就能配送。

由 Chaoyu Yang 在 2019 年开源,目前 ~7k stars,Apache 2.0 协议。Python 框架,但产物(Bento)是一个自描述目录 + Docker 镜像,下游平台不挑语言。

它解决的核心痛:训练完到上线之间这一段巨复杂——你要写 Flask / FastAPI 包一层、写 Dockerfile、装 GPU 驱动、配 batching、加监控、对接 K8s YAML……一个能调参的算法工程师常常被这段拖死。BentoML 用一个 bentoml build 命令把这些都生成出来。

为什么重要

不用 BentoML,常见情形:

  • 训练用 PyTorch,上线要换 TorchServe;想换 TensorFlow 又得重写 serving 层
  • 推理 GPU 利用率 20%,因为请求一个一个进——不会自己攒批(batching)
  • 上线两天后,发现 Docker 镜像 12GB,因为把整个 conda 环境塞进去了
  • 算法换了 v2,部署不知道怎么灰度——5% 流量切过去要改 K8s YAML

BentoML 用 三层抽象 解掉:

  1. Service:你写一个 Python 类,标注哪些方法是 API(@bentoml.api),框架替你套上 HTTP / gRPC
  2. Bentobentoml build 把 Service 代码 + 模型权重 + Python 依赖 + 系统包打成一个自描述目录——bento.yaml 描述这个工件长啥样
  3. 部署目标:同一个 Bento 可以 bentoml containerize 成 Docker,或 bentoml deploy 推到 BentoCloud / K8s / Lambda

最特色的优化是 adaptive batching——同一时间到的请求自动攒成一批进 GPU,吞吐能涨 5-10 倍,对 LLM / 大视觉模型尤其值钱。

核心要点

Service — 用类型注解描述 API

v1.2 重构后的写法(极简):

import bentoml
from PIL import Image
@bentoml.service(resources={"gpu": 1})
class IrisClassifier:
model = bentoml.models.get("iris:latest")
@bentoml.api
def predict(self, img: Image.Image) -> dict:
return self.model.predict(img)

@bentoml.service 标记这是个服务,参数声明要 1 张 GPU;@bentoml.api 标记入口方法。类型注解Image.Image / dict)会自动转成 OpenAPI schema、HTTP 请求/响应解析、客户端 SDK——一处写,三处用。

Bento — 自描述工件

Terminal window
bentoml build

产物在 ~/bentoml/bentos/iris_classifier/<tag>/,长这样:

├── bento.yaml # 元数据:service 入口、Python 版本、依赖
├── src/ # 你的代码
├── models/ # 模型权重快照
├── env/ # conda / pip / docker 配置
└── README.md

这个目录自带”怎么跑起来”的所有信息——别人 bentoml serve <tag> 能直接起服务,无需读你的代码。

Adaptive batching — GPU 推理特色

@bentoml.api(batchable=True, batch_dim=0)
def predict(self, inputs: list[Image.Image]) -> list[dict]:
return self.model.predict_batch(inputs)

batchable=True 就够了。框架在请求到达时等几毫秒看后续有没有更多请求,凑够就一起送进 GPU。窗口大小、最大 batch 自动调,不用手写批处理循环。

部署目标 — 一份 Bento 多处投放

Terminal window
bentoml containerize iris_classifier:latest # → Docker 镜像
bentoml deploy iris_classifier:latest # → BentoCloud(官方托管)

K8s 的话用 bentoctl 或直接用上面 containerize 出的镜像写 Deployment。Yatai 是早期的 K8s operator,2024 起进维护模式,官方主推 BentoCloud(SaaS)。

实践案例

案例 1:把 sklearn 模型 5 分钟变服务

import bentoml
from sklearn.svm import SVC
# 训练完保存到 BentoML 的本地 model store
clf = SVC().fit(X, y)
bentoml.sklearn.save_model("iris_clf", clf)
# 写 service.py(见上面 Service 例子)
# 启动
# $ bentoml serve service:IrisClassifier

浏览器打开 localhost:3000 有 Swagger UI,直接上传图片就能调用。

案例 2:vLLM / Triton 前端

很多 LLM 部署栈是 BentoML(编排 + API + 监控)+ vLLM(推理引擎)。BentoML 负责”对外那一面”——HTTP API、batching、监控、灰度,vLLM 负责”对内那一面”——把单个请求高效跑在 GPU。两者配套是因为各管一段:BentoML 不写 CUDA kernel,vLLM 不管 K8s YAML。

案例 3:OpenLLM — LLM 专用封装

openllm 是 BentoML 团队的子项目,把”用 BentoML 服务一个 HuggingFace 模型”打成一行命令:

Terminal window
openllm start meta-llama/Llama-3-8B

底层就是自动生成的 BentoML Service。背后引擎可以选 vLLM / TGI / TensorRT-LLM。

踩过的坑

  1. v1.2 API 大改:老代码用 bentoml.Service("name", runners=[...]) 函数式定义;新代码改成 @bentoml.service 类装饰器。混用会乱,迁移时照官方 migration guide 一次改完。

  2. Yatai vs BentoCloud 路线变了:2023 前文档主推 Yatai(自托管 K8s operator),2024 后主推 BentoCloud(SaaS)。自托管选型要确认 Yatai 进维护模式后是否还满足需求,可能要直接写 K8s YAML 或用 KServe。

  3. batching 窗口要调max_latency_ms 默认值小,高吞吐场景要调大;调太大会增加 P99 延迟。压测时盯 GPU 利用率 + P99 一起调。

  4. 依赖锁定不彻底bentofile.yamlpython.requirements_txt 默认不锁版本,构建出来的镜像每次 pip install 可能拉到不同版本。生产建议用 python.lock_packages: true 或自带 lockfile。

  5. 冷启动慢:Bento 镜像首次起服务要 import 模型到 GPU,可能 30-60 秒。Serverless 场景要么用 keep-warm,要么提前 bentoml serve --no-prod 预热。

适用 vs 不适用场景

适用

  • Python 训练栈(PyTorch / sklearn / xgboost / HuggingFace)想快速做”训练 → API”那段
  • 多模型组合服务(一个端点串两三个模型)—— Service 类天然支持
  • 中小团队不想自己写 K8s operator + serving 中间件
  • LLM 部署需要 batching + 多副本 + 监控但不想从零搭

不适用

  • 模型训练阶段(这是 mlflow / pytorch-lightning 的活)
  • 极致延迟(< 5ms)的单模型服务——直接 Triton + C++ 客户端更优
  • 非 Python 训练栈(Java / C++)—— 用 Triton / Seldon
  • 完全 K8s 原生流水线 —— Kubeflow / KServe 链路更顺

学到什么

  1. “打包”是 ML 部署的关键抽象:BentoML 把 mlflow 的 flavor 思想再推一步——不只是统一加载,还把”运行所需的全部环境”封进单个工件。这是 ML 工程化绕不开的一层。

  2. API 描述驱动一切:v1.2 用类型注解作 schema 源——文档、解析、客户端 SDK 一处写处处用。这套思路和 fastapi 完全一致,Python 生态正在收敛到”类型注解 = API 真相”。

  3. 分层是 LLM serving 的现实:编排(BentoML)+ 引擎(vllm)+ 模型(HuggingFace)三层各管一段,没人想做大一统。每层有自己的最优解,组合替代单体。

延伸阅读

  • 官方文档:docs.bentoml.com(v1.2 后的新文档结构清晰)
  • 博客:BentoML Blog 有不少 vLLM / SDXL / Whisper 的部署教程
  • 对比:mlflow —— MLflow 管”训练之后到 Registry”那段,BentoML 管”Registry 之后到上线”那段
  • 对比:fastapi —— FastAPI 是通用 Web 框架,BentoML 是模型专用上层

关联

  • mlflow —— 上游:训练记录 + Registry。Registry 里取出来的模型,正好交给 BentoML 打包
  • vllm —— 下游:BentoML 常作为 vLLM 的 HTTP 前端,负责 batching / API / 监控
  • fastapi —— 同思路:用类型注解驱动 API 描述。BentoML 在 ML 场景做了 FastAPI 的”垂直上层”
  • pytorch —— 上游训练框架,BentoML 原生支持 PyTorch flavor

反向链接

  • fastapi —— FastAPI — 用 Python 类型注解写 API
  • mlflow —— MLflow — 端到端 ML 生命周期
  • pytorch —— PyTorch — 深度学习主流框架
  • pytorch-lightning —— PyTorch Lightning — PyTorch 训练循环抽象
  • triton-2019 —— Triton 2019 — 让 Python 写出贴近 cuBLAS 的 GPU kernel
  • triton-inference-server —— Triton Inference Server — NVIDIA 多框架推理服务化标杆
  • triton-llm —— Triton — 让 Python 程序员也能写出贴近 cuBLAS 的 GPU kernel
  • vllm —— vLLM — 高吞吐 LLM 推理引擎