vatt'ghern jaskier's ballads
本文 4 個互動圖表在手機上以重點摘要呈現,互動版請以桌面瀏覽器開啟。

Spotify 資料科學團隊上週公布一個讓人不太舒服的數字——他們把 LLM eval 擺在 A/B test 之前當作預先篩選的 funnel,已經跑了一段時間,可是「成功通過 eval gate 後上線」的實驗,仍然有大約 42% 最後得 rollback;意思是 eval 抓到了 tone、coherence、intent alignment 那一層,卻沒抓到 session length、crash rate、retention 那一層——而後者才是讓你晚上睡不著的那層。

把 LLM eval 擺在 A/B 前面——funnel vs fork、calibration、與那 42% 還是被 rollback 的實驗

篇文章要做的事情很單純:把 Matilda Ankargren 與 Mårten Schultzberg 在 2026-05-18 那篇 Spotify Engineering 貼文裡那套「LLM eval 是 funnel 不是 fork」的思路,從零拆解一遍。你會看到 funnel 與 fork 兩種拓樸的差別、eval 能看到什麼又看不到什麼、為什麼 42% 不代表 eval 設計失敗、以及 calibration 為什麼是這整套方法成立的前提。讀完之後,你應該能判斷自己手上那個 LLM-powered feature 的 experimentation stack,到底是 funnel 還是 fork——以及該補哪一塊。

那 42% 是怎麼來的——一個你誤以為自己解決了的問題

先把場景擺清楚。你有一個 prompt template、一個 model、一個 retrieval layer。某天你想換 prompt——加一句 system instruction,讓回應更短、更具體。傳統 A/B testing 的做法是:舊 prompt 當 control、新 prompt 當 treatment、跑七天到兩週、看核心 metric 有沒有顯著差。這個流程在按鈕顏色變更那類 feature 上沒問題,但 LLM-powered feature 的 candidate 不止「user 反應」這一層——還包括「response 本身是不是合適 / 安全 / 對得起 brand」。後者必須在 user 看到之前先檢查過。

為什麼前者可以「用 A/B test 直接 check」、後者不行?因為前者的 worst case 是 metric 變差、可以即時 rollback、損失有限;後者的 worst case 是 LLM 對某 user 講了傷害性內容、即使 immediately rollback、那條傷害已經發生、無法 retroactive 修正。Brand damage、harm、misinformation 都是 irreversible cost——A/B test 模式假設 worst case 可逆,這個假設對 LLM 失效。Funnel 的 verification stage 不是 efficiency 優化、是應對 irreversible cost的必要措施。

所以業界這兩年蓋出了 LLM-as-judge——用另一個 LLM 對著一份 rubric 評你的 response。Rubric 通常涵蓋 tone、relevance、coherence、instruction following。你跑 1000 條 query、judge 給分、treatment 平均高於 control 就推 A/B test。這把以前需要 human annotator 的工作壓到 LLM API 一次 call 的成本,掉了四到五個 order of magnitude。LLM-as-judge 本身有 well-documented 的 systematic bias——position bias、length bias、self-enhancement bias、verbosity bias——這些 bias 都被學術 paper 量化過,是這套方法既有的 baseline noise。Calibration 的工作之一就是讓 rubric 對這些 bias 有抗性。

下面這段虛擬代碼把 funnel 與 fork 的 control flow 對照寫出來:

// fork:eval 與 A/B 平行、每個 candidate 都跑兩條 path
candidates.forEach(c => { runEval(c); runABTest(c); reconcile(c); });

// funnel:eval 是 gate、A/B 只看通過者
candidates
  .filter(c => runEval(c).score >= THRESHOLD)
  .forEach(c => runABTest(c));

那為什麼 42%?Spotify 公開的內部統計顯示:他們的 LLM-powered feature 變更,即使先通過 eval、再進 A/B test,最後仍然有大約 42% 會 rollback。這個數字放在 industry context 下其實是 reasonable 的——非 LLM 的 ML feature rollback rate 也通常在 40 ~ 60% 之間。Microsoft Bing 公開過他們 search ranking 變更的 rollback rate 是 65%、Booking.com 公開的 hospitality recommendation experiment rollback rate 是 ~50%。所以 Spotify 的 42% 不是 LLM 特別爛、是 user behaviour prediction 本身就難。

