Model sai mà không báo lỗi: tự dựng hệ thống bắt data drift bằng Prometheus và Grafana
Model vẫn trả HTTP 200 chỉ sau vài mili giây, kể cả khi dữ liệu khách hàng đã khác hẳn dữ liệu nó từng học. Hướng dẫn này giúp bạn dựng một hệ thống nhận ra chuyện đó trước khi khách hàng phát hiện.
- 1Service phục vụ modelGhi log dự đoán, đếm request bằng Counter, đo latency bằng Histogram trên cổng 8000
- 2Job drift (Evidently)Đọc log, so với tập tham chiếu, ghi điểm drift theo feature vào Gauge
- 3Endpoint riêng của job driftCung cấp điểm drift qua HTTP trên cổng 8001 để Prometheus đến lấy
- 4Prometheus scrapeKéo metric từ cả hai target theo scrape_interval, lưu time series cho PromQL
- 5Grafana và cảnh báoVẽ điểm drift theo thời gian, báo qua email/Slack/SMS khi vượt ngưỡng
Mỗi công cụ làm đúng một việc: Evidently tính điểm drift, Prometheus lưu metric, Grafana vẽ biểu đồ và gửi cảnh báo.
Đồ hoạ: FDE Times
Tóm tắt nhanh
- Model hỏng vì drift thì không báo lỗi, nên bạn phải tự đo phân bố dữ liệu và đưa con số đó vào hệ thống giám sát.
- Evidently tính điểm drift và cung cấp qua endpoint riêng, Prometheus định kỳ kéo metric về qua HTTP, Grafana vẽ dashboard và gửi cảnh báo khi vượt ngưỡng.
- Điểm drift phải dùng Gauge, đừng dùng Counter. Ngưỡng cảnh báo cũng phải hiệu chỉnh theo dữ liệu thật, đừng chép từ tutorial.
Một model chấm điểm gian lận có thể trả kết quả trong vài mili giây, trả HTTP 200 cho mọi request và không ghi dòng lỗi nào vào log. Dù vậy nó vẫn có thể đang sai. Khi dữ liệu production đã khác đáng kể so với dữ liệu huấn luyện, tức là data drift, model không biết để báo.
Chỉ một hệ thống được dựng riêng để đo phân bố dữ liệu mới nhận ra chuyện đó.
Với một FDE, chuyện này nằm ngay trong việc hằng ngày. Bạn deploy model lên hạ tầng của khách hàng, và vài tuần sau sẽ có người hỏi: “Sao dạo này model kém thế?” Nếu lúc đó bạn đã có sẵn một dashboard chỉ ra feature nào bắt đầu lệch từ ngày nào, bạn đang trả lời bằng dữ liệu. Nếu chưa có, bạn chỉ có thể đoán.
Bài này dựng đúng hệ thống đó với ba công cụ. Evidently thu thập và tính metric, Prometheus lưu metric, còn Grafana hiển thị và cảnh báo.
Bạn sẽ dựng gì, và cần chuẩn bị gì?
Kết quả cuối cùng gồm hai tiến trình Python. Service phục vụ model cung cấp metric về số dự đoán và latency qua một endpoint HTTP. Một job drift chạy định kỳ cung cấp điểm drift qua endpoint thứ hai.
Prometheus định kỳ đến cả hai endpoint để kéo số liệu về, Grafana có một panel vẽ điểm drift của từng feature theo thời gian, và bạn nhận cảnh báo khi điểm vượt ngưỡng.
Bạn cần Python 3, một model đã huấn luyện (model phân loại scikit-learn nào cũng được), Prometheus và Grafana cài trên máy hoặc chạy bằng container. Bạn cũng cần một tập dữ liệu tham chiếu, thường là chính dữ liệu đã dùng để huấn luyện. Thiếu tập này thì không có gì để so.
Có một điểm kiến trúc cần nắm trước khi viết code. Prometheus thu thập time series theo mô hình pull qua HTTP: mỗi tiến trình chỉ cần cung cấp metric qua endpoint, còn Prometheus tự tìm đến để lấy. Vì thế bạn không phải viết đoạn code nào để đẩy metric đi đâu cả.
Bước 1: chọn đúng kiểu metric cho từng câu hỏi
Prometheus cung cấp client library để instrument code ứng dụng, và service phục vụ model cũng chỉ là một ứng dụng. Muốn giám sát model, bạn cần trả lời ba câu hỏi, và mỗi câu hỏi hợp với một kiểu metric.
| Câu hỏi | Kiểu metric | Lý do |
|---|---|---|
| Model đã trả bao nhiêu dự đoán? | Counter | Chỉ tăng đơn điệu, hợp với việc đếm |
| Suy luận mất bao lâu? | Histogram | Đếm từng lần đo vào các bucket cấu hình được |
| Dữ liệu đang lệch bao nhiêu? | Gauge | Giá trị có thể tăng hoặc giảm tùy ý |
Hai câu hỏi đầu được trả lời ngay trong service phục vụ model. Dưới đây là phác thảo tối giản dùng client library Python. Tên hàm có thể khác nhau giữa các phiên bản, nên bạn hãy đối chiếu với docs của bản đang cài.
# serve.py — phác thảo, kiểm tra lại API trong docs client library
from prometheus_client import Counter, Histogram, start_http_server
PREDICTIONS = Counter("predictions_total", "Số dự đoán đã trả về")
LATENCY = Histogram("inference_seconds", "Thời gian suy luận")
start_http_server(8000)
def predict(x):
with LATENCY.time():
y = model.predict(x)
PREDICTIONS.inc()
return y
Kiểm tra: gửi vài request vào hàm predict, rồi mở localhost:8000/metrics trên trình duyệt. Bạn phải thấy predictions_total tăng sau mỗi request và các dòng bucket của inference_seconds.
Bước 2: tính drift theo lô, trong một tiến trình có endpoint riêng
Drift là đặc tính của một phân bố, mà một request đơn lẻ thì không có phân bố. Theo kiến trúc Evidently mô tả, Evidently đọc log của model, so dữ liệu gần đây với tập tham chiếu, rồi cung cấp một endpoint để Prometheus vào lấy.
Chi tiết “endpoint riêng” quan trọng hơn vẻ ngoài của nó. Gauge nằm trong bộ nhớ của tiến trình đã tạo ra nó. Một job chạy định kỳ ở tiến trình khác không thể ghi vào Gauge của service phục vụ model. Vì thế job drift phải tự tạo Gauge và tự cung cấp metric trên một cổng khác, ở đây là 8001.
Bạn cũng có thể chạy phép tính drift như một luồng nền bên trong chính service, nhưng tách riêng giúp phép tính nặng không làm chậm suy luận.
# drift_job.py — giả mã. compute_drift() đại diện cho Report Data Drift của Evidently;
# API Evidently thay đổi theo phiên bản, xem docs hiện hành.
from prometheus_client import Gauge, start_http_server
DRIFT = Gauge("feature_drift_score", "Điểm drift theo feature", ["feature"])
start_http_server(8001)
while True:
current_window = load_recent_prediction_log() # đọc log của service
for feature in FEATURES:
score = compute_drift(reference[feature], current_window[feature])
DRIFT.labels(feature=feature).set(score)
sleep_until_next_run() # ví dụ: mỗi giờ một lần
Thử hình dung một model gian lận có 20 feature. Mỗi feature là một giá trị nhãn của cùng một Gauge, nên bạn có 20 time series. Evidently cho biết ví dụ Data Drift này áp dụng được theo cùng cách cho các Report khác, nên sau này bạn có thể thêm metric về chất lượng dữ liệu mà không phải đổi kiến trúc.
Kiểm tra: sau lượt chạy đầu tiên, localhost:8001/metrics phải có 20 dòng feature_drift_score{feature="..."}, mỗi dòng mang một giá trị.
Bước 3: cấu hình Prometheus để kéo metric về
Trong file cấu hình, scrape_interval quy định Prometheus kéo metric về thường xuyên đến mức nào. Vì có hai tiến trình, bạn cần khai báo hai target. File dưới đây đã được rút gọn để minh họa.
# prometheus.yml (rút gọn)
global:
scrape_interval: 15s
scrape_configs:
- job_name: "fraud-model"
static_configs:
- targets: ["localhost:8000"]
- job_name: "drift-monitor"
static_configs:
- targets: ["localhost:8001"]
Tính thử một chút. Với chu kỳ 15 giây, mỗi time series nhận 240 mẫu mỗi giờ. Nhưng nếu job drift chỉ chạy mỗi giờ một lần, 239 mẫu trong số đó lặp lại đúng một giá trị. Điều này không sai, chỉ là bạn cần hiểu khi đọc biểu đồ: đường drift đi theo bậc thang theo chu kỳ của job, không theo chu kỳ scrape.
Khởi động Prometheus với file này (trang Getting Started có lệnh đúng cho bản bạn cài), mở giao diện web và gõ truy vấn PromQL đơn giản nhất là tên metric feature_drift_score.
Kiểm tra: trang targets phải báo cả fraud-model lẫn drift-monitor đang hoạt động. Nếu thiếu một job, thường là sai port hoặc tiến trình đó chưa chạy.
Bước 4: dựng panel và cảnh báo trên Grafana
Trong Grafana, thêm Prometheus làm data source, tạo một panel time series và dùng truy vấn feature_drift_score. Mỗi feature sẽ thành một đường riêng. Đây là biểu đồ bạn sẽ mở ra khi khách hàng hỏi “model có vấn đề gì không”.
Tiếp theo là cảnh báo. Grafana cho phép đặt cảnh báo qua email, Slack hoặc SMS theo ngưỡng tùy chỉnh. Tutorial của DataCamp dùng ngưỡng 0.026, nghĩa là hệ thống gửi cảnh báo khi điểm drift vượt mức đó. Để thử, bạn có thể viết điều kiện kiểu feature_drift_score > 0.026.
Kiểm tra: lấy dữ liệu test, nhân giá trị của một feature lên gấp đôi rồi cho vào cửa sổ dữ liệu hiện tại. Đường của feature đó phải vọt lên và cảnh báo phải đến kênh bạn đã cấu hình.
Ngưỡng đúng đến từ dữ liệu của chính khách hàng
Cách an toàn là cho hệ thống chạy ở chế độ chỉ quan sát vài tuần, trong lúc model đang chạy tốt, rồi đặt ngưỡng từ chính những con số đó. Thử hình dung job drift chạy mỗi giờ trong 4 tuần: mỗi feature có 4 × 7 × 24 = 672 điểm baseline.
Sắp xếp 672 điểm đó và lấy percentile thứ 99. Vì 1% của 672 là 6,72, giá trị này nằm quanh điểm cao thứ bảy. Giả sử nó là 0.04, nghĩa là 99% số giờ bình thường có điểm drift không vượt 0.04.
Bạn có thể đặt ngưỡng cao hơn một khoảng, chẳng hạn 0.05, để chỉ những lần lệch thật sự bất thường mới gây cảnh báo. Các con số ở đây là giả định, còn cách tính thì áp dụng được cho dữ liệu thật.
Nên tính riêng cho từng feature quan trọng, vì có feature tự nhiên dao động mạnh hơn feature khác. Với PromQL, bạn có thể dùng quantile_over_time trên khoảng thời gian baseline. Hãy kiểm tra cú pháp trong docs Prometheus trước khi dùng.
Những lỗi làm hệ thống giám sát vô dụng
Lỗi đầu tiên là dùng Counter cho điểm drift. Counter chỉ tăng, nên khi drift giảm thì metric không phản ánh được, và biểu đồ của bạn sẽ báo sai. Mọi giá trị biểu thị “trạng thái hiện tại”, như điểm drift hay độ chính xác, đều phải dùng Gauge.
Lỗi thứ hai là chép nguyên ngưỡng từ tutorial. Ngưỡng quá thấp làm Slack của khách hàng ngập cảnh báo, và sau một tuần không ai đọc nữa. Phép tính percentile ở phần trên tốn vài dòng code nhưng giúp bạn tránh được lỗi này.
Lỗi thứ ba là gắn nhãn theo những thứ có rất nhiều giá trị, chẳng hạn mã khách hàng. Như ở bước 2, mỗi giá trị nhãn cho ra một time series riêng: 20 feature là 20 đường dễ đọc, còn nhãn theo từng user sẽ làm số time series phình ra theo số user.
Nên giữ nhãn ở những chiều có ít giá trị và biết trước, rồi kiểm tra kỹ docs của Prometheus trước khi thêm nhãn mới.
Lỗi cuối cùng ít người để ý: tập tham chiếu không còn khớp với model đang chạy, vì model đã được huấn luyện lại mà tập tham chiếu vẫn để nguyên.
Kỹ năng này xuất hiện ở đâu khi làm cho khách hàng?
Khi làm cho khách hàng, phần khó nhất thường không nằm ở code. Bạn phải ngồi với người làm nghiệp vụ để thống nhất ba điều: feature nào quan trọng đến mức cần cảnh báo riêng, ai nhận cảnh báo, và khi cảnh báo bật thì làm gì tiếp. Nếu không có bước xử lý sau cảnh báo, dashboard chỉ để trang trí.
Vì thế, buổi đầu tiên ở khách hàng, bạn nên hỏi họ đang dùng Prometheus, Grafana hay hệ thống giám sát nào khác. Gắn metric của model vào hạ tầng họ đã có thường dễ được chấp nhận hơn nhiều so với đề xuất một stack mới.
Khi đọc job description FDE hoặc MLOps, hãy để ý những cụm như “model monitoring”, “observability” hay “drift detection”. Trong CV, câu “dựng Prometheus và Grafana” không nói lên nhiều. Câu “phát hiện drift trên 20 feature, cảnh báo qua Slack, ngưỡng lấy từ percentile 99 của dữ liệu baseline” cho người tuyển biết bạn hiểu vấn đề.
Model nào được deploy rồi cũng sẽ có lúc chạy sai. Khác biệt là bạn phát hiện ra nhờ một cảnh báo lúc dữ liệu vừa bắt đầu lệch, hay phải đợi đến khi khách hàng gọi điện báo.