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 用 三层抽象 解掉:
- Service:你写一个 Python 类,标注哪些方法是 API(
@bentoml.api),框架替你套上 HTTP / gRPC - Bento:
bentoml build把 Service 代码 + 模型权重 + Python 依赖 + 系统包打成一个自描述目录——bento.yaml描述这个工件长啥样 - 部署目标:同一个 Bento 可以
bentoml containerize成 Docker,或bentoml deploy推到 BentoCloud / K8s / Lambda
最特色的优化是 adaptive batching——同一时间到的请求自动攒成一批进 GPU,吞吐能涨 5-10 倍,对 LLM / 大视觉模型尤其值钱。
核心要点
Service — 用类型注解描述 API
v1.2 重构后的写法(极简):
import bentomlfrom 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 — 自描述工件
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 多处投放
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 bentomlfrom sklearn.svm import SVC
# 训练完保存到 BentoML 的本地 model storeclf = 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 模型”打成一行命令:
openllm start meta-llama/Llama-3-8B底层就是自动生成的 BentoML Service。背后引擎可以选 vLLM / TGI / TensorRT-LLM。
踩过的坑
-
v1.2 API 大改:老代码用
bentoml.Service("name", runners=[...])函数式定义;新代码改成@bentoml.service类装饰器。混用会乱,迁移时照官方 migration guide 一次改完。 -
Yatai vs BentoCloud 路线变了:2023 前文档主推 Yatai(自托管 K8s operator),2024 后主推 BentoCloud(SaaS)。自托管选型要确认 Yatai 进维护模式后是否还满足需求,可能要直接写 K8s YAML 或用 KServe。
-
batching 窗口要调:
max_latency_ms默认值小,高吞吐场景要调大;调太大会增加 P99 延迟。压测时盯 GPU 利用率 + P99 一起调。 -
依赖锁定不彻底:
bentofile.yaml里python.requirements_txt默认不锁版本,构建出来的镜像每次 pip install 可能拉到不同版本。生产建议用python.lock_packages: true或自带 lockfile。 -
冷启动慢: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 链路更顺
学到什么
-
“打包”是 ML 部署的关键抽象:BentoML 把 mlflow 的 flavor 思想再推一步——不只是统一加载,还把”运行所需的全部环境”封进单个工件。这是 ML 工程化绕不开的一层。
-
API 描述驱动一切:v1.2 用类型注解作 schema 源——文档、解析、客户端 SDK 一处写处处用。这套思路和 fastapi 完全一致,Python 生态正在收敛到”类型注解 = API 真相”。
-
分层是 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 推理引擎