BentoML: Đóng gói và triển khai mô hình AI/ML thành REST API production-ready trên Linux

Artificial Intelligence tutorial - IT technology blog
Artificial Intelligence tutorial - IT technology blog

Sau khi train xong một mô hình ML, câu hỏi tiếp theo luôn là: làm sao đưa nó ra production? Mình đã trải qua không ít lần phải tự viết Flask API để wrap model, rồi gặp đủ thứ vấn đề: thiếu versioning, khó scale, log lộn xộn. Đến khi team thử BentoML, cách nhìn về ML serving thay đổi hoàn toàn.

Bức tranh tổng quan: Các cách deploy model ML

Thực tế có nhiều cách để expose model ML thành API. Mình chia thành 4 nhóm chính:

  • Tự viết API (Flask/FastAPI) — linh hoạt nhất, nhưng phải tự xử lý mọi thứ từ đầu
  • BentoML — framework chuyên biệt cho ML serving, tích hợp sẵn nhiều tính năng production
  • TorchServe — dành riêng cho PyTorch, tốt nếu bạn all-in PyTorch
  • Triton Inference Server (NVIDIA) — hiệu năng cực cao, nhưng phức tạp và cần GPU cluster

So sánh chi tiết từng approach

Flask/FastAPI tự viết

Đây là cách phổ biến nhất vì ai cũng biết Flask/FastAPI. Bạn load model, viết endpoint, xong. Nhưng vấn đề nằm ở chỗ khác:

  • Không có cơ chế versioning model — khi update model phải deploy lại toàn bộ service
  • Batching phải tự implement — ảnh hưởng lớn đến throughput khi load cao
  • Health check, monitoring phải tự viết thêm
  • Không có chuẩn nào cho cách đóng gói model cùng dependencies

Mình từng maintain một service Flask như vậy suốt 6 tháng. Mỗi lần data scientist update model là cả team phải coordinate thủ công — copy file, restart service, check log. Rất mất thời gian và dễ xảy ra sự cố.

TorchServe

Nếu team chỉ dùng PyTorch và muốn giải pháp official từ Meta, TorchServe là lựa chọn. Nhưng nó khá opinionated — chỉ dành cho PyTorch, cấu hình XML-based (khá cổ), và tài liệu còn thiếu nhiều edge case thực tế.

Triton Inference Server

Khi cần vắt kiệt hiệu năng GPU — dynamic batching, multiple backends (TensorRT, ONNX, TF, PyTorch) — Triton mới xứng đáng bỏ công setup. Vấn đề là learning curve dốc, cấu hình phức tạp, và nếu không có GPU cluster thì rõ ràng là over-engineering.

BentoML

BentoML đứng ở điểm ngọt ngào giữa “tự viết Flask” và “Triton phức tạp”. Framework-agnostic (hỗ trợ sklearn, PyTorch, TF, XGBoost, ONNX…), có versioning tích hợp, adaptive batching, và export Docker tự động. Phù hợp với 80% use case production mà không cần setup phức tạp.

Tại sao chọn BentoML cho production

Sau khi so sánh, team DevOps của mình chốt BentoML vì 3 lý do cụ thể:

  1. Model registry tích hợp sẵn — save/load model có versioning, không cần DVC hay MLflow riêng cho bước này
  2. Bento = artifact đóng gói hoàn chỉnh — model + code + dependencies gói thành một artifact, deploy ở đâu cũng được
  3. Docker image generation tự động — một lệnh ra ngay Docker image production-ready, không cần viết Dockerfile phức tạp

Lợi ích ít được nhắc đến nhất lại quan trọng nhất với team mình: không còn cuộc gọi “model mới để ở đâu, Python version mấy, dependencies cần gì”. Data scientist save model với tag, DevOps lấy tag đó build Docker. Cái quy trình chuẩn hóa này tiết kiệm cho team mình khoảng 2 tiếng mỗi lần release model mới.

Hướng dẫn triển khai BentoML trên Linux

1. Cài đặt

pip install bentoml

# Kiểm tra
bentoml --version

2. Save model vào BentoML model store

Bước đầu tiên là đưa model đã train vào BentoML registry. Ví dụ với scikit-learn:

import bentoml
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris

# Train model (thực tế bạn đã có model rồi)
iris = load_iris()
clf = RandomForestClassifier(n_estimators=100)
clf.fit(iris.data, iris.target)

