:On-Policy Distillation 的配置骨架與驗證路徑)
1. 從一次 OPD 訓練不收斂說起如果你正在做 Agentic RL 相關的工程實踐大概率聽過 OpenClaw-RL 這個框架。它把在線強化學習和 On-Policy DistillationOPD策略內蒸餾揉在一起專門解決智能體工具調用場景下的訓練問題。但真正把倉庫拉下來跑的時候很多人會卡在同一個地方配置文件寫完了訓練腳本也啟動了loss 卻像一條死魚一樣不動或者 advantage 全是零。我試過在本地復現(xiàn) OpenClaw-RL 的 OPD 流程前后踩了不少坑。這篇筆記不打算重復講 OPD 的數(shù)學推導而是聚焦一個更實際的問題On-Policy Distillation 的配置骨架到底長什么樣以及怎么用最小的驗證動作確認你的 OPD 鏈路是通的。適合已經(jīng)讀過 OPD 原理、準備動手跑 OpenClaw-RL 的強化學習工程實踐者。OpenClaw-RL 支持三種模式openclaw-rl基于二元獎勵的 GRPO、openclaw-opd基于后見之明提示的在線策略蒸餾、openclaw-combine聯(lián)合方法。其中 OPD 是最有差別化的設計它的核心思路是學生模型先在原始上下文下生成動作環(huán)境返回 next state 后從中提取一個簡潔的 hindsight hint把 hint 拼回原始上下文形成增強后的 teacher context再用同一個模型在這個增強上下文下對原響應做 forced scoring得到 teacher logprobs最后和 student 原來的 logprobs 做差作為 token 級 advantage。這個鏈路里涉及多個組件SGLang 推理引擎、PRM judge 服務、Megatron 訓練引擎、經(jīng)驗回放緩沖區(qū)。任何一個環(huán)節(jié)的配置對不上OPD 的信號就斷了。下面我把配置骨架和驗證路徑拆開講。2. TaoToken 前置模型服務與 API Key 準備在跑 OPD 之前你需要一個能穩(wěn)定提供模型推理服務的端點。OpenClaw-RL 的 OPD 分支里judge 評分和 teacher logprobs 查詢共享同一個_prm_url端點也就是說你不需要部署兩個獨立服務但需要保證這個端點能同時處理打分請求和 logprobs 查詢。如果你本地沒有現(xiàn)成的推理集群可以用 TaoToken 提供的模型服務作為 PRM judge 和 teacher scoring 的后端。它的 API 兼容 OpenAI 格式接入成本低。具體操作先到官網(wǎng) https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注冊賬號然后在控制臺創(chuàng)建一個 API Key??刂婆_地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。創(chuàng)建完 Key 之后到 API Keys 頁面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 復制你的密鑰。API 的基礎地址是https://taotoken.net/api注意這個地址不加 UTM 參數(shù)。你可以在模型對話頁面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 先手動測試一下模型是否能正常返回確認 Key 有效。如果你打算長期跑編碼類 Agent 的訓練任務可以了解一下 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 它在高頻調用場景下更劃算。接入文檔在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有完整的請求示例和參數(shù)說明。注意OPD 的 teacher scoring 需要對每個 token 返回 logprobs不是所有模型服務都默認開啟這個能力。在配置_prm_url之前先用一個簡單的 curl 請求確認你的端點支持logprobs參數(shù)。3. 可復制的 config.toml 與 settings.json 配置骨架OpenClaw-RL 的配置分兩層config.toml管訓練框架級別的參數(shù)settings.json管 OPD 模塊特有的行為。下面是我實測能跑通的骨架你可以直接復制后按自己的環(huán)境改。3.1 config.toml 訓練框架配置[model] student_model_path /path/to/your/student-model tokenizer_path /path/to/your/tokenizer dtype bfloat16 max_seq_len 8192 [rollout] engine sglang sglang_host 127.0.0.1 sglang_port 30000 rollout_batch_size 32 max_new_tokens 2048 temperature 0.7 top_p 0.95 [training] engine megatron train_batch_size 16 micro_batch_size 2 learning_rate 1e-6 ppo_clip_epsilon 0.2 kl_coef 0.0 num_epochs 1 save_interval 100 [advantage] estimator on_policy_distillation gamma 1.0 lam 1.0 [prm] prm_url https://taotoken.net/api prm_api_key sk-your-key-here judge_model your-judge-model-name teacher_model your-teacher-model-name hint_max_tokens 128 hint_temperature 0.3幾個關鍵點解釋一下。kl_coef 0.0是因為 OPD 模式下 KL 正則被禁用advantage 本身已經(jīng)包含了 teacher 和 student 的分布差異再加 KL 懲罰會干擾信號。advantage.estimator必須設為on_policy_distillation這是觸發(fā) OPD 分支的開關。prm_url和prm_api_key指向你的 judge 和 teacher 共享端點。3.2 settings.json OPD 模塊配置{ opd: { enable_hint_extraction: true, hint_format: \n\n[users hint / instruction]\n{hint}, min_hint_length: 10, max_hint_length: 256, judge_vote_count: 3, judge_temperature: 0.0, teacher_scoring_mode: forced, advantage_clip: 5.0, drop_sample_without_hint: true, log_teacher_logprobs: true }, rollout: { passive_mode: true, session_timeout_sec: 300, max_turns_per_session: 10 }, training: { use_custom_loss: false, custom_loss_path: null } }hint_format這個字段很重要它決定了 hint 怎么拼回原始上下文。OpenClaw-RL 默認是把 hint 追加到最后一條用戶消息的末尾格式就是上面寫的\n\n[users hint / instruction]\n{hint}。如果你改了格式teacher scoring 的結果會完全不一樣。drop_sample_without_hint設為true表示如果 judge 抽不出清晰的 hint這條樣本就不進入 OPD 訓練。這個設計是為了保證只有高質量的 directive signal 才被用來更新策略。teacher_scoring_mode設為forced表示用 teacher context 對原響應做強制打分而不是重新生成。這是 OPD 和普通蒸餾的關鍵區(qū)別。3.3 兩種 OPD 變體的配置差異OpenClaw-RL 實現(xiàn)了兩種 OPD 變體。變體 A 是標準 OPDadvantage-based走 PPO 的 advantage 分支配置就是上面那套。變體 B 是 Top-K OPDreverse KL loss需要額外設置[advantage] estimator grpo custom_loss_function_path openclaw_opd/losses/topk_reverse_kl.py [topk_opd] top_k 64 use_teacher_topk true變體 B 不使用 PPO clip 保護而是直接在 K1 個類別上計算 reverse KL。它的信息傳輸效率更高每個樣本大約 200KB而標準 OPD 每個樣本約 300MB。但變體 B 沒有 clip 保護訓練穩(wěn)定性需要額外關注。4. 驗證請求與成功結果確認配置寫完之后不要直接啟動完整訓練。先用一個最小驗證腳本確認 OPD 鏈路的每個環(huán)節(jié)都能跑通。4.1 驗證 PRM judge 端點import requests import json url https://taotoken.net/api/v1/chat/completions headers { Authorization: Bearer sk-your-key-here, Content-Type: application/json } payload { model: your-judge-model-name, messages: [ {role: system, content: You are a judge. Evaluate the assistants last action and extract a hint if there is corrective information.}, {role: user, content: The assistant tried to edit a file but forgot to check if it exists first. The tool returned FileNotFoundError.} ], temperature: 0.0, max_tokens: 128 } resp requests.post(url, headersheaders, jsonpayload) print(resp.status_code) print(resp.json()[choices][0][message][content])如果返回的 hint 類似“先檢查文件是否存在再編輯”說明 judge 端點工作正常。4.2 驗證 teacher logprobs 查詢payload { model: your-teacher-model-name, messages: [ {role: user, content: Write a function to read a file.\n\n[users hint / instruction]\n先檢查文件是否存在再編輯} ], logprobs: True, top_logprobs: 5, max_tokens: 1, echo: True } resp requests.post(url, headersheaders, jsonpayload) logprobs resp.json()[choices][0][logprobs] print(json.dumps(logprobs, indent2)[:500])確認返回結構里有token_logprobs字段并且每個 token 都有對應的對數(shù)概率值。如果返回的是空或者報錯說明你的端點不支持echologprobs組合需要換一個支持 forced scoring 的模型服務。4.3 驗證 advantage 計算在 OpenClaw-RL 的compute_advantages_and_returns函數(shù)里OPD 分支的核心邏輯是elif args.advantage_estimator on_policy_distillation: student_log_probs log_probs teacher_log_probs rollout_data.get(teacher_log_probs) response_lengths rollout_data.get(response_lengths) device student_log_probs[0].device teacher_log_probs [t_log_prob.to(devicedevice) for t_log_prob in teacher_log_probs] teacher_log_probs [ t_log_prob[-response_length:] for t_log_prob, response_length in zip(teacher_log_probs, response_lengths, strictFalse) ] advantages [ teacher_log_prob - student_log_prob for teacher_log_prob, student_log_prob in zip(teacher_log_probs, student_log_probs, strictFalse) ] returns advantages你可以在本地用兩個小的 logprobs 數(shù)組模擬一下import torch student_lp torch.tensor([-1.2, -0.8, -2.1, -0.5]) teacher_lp torch.tensor([-0.9, -1.5, -1.8, -0.3]) advantages teacher_lp - student_lp print(advantages) # tensor([ 0.3000, -0.7000, 0.3000, 0.2000])正 advantage 表示 teacher 比 student 更認可這個 token訓練會推動 student 提高它的概率負 advantage 則相反。如果所有 advantage 都是零說明 teacher 和 student 的 logprobs 完全一樣這通常意味著 hint 沒有生效或者 teacher scoring 用的上下文和 student 一樣。4.4 成功結果的判斷標準一次成功的 OPD 驗證應該看到第一judge 能穩(wěn)定輸出 1-3 句可執(zhí)行的 hint而不是空字符串或泛泛而談的“做得不好”。第二teacher logprobs 和 student logprobs 在關鍵 token 上有明顯差異。比如在“檢查文件”這個動作對應的 token 上teacher 的概率應該顯著高于 student。第三advantage 的分布不是全零也不是全部同號。正常情況應該有正有負均值接近零但方差不為零。第四訓練啟動后 loss 在頭幾十步內有下降趨勢而不是一條水平線。5. 本篇常見錯誤排查5.1 advantage 全為零最常見的原因有三個。一是prm_url配置的端點不支持logprobs參數(shù)返回的 teacher logprobs 全是默認值。二是 hint 提取失敗drop_sample_without_hint設為false導致沒有 hint 的樣本也進入訓練teacher context 和 student context 完全一樣。三是teacher_scoring_mode設成了generate而不是forced導致 teacher 重新生成了響應和原響應的 token 對不上。排查方法在compute_advantages_and_returns里加一行日志打印teacher_log_probs[0][:10]和student_log_probs[0][:10]看兩者是否完全相同。5.2 hint 提取質量差judge 模型如果太小或者 prompt 設計不好抽出來的 hint 可能是“你需要改進”這種沒有方向性的廢話。解決辦法是調整 judge 的 system prompt明確要求輸出可執(zhí)行的指令比如“先做 X 再做 Y”或“不要包含 Z”。另外judge_vote_count設為 3 可以通過多數(shù)投票過濾掉低質量 hint。5.3 teacher logprobs 長度對不上OPD 要求 teacher logprobs 和 student logprobs 在 response 部分逐 token 對齊。如果 teacher scoring 時 max_tokens 設得太小或者 response_length 計算有誤就會出現(xiàn)長度不匹配。代碼里用t_log_prob[-response_length:]做截斷但如果 teacher 返回的序列比 response 短截斷后長度仍然不對。排查方法打印len(teacher_log_prob)和response_length確認 teacher 返回的 logprobs 長度大于等于 response_length。5.4 訓練啟動后 OOMOPD 需要同時維護 student 和 teacher 兩份 logprobs顯存占用比普通 RL 高。如果max_seq_len設為 8192 且rollout_batch_size設為 32在單卡上很容易 OOM。建議先把rollout_batch_size降到 8max_seq_len降到 4096跑通后再逐步調大。5.5 Top-K OPD 的 custom loss 報錯變體 B 需要指定custom_loss_function_path如果路徑不對或者文件里沒有正確導出 loss 函數(shù)訓練會直接報ImportError。確認你的topk_reverse_kl.py里定義了compute_loss函數(shù)并且簽名和框架期望的一致。6. 接入文檔與后續(xù)調試路徑OPD 的配置骨架搭好之后下一步是把它接到真實的 Agent 交互循環(huán)里。OpenClaw-RL 的 passive rollout 模式會攔截 SGLang 的 API 請求把用戶對話和工具返回結果作為 next-state signal 收集起來。你需要確保session_timeout_sec和max_turns_per_session設置合理否則長會話會被截斷hint 提取拿不到完整的上下文。如果你在接入過程中遇到 API 報錯或者 logprobs 返回格式不對可以先到接入文檔 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 核對請求參數(shù)。模型對話頁面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 可以用來快速測試 judge prompt 的效果不用每次都跑完整訓練腳本。對于需要長期跑 OPD 訓練的任務建議把 API Key 和端點配置放在環(huán)境變量里不要硬編碼在 config.toml 中。這樣切換環(huán)境時只需要改環(huán)境變量不用動配置文件。最后說一個實際調試中的小技巧在 OPD 訓練的前 100 步把log_teacher_logprobs設為true把每個樣本的 teacher 和 student logprobs 差值保存下來。跑完之后統(tǒng)計一下 advantage 的分布如果發(fā)現(xiàn)某些 token 的 advantage 絕對值特別大比如超過 10說明 teacher 和 student 在這些 token 上的分歧過大可能需要調低學習率或者加 advantage clip。這個統(tǒng)計比看 loss 曲線更能反映 OPD 信號的質量。