一键导入
concept-drift-analysis
Root-cause a performance alert using sliced metrics + ground-truth
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Root-cause a performance alert using sliced metrics + ground-truth
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Scaffold and run batch scoring jobs (CronJob + Parquet output) that reuse the service's model + feature-engineering code without opening the live API
Review cloud costs against budget and identify optimization opportunities
Debug ML inference issues — latency spikes, wrong predictions, event loop blocking
Deploy ML service to EKS with Kustomize overlays and IRSA
Deploy ML service to GKE with Kustomize overlays and Workload Identity
Run and interpret DATA drift (PSI) AND CONCEPT drift (sliced performance) for an ML service
| name | concept-drift-analysis |
| description | Root-cause a performance alert using sliced metrics + ground-truth |
| allowed-tools | ["Read","Grep","Glob","Bash(python:*)","Bash(kubectl:*)","Bash(gh:*)"] |
| when_to_use | Use when a performance-level alert fires (AUC/F1 dropped), when you need to discriminate concept drift from data drift, or when a slicing alert asks 'why is country=ES AUC low?'. Pairs naturally with drift-detection (PSI) but focuses on GROUND-TRUTH-BACKED metrics, not feature distributions. Examples: 'AUC dropped for country=ES', 'concept drift analysis', 'why is F1 low', 'interpret performance report' |
| argument-hint | <service-name> [--slice <slice=value>] |
| arguments | ["service-name"] |
| authorization_mode | {"analyze":"AUTO","update_baseline":"CONSULT","trigger_retrain":"CONSULT"} |
This skill is the RCA counterpart to drift-detection. Where PSI detects
feature-distribution change, this skill detects and diagnoses
performance degradation using delayed ground-truth labels.
reports/performance.json from the most recent CronJob run (or manual run)models/baseline_metrics.jsondrift_report.json to cross-reference with PSI Performance alert fired
│
┌─────────────┴─────────────┐
Global AUC low? Only sliced AUC low?
│ │
┌───────┴───────┐ ┌─────────┴─────────┐
Data drift No drift Drift in same slice? No drift?
│ │ │ │
Retrain on Label noise Targeted retrain Label quality
fresh data or real or feature fix in that segment
concept drift
jq '.status, .global, .alerts' reports/performance.json
jq '.slices' reports/performance.json # per-slice breakdown
Identify which slices fired alerts. Each entry has:
{ "slice_name": "by_country", "slice": "country=ES", "metric": "auc",
"value": 0.58, "threshold": 0.65 }
# Global AUC
jq '.global.auc' reports/performance.json
# All slice AUCs, sorted ascending
jq -r '.slices | to_entries[] | .value | to_entries[] | [.key, .value.auc] | @tsv' \
reports/performance.json | sort -k2 -n
Correlate slice degradation with feature PSI in the SAME window:
jq '.features | to_entries[] | select(.value.psi > 0.15)' drift_report.json
| Pattern | Likely cause | Action |
|---|---|---|
| High PSI + sliced AUC drop in same slice | Upstream data pipeline for that segment | Fix ETL, no retrain yet |
| High PSI everywhere + global AUC drop | New data regime | Full retrain |
| No PSI + AUC drop in one slice | Label noise or concept shift | Inspect labels_log for that slice |
| No PSI + global AUC drop | Ground-truth pipeline degraded | Verify ingester heartbeat |
jq '.slices.by_country | to_entries[] | {slice: .key, n: .value.sample_size, status: .value.status}' \
reports/performance.json
If status == "insufficient_data" for the flagged slice, you are looking at
noise. Raise min_samples_per_slice in configs/slices.yaml or wait for
more data. DO NOT retrain on noise.
Before blaming the model, rule out ground-truth quality:
# Check ingester heartbeat
kubectl get cronjob {service}-ground-truth-ingester -n {namespace}
kubectl logs job/{service}-ground-truth-ingester-<timestamp>
# Verify labels have non-trivial class balance
python -c "
import pandas as pd, glob
files = sorted(glob.glob('data/labels_log/year=*/month=*/day=*/*.parquet'))[-7:]
df = pd.concat(pd.read_parquet(f) for f in files)
print(df['true_value'].value_counts())
"
A sudden swing in class balance often explains AUC/F1 drops without any model change.
| Diagnosis | Action | Mode |
|---|---|---|
| Noise (small n) | Wait, widen window | AUTO |
| Subpopulation data pipeline issue | Fix ETL; no retrain | CONSULT |
| Real sliced concept drift | Retrain (possibly with reweighted sampling) | CONSULT |
| Population-wide concept drift | Trigger /retrain | CONSULT |
| Ground-truth pipeline broken | Fix ingester; mute alert for now | STOP-for-retrain |
| Label noise | Escalate to data team | STOP-for-retrain |
Trigger retraining only after confirming real concept drift:
gh workflow run retrain-{service}.yml \
-f reason="Concept drift confirmed: global AUC ${auc} vs baseline ${baseline}; slices: ${slices}"
The retrain workflow will execute C/C (ADR-008) — do not assume promotion.
Always append a short entry to docs/concept_drift_log.md:
## 2026-04-23 — {service} concept-drift incident
- **Triggered by**: SlicedAUCBelowAlert country=ES (AUC=0.58)
- **Global AUC**: 0.84 (healthy)
- **Slice AUC**: 0.58 (ES), 0.87 (US), 0.85 (MX)
- **Data drift in ES**: PSI(feature_X) = 0.24
- **Root cause**: ES-specific data pipeline joined stale partner feed
- **Action taken**: Fixed ETL partition filter; no retrain
- **Confirmed resolved**: 2026-04-24 report shows ES AUC = 0.86
This log is cheap insurance against repeated debugging of the same issue.
debug-ml-inference).drift-detection).model-retrain + ADR-008).