這 42% 不是 eval 寫錯——而是 eval 與 A/B test 看的是兩件不同的事情。Eval 看「output 本身的品質」:tone 合適嗎、有沒有 follow instruction、relevance 夠不夠。A/B test 看「user 接觸到 output 之後的行為變化」:session 有沒有更長、有沒有少 crash、下週還會不會回來。前者是 artifact-level 的判斷,後者是 outcome-level 的判斷。兩者之間有 correlation 但不是同一回事。

這 42% 的存在,正好戳破一個常見的誤解:「我裝了 LLM eval、所以我不需要 A/B test 了。」eval 不是 A/B test 的替代品,eval 是 A/B test 的前置篩選。能不能把這層 framing 內化成 team 的 default mental model,是這整套方法成不成立的關鍵。順帶把這 42% 的時間尺度標清楚:說的是「實驗跑完整 cycle、最終 ship decision 是負面」這個 final outcome,不是「實驗開了三天看數字爛就關掉」的早期殺。Eval gate 改善了通過 candidate 的平均品質,但沒辦法把 user-level 的 second-order failure 從 distribution 裡完全 cut 掉。

對比一個 fork 模式下沒有 eval gate 的 baseline 數字:在 LLM 之前的 web product feature 變更 promotion rate 通常在 10 ~ 20%——也就是 80 ~ 90% 的 candidate 最終會 rollback。Funnel 把這條 rollback rate 從 80% 改善到 42%(promotion rate 從 20% 升到 58%),等於把 candidate 通過率翻三倍。這個 effect size 不算小,但也說明了 eval gate 在做的事情有 ceiling——它能濾掉 obvious 失敗,但對看起來合理但 user 不買單的 candidate 沒辦法 catch。這條 gap 不是「eval 設計太寬」造成的,是「rubric 與 user value 之間有 systematic mismatch」造成的——calibration 的工作就是持續識別這條 mismatch 在哪、把 rubric 朝 user value 拉近。

funnel 與 fork——兩種看起來像、實際上不一樣的拓樸

Spotify 那篇文章為這個誤解取了名字:fork。Fork 的意思是「eval 與 A/B test 是平行的兩件事,分開做、各取所需」。Funnel 的意思是「eval 是 A/B test 上游的篩選器,弱 candidate 被擋在 user-facing experiment 之前」。兩個字看起來只是隱喻差異,但拓樸完全不同。下面這張 tab widget 把兩種拓樸的 control flow 並排放在一起——第三個 tab 把差異列出來。

fork:eval 與 A/B test 平行

candidateprompt / model
LLM evaloffline score
A/B testuser metrics
human judgementweigh both signals

每個 candidate 都跑完兩條 path · 沒有預先篩選

candidate prompt / model LLM eval A/B test offline score user metrics human judgement weigh both signals fork:eval 與 A/B test 平行、結論交給人 每個 candidate 都走完兩條 path · 沒有預先篩選

funnel:eval 是 gate

candidateprompt / model
LLM eval(gate)pass → 下一站;fail → reject
↓ pass
A/B testuser metrics
promoteor rollback

弱 candidate 在 eval 階段被擋下 · A/B 流量只給通過 gate 的

candidate prompt / model LLM eval(gate) pass fail:reject 不上 A/B reject pile A/B test promote or rollback funnel:eval 是 gate、A/B test 是 final arbiter 弱 candidate 在 eval 階段被擋下 · A/B 流量只給通過 gate 的
// fork vs funnel——資源配置與決策權上的差異

fork:
  eval 與 A/B test 平行 → 兩條 path 都對每個 candidate 跑
  決策權在 human:要 reconcile eval score 與 A/B test outcome
  → 流量被消耗在弱 candidate 上(最終要 rollback 的那些)
  → eval 是 sanity check、不是 budget guard

funnel:
  eval 在 A/B test 之前 → 弱 candidate 不會吃到 user 流量
  決策權在 eval rubric 與 A/B test:兩者各管自己那層
  → 通過 eval 的 candidate 才進 user-facing experiment
  → eval 是 budget guard、保護 user experience 也保護 traffic

問同樣的問題、得到的 dataset 不一樣:
  fork:N 個 candidate 的 A/B test outcome(含一堆爛的)
  funnel:N 個 candidate 的 eval score + 通過者的 A/B test outcome

