Đo impact khi upgrade model đồng loạt — playbook causal inference

Đo impact khi upgrade model đồng loạt — playbook causal inference

Provider nâng model cho tất cả cùng lúc, metric tăng — nhưng chứng minh nhân quả thế nào khi không có nhóm đối chứng? Playbook synthetic control cho team AI product.

Metric tăng sau khi upgrade model — nhưng bạn có dám nói chắc đó là nhờ model mới?

Sáng thứ Hai, infra push Claude 4.6 lên toàn bộ 30 workspace production. Thứ Sáu, task completion nhảy lên rõ rệt. PM ghi vào slide: "Model mới cải thiện completion." Nhưng cùng tuần đó, UX team ship flow onboarding mới và một khách enterprise vừa xong training nội bộ. Con số kia thuộc về ai?

Đây là bài toán đo lường mà mọi team dùng LLM API đều vấp — vì provider upgrade model cho tất cả cùng lúc, xóa sạch khả năng so sánh kiểu A/B truyền thống.

Bài này giải quyết gì

Khi không có holdout group (nhóm giữ lại chạy version cũ), so sánh before/after bị nhiễu bởi tất cả những gì thay đổi cùng thời điểm. Trong causal inference (suy luận nhân quả), đây gọi là Global Rollout Problem — triển khai đồng loạt xóa luôn nhóm đối chứng.

Playbook này đưa bạn qua synthetic control — phương pháp dựng lại nhóm đối chứng từ dữ liệu có sẵn — để trả lời câu hỏi: "Nếu không upgrade, metric lẽ ra đi theo hướng nào?" Khoảng cách giữa thực tế và bản dựng lại đó chính là causal effect ước lượng.

Trước khi mở notebook — checklist đầu vào

Nếu thiếu donor pool — toàn bộ hệ thống upgrade cùng đêm — synthetic control không áp dụng được. Lúc này xét regression discontinuity (hồi quy gián đoạn): nếu hệ thống có threshold routing (ngưỡng confidence score quyết định model nào xử lý query), ngưỡng đó chính là thí nghiệm tự nhiên.

Bốn bước dựng synthetic control

1 — Xác định treated unit và donor pool

Kịch bản thực tế: Team bạn vận hành SaaS 30 workspace. 20 workspace upgrade model ngày 5/5, 10 workspace còn lại upgrade ngày 12/5. Tuần 5/5–11/5, 10 workspace kia vẫn chạy version cũ — đó là donor pool tự nhiên.

2 — Tìm trọng số khớp giai đoạn pre-treatment

Dùng scipy.optimize.minimize tìm bộ trọng số w cho donor pool sao cho weighted average metric của donor khớp metric treated unit trước thời điểm upgrade.

from scipy.optimize import minimize
import numpy as np

def objective(weights, treated_pre, donor_pre):
    synthetic = donor_pre @ weights
    return np.sum((treated_pre - synthetic) ** 2)

cons = {'type': 'eq', 'fun': lambda w: np.sum(w) - 1}
bounds = [(0, 1)] * n_donors
result = minimize(objective, x0, args=(treated_pre, donor_pre),
                  bounds=bounds, constraints=cons)

Nếu RMSE pre-treatment fit cao → donor pool không phù hợp, kết quả sẽ không đáng tin.

3 — Ước lượng causal effect

synthetic_post = donor_post @ result.x
causal_effect = treated_post - synthetic_post

Con số này là impact ước lượng, đã loại trừ trend chung mà mọi workspace đều chịu.

4 — Validate bằng placebo permutation

Giả vờ một donor unit là treated (dù nó không bị upgrade), chạy lại toàn bộ. Lặp cho tất cả donor → bạn có phân phối placebo effects. Effect thật phải nằm ngoài phân phối này mới có ý nghĩa.

Bootstrap thêm confidence interval (khoảng tin cậy) 95% để báo cáo kèm range thay vì chỉ một con số trần.

Những chỗ hay vấp

Donor pool quá nhỏ hoặc quá khác biệt. Giả sử team chỉ có 3 workspace chưa upgrade, cả 3 đều là sandbox nội bộ — ít user, pattern khác hẳn production. Synthetic control sẽ fit noise thay vì signal. Như một tam tấu cố tái hiện bản giao hưởng đầy đủ — có âm thanh đấy, nhưng thiếu quá nhiều bè.

Metric quá noisy. Revenue per user dao động mạnh theo ngày, fit sẽ kém. Task completion rate hoặc latency p50 ổn định hơn. Ưu tiên metric ít variance trong giai đoạn pre-treatment.

Confounding event trùng thời điểm. Marketing chạy campaign lớn cùng tuần upgrade → metric tăng vì campaign, không phải model. Synthetic control giảm thiểu vấn đề này NẾU campaign tác động cả donor pool lẫn treated. Nếu chỉ nhắm đúng treated → phải ghi rõ limitation trong report.

Ví dụ cụ thể: Một team edtech ở Hà Nội kể rằng họ chạy synthetic control sau khi upgrade model xử lý bài tập. Kết quả "effect" ra âm — metric giảm. Hoảng hốt mất nửa ngày debug, cuối cùng phát hiện donor pool chứa workspace QA đang chạy load test, metric ảo cao. Loại workspace QA ra, effect trở lại dương và ổn định. Bài học: donor pool cần cùng "nhịp sống" với treated unit.

Hành động sprint này

  1. Bắt đầu log metric hàng ngày theo workspace/segment ngay bây giờ. Đây là pre-treatment data — bạn cần nó TRƯỚC KHI upgrade xảy ra. Không log sớm thì lúc cần sẽ trắng tay.
  2. Lần upgrade tới: Xin infra delay rollout 5–7 ngày cho 20–30% workspace. Không phải A/B test chính thức, chỉ là staggered rollout (triển khai so le) — đủ tạo donor pool tự nhiên.
  3. Sau upgrade: Chạy notebook synthetic control, validate bằng placebo, báo cáo kèm confidence interval. Khi leadership hỏi "tăng vì đâu", bạn có câu trả lời không dựa vào cảm tính.

Nếu conductor đổi bản phối qua đêm mà không giữ bản thu version trước, sẽ không ai biết phần nào thật sự hay hơn. Staggered rollout chính là bản thu đó — synthetic control là cách bạn chấm điểm sự khác biệt.

---

Bụi Wire — nghiện đọc release notes lúc 2 giờ sáng

Nguồn tham khảo