提示的 A/B 測試框架:把改動風險降到最低
離線分數好不代表線上好。這是一套從灰度到全量的提示發布機制。
提示改動的特性是:影響立即、範圍全面、且難以用測試涵蓋。所以它需要跟程式碼發布一樣的灰度機制,甚至更謹慎。
核心設計是把「使用哪一版提示」變成執行時的決策,而不是部署時的決策。這樣才能在不重新部署的情況下調整流量比例或緊急回滾。
提示註冊表
# prompts/registry.yaml
classify_log:
active:
v3: 90 # 90% 流量
v4: 10 # 10% 灰度
default: v3 # 讀取失敗時的保底
metrics:
- accuracy
- format_valid
- p95_latency
- cost_per_call穩定分流
def pick_version(task, key):
cfg = registry[task]
bucket = int(hashlib.sha256(f'{task}:{key}'.encode()).hexdigest(), 16) % 100
acc = 0
for ver, pct in cfg['active'].items():
acc += pct
if bucket < acc:
return ver
return cfg['default']分流鍵的選擇要看場景:面向使用者的功能用 user_id(同一人體驗一致);批次任務用 item_id(分布更均勻)。用隨機數是錯的,同一個使用者會忽好忽壞。
必須同時盯的四個指標
- 品質:可自動判斷的正確率或格式合法率。
- 成本:每次呼叫的平均 token,新版提示變長會直接反映。
- 延遲:p95,長提示會拉高 TTFT。
- 行為分布:輸出長度、棄答率、工具呼叫分布的變化。
自動停損
GUARDS = {
'format_valid': lambda new, base: new >= base - 0.005,
'cost_per_call': lambda new, base: new <= base * 1.3,
'p95_latency': lambda new, base: new <= base * 1.5,
}
def check_guards(new_stats, base_stats):
broken = [k for k, f in GUARDS.items()
if not f(new_stats[k], base_stats[k])]
if broken:
registry.rollback(task, reason=f'護欄破線:{broken}')發布節奏
- 離線評測通過 → 進入 5% 灰度。
- 觀察至少一個完整日夜週期。
- 指標無異常 → 25% → 50%。
- 穩定後全量,舊版保留在註冊表中至少兩週。
回滾要能在一分鐘內完成,且不需要重新部署。如果回滾需要走完整的 CI/CD,實務上就等於沒有回滾能力。
訂閱後繼續閱讀全文
本篇為訂閱者專屬內容。訂閱後可取得下列權限:
- 解鎖全部內容權限
- 閱讀不限篇數
- 全站移除廣告
月卡
NT$240
開通 30 天
一次付清,開通 30 天
季卡
NT$620
開通 90 天
一次付清,開通 90 天,每天約 NT$7
年卡
NT$2,160
開通 365 天
一次付清,開通 365 天,每天約 NT$6
一次性付款,付款成功後立即開通,到期自動結束,不會再次扣款,也不需要取消訂閱。
立即訂閱
金額均為新臺幣(TWD),即實際扣款金額,不另收手續費
支援信用卡 · Apple Pay · Google Pay · WebATM · ATM 轉帳
購買須知與退款政策