注意一個容易誤會的點:funnel 不會讓 A/B test「不需要」——
  它讓 A/B test 不必為 obvious 的爛 candidate 浪費流量。
  那 42% 仍然 rollback 的 case,是 eval 看不到的失誤——
  例如「prompt 變更導致 response 變長 200 字、user 滑掉的比例上升」。
  Eval 不看 user 滑掉、A/B test 看,所以 funnel 不取代 A/B test。
切換上方三個 tab。第一個是 fork 的拓樸——eval 與 A/B 平行、決策權在人;第二個是 funnel 的拓樸——eval 是 gate、reject 不再消耗 user 流量;第三個列出兩者在 dataset、決策權、與 traffic budget 上的具體差別。

切換上方三個 tab

Fork 讓每個 candidate 都消耗 A/B 流量;funnel 以 eval 為 gate,弱 candidate 在 A/B 前就被過濾。

看完三個 tab 應該抓得到核心:fork 的問題不是「eval 跟 A/B 都做了」這件事——是兩者都對每個 candidate 都跑、決策權只能交回人手上「兩個 signal 對不上時你要相信誰」。當 candidate 數量多(一個 team 一個 sprint 可能有 10 ~ 30 個 prompt 變更要評),fork 的 traffic 成本與決策 cost 都會線性放大。Funnel 把「先 verify 再 validate」這條 testing pyramid 紀律套到 LLM 上,user 流量只給通過 gate 的 candidate。

從 information theory 角度看,funnel 順序的價值是「先用低成本的 noisy signal 過濾、再用高成本的 reliable signal 確認」這套經典 cascade 策略。Eval 是 cheap 但 noisy 的——judge LLM 有 bias、rubric 不完整。A/B test 是 expensive 但 reliable——直接量到 user 行為。先用 eval 把明顯失敗的 candidate 過濾掉、剩下的 candidate 用 A/B test 仔細看。這條 cascade 在 spam filter、anti-fraud detection、search ranking 都用——LLM eval 是這個 well-known pattern 的新 instance。但 funnel 也有一個風險:eval 變成 gate 之後,eval 本身會變成 gaming 的對象——team 知道「eval 過了才上 A/B」,於是會去 tune prompt 直到 eval 給高分為止。這個風險就是 calibration 要處理的核心題目。

另一個 fork 容易踩的坑是「決策時間」。Fork 模式下每個 candidate 都帶兩個 signal 回來:eval score 與 ab outcome。當這兩個 signal 不一致——eval 高分但 A/B test 結果負面,或 eval 低分但 A/B test 結果正面——team 要花一輪 meeting 討論「相信誰」。實務上常見的結論是「相信 A/B test」——這等於把 eval 整段降級成 sanity check,當初 build eval 的 ROI 拿不到。Funnel 模式因為 eval 在 A/B 之前,根本不存在「兩個 signal 衝突」的場景——eval 的 signal 只決定「進不進 A/B」,A/B 的 signal 只決定「promote 還是 rollback」,兩層各管自己一刀切,team meeting 的 ambiguity cost 降到接近零。對組織來說這層好處比 traffic 節省更實在:開會時間是稀缺資源,把它從「兩個指標哪個是真的」這種沒結論的爭論中省下來,比省 30% 的 A/B 流量更值錢。同樣的邏輯也適用於跨團隊的 alignment ——當 product team 與 data science team 共用同一條 funnel、看的是同一個 gate 分數,scope creep 與 finger-pointing 的空間被結構性地縮小,不需要靠流程或 governance 文件去補。

那 42% 怎麼破解——eval 看得到什麼、看不到什麼

先具體列出 eval 看得到的 signal 與看不到的 signal。下面這張表把 Spotify 文章裡舉的 dimension 與常見的 user-outcome metric 並排放。重點不是「eval 沒用」——是 eval 有非常清晰的適用範圍,超出這個範圍的事情 eval 不應該承擔。

click column header to sort · 4 columns × 10 rows

