如果你的模型一夜之間「行為變了」,但模型本身沒換,那大概率是 tokenization drift。同一個 tokenizer、語意相同的輸入,產生的 token 序列卻完全不同。MarkTechPost 給的 GPT-2 例子:`" classify"` 前面帶一個空格,tokenize 出來是一個 ID — `[36509]`;`"classify"` 不帶空格,tokenize 出來是兩個 ID — `[4871, 1958]`。對模型來說,這倆不是同一個詞,而是落在 token 空間不同區域裡的兩個不同輸入。「我的 prompt 跟 fine-tune 時看到的差不多」跟「一模一樣」,完全是兩回事。

文章把這個失敗模式量化了。用 GPT-2 的 tokenizer 加一個 fine-tune 過的分類器:SFT 對齊的 prompt 格式拿到約 83% 的 accuracy;把換行去掉,掉到 40-50%;改寫一下指令措辭,token 集合和訓練格式的 Jaccard overlap 掉到 ~50%,輸入直接走出分布,準確率隨之崩。文章給的修法叫 APO(Automated Prompt Optimization):測試五個以上的 prompt 模板變體,每一個都用「token 集合與原始 SFT 模板的 Jaccard 重疊度」打分,然後給 validation accuracy 乘上一個跟 overlap 成正比的 OOD 懲罰因子,最後選在合成指標上贏的模板。落地代碼也就是幾行 HuggingFace `AutoTokenizer.encode()` 加集合比較。

更宏觀的規律是:線上 prompt 出現「回歸」,通常不是模型回歸,而是 tokenizer 層面的對不上 —— 模型在 instruction tuning 階段學到了什麼樣的格式,你的應用現在送進去的是什麼樣的格式,兩者出現了偏差。這種 bug 會繞過你所有現有的測試,除非你顯式地把 token 序列拿去跟參考分布比對。這也解釋了一件每個人都幹過的事:把一段「同樣的 prompt」從 Notion 貼到程式碼編輯器裡,然後悄無聲息地變差 —— 編輯器把空白做了 normalization,或者把末尾換行刪了,你與訓練資料的距離一下子變了。RLHF 和 instruction-tuned 的模型對這事尤其敏感,因為格式本身已經成了任務表徵的一部分,不是任務文字周圍的裝飾。

週一可以動手的事:對線上的 prompt,把原始的 token 序列也 log 下來 —— 不要比字串,要比 token ID,然後跟你部署時驗證過的那條原始 prompt diff。把 Jaccard-overlap 做成 prompt CI 流水線裡的一條回歸測試。如果你跑 fine-tune,把訓練格式確切的 tokenization 存檔,推論時拿進來的輸入要去驗證一遍。如果你做的是閉源權重的模型、沒法重訓,文章那套 APO 迴圈就是務實選擇:經驗性地搜「能讓 token 與已知模型見過的格式最大重疊」的 prompt 變體。「我的 prompt 現在有用嗎」這個問題,從此變成 tokenizer 層面的問題,而不是「我措辭夠不夠好」的問題。