🎯 目標
模型(與規則)可版本化、可切換、可灰度(百分比分流/A/B)
推論與業務指標可觀測(metrics + 日誌樣本)
內建回滾與快取失效機制,確保 M4 Air 上穩定
🛠 工作項目
1) 模型版本與校驗
檔案命名:models/reco_ranker-1.0.0.onnx + feature_schema-1.0.0.json + SHA256
啟動檢查:
讀 application.yml:model.version=1.0.0、model.path=...
校驗 feature_schema 欄位順序與類型、SHA256 相符才載入;否則自動退回 rule 模式
Actuator info 暴露:
model.version、schema.version、model.sha256、loaded=true/false
2) 配置式切換與灰度
ScoringStrategy 介面保留(rule / ml)
@ConditionalOnProperty("scoring.mode")
灰度策略(簡易):
scoring.gray.enabled=true
scoring.gray.mlPercent=20 → 20% 請求用 ML,其餘用 rule
or scoring.mode=ab + X-Exp-Bucket header 控制
回傳 header(便於對照):X-Scoring-Mode: ml|rule
3) 線上評估與指標
Micrometer 計量:
recommendations.ml_infer_ms(推論時間)
recommendations.items_returned
recommendations.strategy_used{mode=ml|rule}
recommendations.cache_hit(若有 Cache)
取樣日誌(1%):
effectId、前 5 名項目(名稱、分數)、mode、requestId
僅記非敏感(不落使用者個資)
4) 快取與無痛更新
Caffeine cache:key=effectId
新增管理端點(需 token 或本機限定):
POST /admin/recache?effectId=E001 → 清除並重算
POST /admin/switch?mode=ml|rule → 即時切換(寫入 in-memory flag)
POST /admin/gray?mlPercent=30 → 調整灰度百分比
匯入新模型流程:
上傳 onnx/json/sha256 → 驗證通過 → 不切流
灰度 mlPercent=10 → 30 → 50
視指標決定放大或回退
5) 風險控管與回滾
啟動/運行期間任何 ML 例外(模型缺檔、校驗失敗、推論拋出)→ 自動 fallback rule + WARN 日誌一次
提供一鍵回退腳本:
scripts/switch_rule.sh → hit admin API 切回 rule
健康檢查擴充:
/actuator/health 增加 model 指標(已載入且可推論一筆乾測)
6) 測試與驗收
單元:MlScoringStrategyTest(特徵 → 輸出分數可重現)
整合:/api/recommendations?effectId=E002 在 mode=ml 與 mode=rule 排序不同且可切換
灰度:連打 100 次,約 20% 回 X-Scoring-Mode: ml(可調)
回滾:移除模型檔 → 啟動時自動回 rule,不崩潰
效能(M4 Air):P95 推論 < 50ms(候選 ≤ 100)
📦 交付物
config
application.yml 增:scoring.mode、model.version、model.path、gray.mlPercent
service/scoring
MlScoringStrategy.java(已於 Day 12)
RuleScoringStrategy.java(保留)
StrategyRouter.java(根據配置/灰度決定使用哪個策略)
config/OnnxConfig.java
載入模型、校驗 feature_schema、失敗 fallback
controller/AdminController.java
POST /admin/switch、/admin/gray、/admin/recache
metrics
在 RecommendationService 記錄 Micrometer 計量與取樣日誌
scripts/
deploy_model.sh(放置新模型 + 校驗 sha256)
switch_rule.sh(一鍵切回規則)
README_DAY13.md
灰度操作手冊、回滾步驟、指標觀察清單