signal / 維度 eval 看得到? 為什麼 通常誰量?
tone 是否合宜YESresponse 本身的 lexical / register 特徵LLM-as-judge rubric
是否 off-topicYEScompare response 與 query 的 semantic overlapLLM-as-judge rubric
instruction followingYESformat / 長度 / 順序這類可形式化的合約rule-based + LLM judge
intent alignmentYES判斷 response 是否解了 user 真正要問的東西LLM-as-judge rubric
trust-breaking contentYES偵測 unsafe / brand-incompatible 的 patternsafety classifier + LLM judge
session length 變化需要 user 在 session 內的後續行為才能測A/B test
crash rate 變化client-side error,response 內容無法 predictA/B test + client telemetry
retention(D7 / D30)跨 session 的延遲信號,eval 是 single-shotA/B test + cohort 分析
downstream churn需要週 / 月級延遲、eval window 不夠A/B test + cohort 分析
latency p99 變化response 內容好但花了更久——eval 不看時間軸A/B test + APM
上半段 YES 的五個 signal 是 eval 的 sweet spot——response 本身的可觀察特徵;下半段 NO 的五個 signal 是 A/B test 的領域——需要 user 接觸 response 之後的行為才能量。42% rollback 的 case 幾乎都落在下半段的某一個或多個 signal 上。

上半段 YES 的五個 signal 是 eval 的 sweet spot——response 本身的可觀察特徵;下…

Eval 能量 tone/relevance 等品質;session length、D7 retention、crash rate 只有 A/B 能量。

講一個具體會踩到的 eval-blind case,方便你心中有畫面:團隊把 chat assistant 的 system prompt 從「給簡短回答」改成「給結構化回答(先列 bullet point 再展開)」。Eval rubric 評了 relevance、coherence、instruction following,全部上升。上 A/B test 一週後 session length 與 conversation depth 都下降——user 在新版會 read 第一個 bullet 就 dismiss、不再追問細節,因為「條列」已經給了他「我看完了」的訊號。Eval rubric 看 single-shot response 品質、看不到「user 看完 response 後的 follow-up 行為改變」,所以這條 user-behaviour-level 的 regression 沒有 way for eval to flag。這就是典型的 eval-blind failure。

另一個常見 case 是 latency 的 hidden cost。Prompt 變更導致 model 平均 output token 從 80 增加到 220、response 內容更完整、eval rubric 給的 quality score 上升。但 streaming 完成時間從 1.4 秒延到 3.1 秒、user 在等待期間滑掉 / 切走 / abandon 的比例上升。Eval 不量時間軸、不量 user 注意力的 cost-of-waiting,只有 A/B test 端的 client-side latency telemetry 抓得到。這條 case 在 LLM-powered chat / search / completion 類產品幾乎每月會撞一次。

第三個 eval-blind case 是「meaning shift over multi-turn」——chat assistant 在 single turn response 看起來都合適,但累積 5 ~ 8 turn 之後 contradicts 早期 response、或忘了 user 一開始講的 constraint。Eval 通常一條 query 一條 response 評、不模擬 multi-turn 對話,所以這條 long-context coherence 失敗 invisible。修法是 eval set 加入 multi-turn scenario、judge 評整段對話。但這條 fix 也只是 partial——真正的 multi-turn 失誤 mode 太多、eval set 永遠 cover 不完,仍然得靠 A/B test 上的 session length 與 conversation depth metric 來 backup。第四個維度比較隱晦但實際重要:eval 不量跟既有 user 習慣的相容性——一個 candidate 也許 objectively 比現行 prompt 好,但變化太大、需要 user 重新學「怎麼問」,eval 不看 user 的 transition cost、A/B test 才會在 retention curve 上看到「短期 disagreement、長期 maybe 不錯」這條 J-shape。

所以 42% 這個數字應該這樣讀:在 eval 通過的 candidate 裡,仍然有 42% 在這些 eval-blind 的 dimension 上踩雷。這個數字不是「eval 失敗率」,是「eval 適用範圍之外的失敗率」。改進方向不是把 eval rubric 寫得更嚴格——那會擋掉一堆其實 user 喜歡但 rubric 不喜歡的 candidate。改進方向是把 eval 與 A/B test 的 signal 對齊起來,讓 eval 對下半段那些 dimension 有 indirect 但 calibrated 的 proxy。這就是 calibration 的工作。

calibration——讓 eval 的 opinion 變成 evidence 的那一步