# Save vào BentoML model store
saved_model = bentoml.sklearn.save_model(
    "iris_classifier",
    clf,
    signatures={"predict": {"batchable": True}},
    metadata={"accuracy": 0.97, "dataset": "iris"}
)

print(f"Model saved: {saved_model.tag}")
# Output: iris_classifier:3mxqpfzbs6tpjuqj

Model được lưu tại ~/bentoml/models/, có versioning tự động qua tag hash — muốn rollback chỉ cần đổi tag.

3. Tạo BentoML Service

Phần cốt lõi — định nghĩa API endpoint và logic xử lý:

# service.py
import bentoml
import numpy as np
from bentoml.io import NumpyNdarray, JSON

# Load model từ registry
iris_runner = bentoml.sklearn.get("iris_classifier:latest").to_runner()

svc = bentoml.Service("iris_classifier_service", runners=[iris_runner])

IRIS_CLASSES = ["setosa", "versicolor", "virginica"]

@svc.api(input=NumpyNdarray(shape=(-1, 4), dtype=np.float32), output=JSON())
async def predict(input_data: np.ndarray):
    batch_pred = await iris_runner.predict.async_run(input_data)
    result = [IRIS_CLASSES[i] for i in batch_pred]
    return {"predictions": result}

4. Test local

# Chạy development server
bentoml serve service:svc --reload

# Test bằng curl (terminal khác)
curl -X POST http://localhost:3000/predict \
  -H "Content-Type: application/json" \
  -d '[[5.1, 3.5, 1.4, 0.2]]'

# Response:
# {"predictions": ["setosa"]}

5. Build Bento artifact

Tạo file bentofile.yaml mô tả toàn bộ dependencies:

service: "service:svc"
labels:
  owner: devops-team
  project: iris-api
include:
  - "service.py"
python:
  packages:
    - scikit-learn
    - numpy
bentoml build

# Output:
# Successfully built Bento(tag="iris_classifier_service:7a3bk2...")
# Bento size: 15.2 MB

6. Deploy lên production với Docker

# Containerize Bento thành Docker image
bentoml containerize iris_classifier_service:latest

# Tag và push lên registry
docker tag iris_classifier_service:latest your-registry.com/iris-api:v1
docker push your-registry.com/iris-api:v1

# Chạy container
docker run -p 3000:3000 iris_classifier_service:latest serve

7. Deploy trực tiếp trên Linux với systemd

Nếu không dùng Docker, tạo systemd service để quản lý process:

# /etc/systemd/system/iris-api.service
[Unit]
Description=BentoML Iris Classifier API
After=network.target

[Service]
User=www-data
WorkingDirectory=/opt/iris-api
ExecStart=/opt/iris-api/venv/bin/bentoml serve iris_classifier_service:latest \
  --host 0.0.0.0 \
  --port 3000 \
  --workers 4
Restart=always
RestartSec=5
Environment=BENTOML_HOME=/opt/iris-api/bentoml

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable iris-api
systemctl start iris-api
systemctl status iris-api

Những điểm cần lưu ý khi chạy production

Adaptive batching

BentoML có cơ chế adaptive batching — tự gom nhiều request nhỏ thành batch để tăng throughput. Cấu hình trong bentofile.yaml:

runners:
  - name: iris_runner
    max_batch_size: 100
    max_latency_ms: 15

Monitoring với Prometheus

BentoML expose sẵn metrics Prometheus tại /metrics. Thêm vào Prometheus config là dùng được ngay:

scrape_configs:
  - job_name: 'bentoml'
    static_configs:
      - targets: ['your-server:3000']

Health check endpoint

Built-in tại /healthz/readyz — dùng được ngay với Kubernetes liveness/readiness probe mà không cần viết thêm gì.

Kết

Mình đã migrate 3 service ML từ Flask tự viết sang BentoML. Thời gian để đưa một model mới lên production — từ lúc data scientist bàn giao đến khi API chạy được — giảm từ khoảng 3 tiếng xuống còn 20–30 phút, chủ yếu là thời gian build Docker image. Model registry cũng giúp rollback dễ dàng khi model mới có vấn đề.

BentoML không phải silver bullet. Cần tối đa hiệu năng GPU với TensorRT thì Triton vẫn là lựa chọn tốt hơn. Nhưng với phần lớn team ML/DevOps, BentoML là điểm cân bằng thực tế giữa tốc độ triển khai và độ ổn định production. Thử ngay với pip install bentoml scikit-learn và chạy theo các bước trên.

Share: