在過去幾天的鐵人賽文章中,我有使用一道 4^6 = 8^n 數學題,來展示 teacher trajectory,第一行先寫了 $n=3$,最後才推到正確的 \boxed{4}。Final-answer verifier 接受 4,SFT 的 next-token loss 卻不會回頭判斷第一行;只要整段文字被放進 target,錯誤的 3 和正確的 4 都會成為模型要模仿的 token。
我們原本設定的三種 SFT target 最後都沒有勝過最初的 Base,表現最好的是 process-structured proxy,在 640 道 internal development problems 答對 66 題,仍低於 Base 的 103 題;它替 trajectory 加上 Step N,沒有增加任何 step-level truth,顯然這些調整無法解決「我們只能確定最後答案」這個問題。
如果可靠的訊號只有 final answer,另一個解決方法是先讓模型自己生成,再依結果給分。模型不必逐 token 模仿一份預先寫好的完整解答,而是抽樣出 response,由 verifier 回傳 reward,policy update 再調整這類 response 之後出現的機率,這就是這幾天的主題-Reinforcement Learning with Verifiable Rewards(RLVR)預計要討論的。
SFT 在更新以前就知道 target response,每個受監督 token 都有明確標籤;reinforcement learning 看到的是模型實際採取的 action 與最後取得的 reward,中間還需要 credit assignment,判斷哪些選擇值得增加或降低機率。Reward 是結果分數,不是一串自動對齊到每個 token 的正確答案。
Reinforcement Learning from Human Feedback(RLHF)處理的是另一種評分困難,相信大家在幾年前就知道這套方法是 ChatGPT 使用的,也就是語氣是否合宜、回答是否有幫助、兩份長文哪一份更好,往往得由人類比較,再訓練 learned reward model 近似這些偏好。它能涵蓋無法寫成規則的品質,也帶來標註成本、評分者差異,以及 reward model 在新分布上的誤差。
RLVR 把評分來源換成可以執行的規則,因為數學答案可以做正規化與符號等價比較,程式碼可以跑測試,棋局可以直接判定勝負;同一份輸出交給同一版 verifier,應該得到同一個結果,能夠幫助人類節省逐筆排序答案的時間和心力。
reward source 它能評什麼 主要風險
human preference 整體偏好、語氣、幫助性 成本與評分者差異
learned reward model 從偏好資料近似品質 bias、分布外誤差
final-answer verifier 支援範圍內的答案正確性 parser 與規則邊界
format/length proxy 方框、長度、固定字串等可見特徵 容易獎勵錯誤捷徑
「可驗證」不等於 verifier 是正確的,答案擷取器可能漏掉合法表示法,符號化比較可能遇到不支援的 expression,過度寬鬆的 fallback 也可能把正文裡無關的數字當成答案;一旦 false positive 被寫成 reward 1,optimizer 會忠實放大評分器的錯誤。所以 reward contract 必須先凍結、加版本、接受對抗案例測試,遇到支援範圍外的輸入就保守地給 0,不能看過 rollout 後才臨時改規則。
最後採用的 v3 reward contract 是配合 Sebastian Raschka Chapter 6 的原始 no-KL 設定:模型必須交出可擷取的 boxed final answer,而且答案與 reference 等價,才能得到 1;其餘情況一律是 0。Reference answer 不會出現在 generation prompt,而是在 response 完成後才交給 verifier。
回到 4^6 = 8^n,這份契約會把四種輸出分開:
model output extracted answer reward
... \boxed{4} 4 1
... therefore n = 4 none 0
... \boxed{5} 5 0
... \boxed{unsupported(...)} unsupported 0
第二列的數學內容可能是對的,卻沒有符合這一版明確凍結的 boxed-answer contract;第三列的格式再漂亮,答案錯了仍然是 0。這項設計讓 reward 可以穩定重播,也表示 format requirement 已經成為 reward definition 的一部分。之後若要改成接受 unboxed answer、加入 partial credit 或評估中間步驟,就必須建立新版本,不能沿用同一個名稱偷偷換尺度。
實作上,正式 reward 的核心只有兩行:
decision = evaluate_prediction(generated_text, reference_answer, fallback="none")
reward = float(bool(decision["correct"]))
Prompt 可決定模型看見什麼,fallback="none" 決定哪些輸出可以被擷取,evaluator 決定數學等價的支援範圍,最後那個 Boolean 才變成 optimizer 看到的 0 或 1。Final answer 通過則證明結果落在 verifier 接受的集合裡,但這個階段還未把整段 reasoning 變成逐步驗證的證明。
接著才輪到 rollout,正式 v3 從 pinned revision da87bfb 的 Qwen/Qwen3-0.6B-Base 開始,每道 training prompt 依序抽樣 8 個 responses,temperature 0.8、top-p 0.9、上限 512 tokens。這 8 個 reward 會在同一組裡比較,形成 relative advantage。
[0, 0, 0, 0, 0, 0, 0, 0] 全錯,組內沒有排序訊號
[0, 0, 0, 0, 0, 0, 0, 1] 一個正例,可以形成相對差異
[1, 1, 1, 1, 1, 1, 1, 1] 全對,組內同樣沒有差異
到這裡,第 31 個 optimizer step 才有了可以理解的位置。那一題的 8 個 rollouts 全部答對,reward_mean 是 1.0;由於每個候選都拿到相同分數,標準化後的 advantage 全是 0,policy_loss 與 gradient_norm 也都是 0。Reward 判定沒有出錯,缺少的是同組候選之間可供學習的差異。
完整的歷史 v3 run 使用 50 道 prompts、共 400 個 rollouts,只有 15 個得到 reward 1,平均 reward 是 0.0375。50 組裡有 44 組全錯、1 組全對,真正同時包含 0 與 1 的只有 5 組;非零 gradient 因此只出現在 step 2、4、27、43、47。這些數字先回答 reward signal 有多稀疏,還不是模型能力是否提升的 development 結論。
這組 v3 在實驗當時通過設計凍結、CUDA execution、rollout 計數、checkpoint reload 與 sealed-test firewall 的驗證;大型 runtime package 後來因已記錄的 Windows Junction cleanup incident 不再留在目前 workspace,所以現在保留的是 compact artifacts 與歷史驗證結果,Final heldout 的 500 題與 MATH-500 則都維持零 inference。
回到本日開頭的題目,先寫 $n=3$、最後交出 $\boxed{4}$ 的 trajectory,v3 verifier 會給它 1 分,因為它只負責 final answer。RLVR 把「模仿哪段文字」改成「哪些結果值得增加機率」,但在模型能穩定抽到可比較的對與錯以前,一個判分正確的 verifier 仍可能學不到真正重要的資訊。