到這裡你應該抓到了:eval 是 funnel 的 gate、A/B test 是 final arbiter、兩者看不同 signal。但這套配置有一個看起來很尷尬的問題——eval 自己怎麼知道它的 rubric 跟 user outcome 對得上?Spotify 那篇文章的精髓在這一句:「Without offline-online signal calibration, our evals are opinions, not evidence.」翻成白話:你的 eval 給的分數,本來只是 rubric 寫死的一個 opinion。要把這個 opinion 升級成 evidence,你必須能拿過去做過的 A/B test 結果,回頭驗證 eval 對這些 case 的 ranking 與 user outcome 的 ranking 是不是 correlated。對得起來 → eval 是 calibrated proxy;對不起來 → rubric 有偏差、需要修。下面這個 widget 把這條 correlation 與 funnel hit-rate 之間的關係畫出來,你可以拖動 calibration ρ 看兩條曲線分開的速度。

drag handle to sweep offline-online correlation ρ from 0 to 1

ρ=0.40 · hit-rate ?
calibration ρ(offline-online correlation) experiment hit-rate 0% 25% 50% 75% 100% 0 0.25 0.5 0.75 1.0 fork ~28% funnel(eval gate + A/B) fork(parallel)
橙色是 funnel 的 hit-rate——eval gate 過濾掉的 candidate 越是真的爛、過 gate 進 A/B 的 lift 比例越高;綠色是 fork 的 hit-rate——eval 與 A/B 平行所以沒有過濾效果。ρ→1(perfect calibration)時 funnel 上限約 80%,現實沒人能到;ρ→0(無 calibration)時 funnel 退化成隨機篩,跟 fork 一樣。Spotify 那 42% rollback 對應的是 funnel 在 ρ≈0.55 附近的位置——可改善但不會降到零。

橙色是 funnel 的 hit-rate——eval gate 過濾掉的 candidate 越是真的爛、過 gat…

ρ=0 時 funnel 退化成隨機篩;ρ≈0.55 對應 Spotify 42% rollback;perfect calibration 上限約 80%。

橙色線的形狀有兩個結論。第一,ρ=0 的時候 funnel 退化成「隨便挑」、實際 hit-rate 與 fork 相同——eval gate 沒有提供任何 signal。第二,ρ 不需要到 1 就能拿到大部分 funnel 的好處——ρ≈0.5 ~ 0.6 區間 funnel hit-rate 就能爬到 50% ~ 60%。意思是你不需要 perfect calibration,你只需要系統性地朝 calibration 方向走。LLM-as-judge 研究文獻的 convention 大致是:ρ ≥ 0.6 算 strong calibration、0.4 ~ 0.6 算 moderate、< 0.4 算 weak。Calibration 不只是「越高越好」的 monotonic 指標,moderate 以上 eval 才開始 add value。

那 calibration 怎麼做?三步:對過去 N 個 A/B test 的 candidate,回頭跑 eval、記下 (eval_score, ab_outcome) 這個 pair;計算這兩個 series 的 Spearman correlation——這就是 ρ;找出 eval 與 A/B test 不一致的 case 拿出來人工 review、看 rubric 漏了什麼、更新 rubric、下一輪重新算 ρ。這個 loop 有兩個 subtle 但重要的細節:你不能用「即將跑 A/B」的 candidate 去 calibrate 那個 eval rubric——那是 leakage;calibration 不收斂到 ρ=1,因為 A/B test 本身也有 noise(sample size、temporal confounders、segment heterogeneity),ρ 的天花板被這個 noise 限制住。實務上能跑到 0.5 ~ 0.7 已經是 well-calibrated 的 eval。

還有第三個細節,是 calibration 設計常見的盲點:你的 calibration sample 不能只取「上線後 promoted」的 variant。如果只用 promoted variant 算 ρ,你算的是 eval 在「過 A/B test 的 candidate distribution」上的 correlation——這個 distribution 已經被 selection bias 過濾過。正確做法是 calibration sample 同時包含 promoted 與 rolled-back 兩種 outcome,rubric 的 ranking 要在整個 candidate distribution 上 correlate 得起來,不是只在 winner 子集上。這條原則跟 ML 模型訓練資料的 negative example 一樣——你需要 model 看過失敗 case 才會學到「失敗長什麼樣」。Pearson correlation 假設線性、對 outlier 敏感;Spearman 是 rank-based、對非線性 monotonic 關係 robust,所以 calibration log analysis 應該預設用 Spearman。

那個 Opus 4.5 案例——calibration 失敗會長什麼樣子

Spotify 那篇文章舉的最尖銳的反面案例,是 Anthropic 自己對 Claude Opus 4.5 的 evaluation。原本他們在用「coding eval」當 proxy——一組固定的 coding task 集合。Opus 4.5 在這組 eval 上的表現相對於前一代「沒有 measurable improvement」——數字看著沒進步。但 Opus 4.5 在實際工程師日常用的 longer-task scenario 上有明顯的進步——能持續處理更長的 context、更複雜的多步驟 task、更好的中途糾錯。這個 case 是 calibration failure 的教科書範例:eval 的 rubric—coding task 集合——跟「user 實際從新 model 拿到的價值」之間,correlation 不夠高。下面這個 widget 把這個 dynamic 視覺化。拖動 calibration ρ,看 eval 的「看到的進步」與 model 的「真實進步」這兩條曲線怎麼分開。

drag handle to control eval rubric calibration ρ

ρ=0.30 · gap ?
model generation(Sonnet 4 → Opus 4.5) measured improvement 1.25× 1.5× 1.75× 2.0× v4-base v4.2 v4.3 v4.4 v4.5 real-task improvement coding eval(rubric proxy)
綠色是 Anthropic 在 longer-task scenario 看到的 Opus 4.5 真實進步;橙色是 fixed coding eval 看到的(幾乎平的)proxy 數字。ρ 越低,兩條曲線在 v4.5 那一點的 gap 越大——眼前你看到的就是 calibration failure 的視覺形狀。拖到 ρ→1 兩條曲線會貼起來。

綠色是 Anthropic 在 longer-task scenario 看到的 Opus 4.5 真實進步;橙色是 …

Opus 4.5 真實進步 1.78×,但 coding eval 僅顯示 1.1×;rubric 未涵蓋長 context,calibration 失敗。

把 calibration ρ 拖到 0.30 附近——這大概是「沒做 calibration、隨意挑的 fixed coding eval」對 longer-task scenario 的 correlation。你會看到 v4.5 那點上 eval 顯示的 multiplier 大約 1.1×,但真實是 1.78×——gap 0.68×。這個 gap 就是「Opus 4.5 看著沒進步」的真實量化。注意這條曲線在 v4 ~ v4.3 區間 gap 很小、到 v4.5 才放大;這個 shape 反映了一個普遍現象:calibration gap 在 model 的 capability frontier shift 時最大——minor updates 只是 incremental polish、舊 rubric 仍 capture 得到差別;major capability jump 會 outpace rubric 的 measurement coverage、gap 突然放大。所以 calibration audit 的最佳時機,是 model upgrade 之後的第一週

這條 lesson 對 product team 的應用很直接:你手上那個 eval rubric 是 designed for 你過去的 user behaviour profile。當 user 開始用新方式跟 LLM 互動(task 變長、context 變複雜、retry pattern 改變),舊 rubric 與新 reality 之間的 correlation 會逐步衰減。Calibration 不是一次性的 setup——是季度級的維護工作。如果你的 team 用同一份 eval rubric 超過 6 個月沒重新 calibrate,你應該假設這份 rubric 已經 drift 過了——拿過去這 6 個月的 A/B test outcome 回頭跑一遍,算 Spearman ρ,看是不是還在 0.5 以上。如果掉到 0.3,那個 rubric 已經是 opinion 不是 evidence,funnel gate 等於沒裝。

把 Opus 4.5 那條 lesson 推到一個更廣的 framing:每次 model upgrade 都應該同時重新 calibrate eval。為什麼?因為 model 變了之後,response 的 surface form 會變——句長分布、結構傾向、example 用法、refusal pattern 都會 shift。舊 rubric 對舊 response distribution 的判斷是 calibrated 的,對新 distribution 不一定。如果你直接用舊 rubric 評新 model,最常見的失敗模式是「新 model 在 rubric 上看著沒進步、實際 user 反應好」——也就是 Opus 4.5 case 的 generic 版本。反方向也存在——新 model 在 rubric 上看著大幅進步、實際 user 反應沒變甚至更差,這個 case 通常是 model 的 response style 朝 rubric 偏好的方向 shift,style match 變好、user value 沒變好。兩個方向都靠 calibration log 才能區分。

怎麼把 funnel 接到你已經有的 experimentation stack 上

你的 team 八成已經有一個 A/B test platform。如何把 funnel 接上去?最小可行步驟:把現有 A/B test 的 (variant_id, ab_outcome) dataset 整理出來;對每個 variant 跑 eval;算 (eval_score, ab_outcome) 的 Spearman ρ——這就是你 eval 的 calibration baseline。低於 0.4 → eval 是 opinion;0.4 ~ 0.6 → 可用但需要 A/B test 看著;高於 0.6 → eval 可信。然後把 eval gate 接到 release pipeline 之前,具體形狀像這樣:

// 在 prompt / model 變更從 dev 進 staging 之前插 eval gate
function gateCandidate(candidate) {
  const evalSet = getEvalSet();                    // 200 ~ 500 條代表性 query
  const scores = evalSet.map(q => runEval(candidate, q));
  const aggregate = aggregateScores(scores);       // 通常是 weighted mean of rubric dimensions

  if (aggregate < THRESHOLD_PASS) {
    return { decision: 'reject', reason: aggregate, dim_failures: lowestDims(scores) };
  }
  if (aggregate >= THRESHOLD_PASS && aggregate < THRESHOLD_HIGH) {
    return { decision: 'ab_test', traffic_allocation: 0.05 };  // 進 A/B test,5% 起跳
  }
  // aggregate 高且 calibration ρ > 0.6——可以給更大流量
  return { decision: 'ab_test', traffic_allocation: 0.20 };
}

建立 calibration feedback loop:每個 A/B test 結束、不論 promote 還是 rollback,把 (variant_id, eval_score, ab_outcome) 寫進一張 calibration log table。每季拿這張 table 跑 ρ 估計、更新 rubric 或 THRESHOLD。這套是 continuous 的——不是「裝一次就好」。識別 eval 與 A/B test 不一致的 case:eval 高分但 A/B test rollback 通常代表 rubric 有 dimension 沒涵蓋(latency / session length / format preference 這類 second-order);eval 低分但 A/B test 過通常代表 rubric 過嚴或有 systematic bias。每個不一致 case 都是 rubric 改進的 input。Eval rubric 是 grow 出來的、不是 design 出來的——一開始的 5 個 dimension 永遠不夠,calibration loop 告訴你還欠哪幾個。

整套 funnel 落地不是技術問題、是 process 紀律問題。技術上 SQL query、judge API call、Spearman correlation 計算、threshold 拍版,任何 mid-level engineer 都能 implement;難在「持續做」、「跨 sprint 維護」、「team 換人之後不失去 muscle memory」。把八步壓縮成一句話:在每個 LLM-powered feature 變更上線之前,都有一個 explicit、calibrated、versioned 的 quality gate;A/B test 之後的 outcome 都自動 feed 回 calibrate 那個 gate。這個 closed loop 是 funnel 真正的 essence——一旦這個 loop 在 team 內部 spin up,funnel 就會 self-sustain。沒有這個 loop、即使你跑了 eval 跑了 A/B test 跑了 lots of dashboards,也只是 fork 的高級版本——eval 與 A/B 各自為政、各自進化、各自說各自的數字。

實務上,你今天能對手上 LLM feature 做的最小可行 action 是:打開最近三個月的 A/B test list,看哪些 candidate 是 rolled-back、哪些 promoted;對這些 candidate 跑現在的 eval rubric 一遍;算一個 Spearman ρ。如果 ρ < 0.4,你的 funnel 是裝飾、不是 gate;如果 ρ ≥ 0.5,恭喜——你已經在 funnel 模式裡了,下一步是把 calibration 排進 quarterly schedule、別讓 ρ 慢慢漂走。這條 minimum viable action 不需要工具升級、不需要 team approval、不需要重做 process——只需要半天的 SQL 跟 eval batch run。能不能踏出這一步,往往就決定了 team 跟 Spotify 那篇文章對齊還是繼續停在直覺驅動。

Take-away:eval 是 funnel 的 gate、A/B test 是 final arbiter——但 eval 要從 opinion 升級成 evidence,唯一的辦法是讓 offline rubric 與 online outcome 持續對齊;當你的 eval rubric 與真實 user behaviour 之間的 Spearman ρ 低於 0.4,那個 gate 等於沒裝,把它修好之前,funnel 就只是名字看起來比 fork 漂亮的 fork。