化學(xué)習(xí) / OPD】OpenClaw-RL 源碼閱讀筆記 --- (10)--- PRM 與 TaoToken 配置實(shí)戰(zhàn))
1. 從一次 PRM 打分失敗說起OpenClaw-RL 源碼閱讀里最容易卡住的環(huán)節(jié)如果你正在讀 OpenClaw-RL 的源碼大概率會(huì)在 PRM 這一層停下來。原因不復(fù)雜這個(gè)項(xiàng)目里叫 PRM 的東西跟教科書上的 Process Reward Model 不是一回事。它本質(zhì)是一個(gè) zero-shot LLM Judge用同族模型Qwen3通過 prompt 對(duì)整條 response 打\boxed{1}/\boxed{0}/\boxed{-1}再做 majority vote 降噪。理解這一點(diǎn)之后源碼里那些_build_prm_judge_prompt、_majority_vote、at-least-one guarantee的寫法就順了。但真正讓人卡住的不是概念是環(huán)境。OpenClaw-RL 的 PRM Server 是一個(gè)獨(dú)立的 SGLangRouter 進(jìn)程Policy Server 是另一個(gè) FastAPI 服務(wù)兩者通過 HTTP 通信。你在本地想跑通一次 PRM 打分鏈路需要同時(shí)把 Judge 模型的推理端點(diǎn)、Policy 側(cè)的調(diào)用地址、以及訓(xùn)練腳本里的模型 ID 對(duì)齊。任何一處不一致就會(huì)看到local proxy failed或者reading choices這類報(bào)錯(cuò)。這篇筆記的目標(biāo)很具體在源碼閱讀的過程中用 TaoToken 統(tǒng)一 Key/API 通道把本地 PRM 打分鏈路跑通一次。你會(huì)拿到可復(fù)制的 settings 配置片段、Base URL 寫法、Model ID 對(duì)照以及從_prm_evaluate到_majority_vote的完整驗(yàn)證步驟。適合已經(jīng)在讀 OpenClaw-RL 源碼、想動(dòng)手驗(yàn)證 PRM 模塊行為的人。先說清楚 TaoToken 在這里扮演什么角色。它是一個(gè)統(tǒng)一的模型 API 通道把不同廠商的模型收斂到同一個(gè) Base URL 和同一套 Key 體系下。對(duì) OpenClaw-RL 這種需要同時(shí)調(diào)用 Judge 模型和 Policy 模型的框架來說好處是你不用為每個(gè)模型單獨(dú)維護(hù) endpoint 和鑒權(quán)。官網(wǎng)入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 根地址是 https://taotoken.net/api 。我試過在本地把 PRM Judge 指向 TaoToken 的通道然后用一個(gè)最小的 Python 腳本模擬_prm_evaluate的調(diào)用確認(rèn)返回的\boxed{}能被正確解析。下面把整個(gè)過程拆開寫。2. TaoToken 前置準(zhǔn)備Key、Base URL 與 PRM Judge 模型選型在動(dòng) OpenClaw-RL 的代碼之前先把 TaoToken 側(cè)的三個(gè)東西準(zhǔn)備好API Key、Base URL、以及你要用作 PRM Judge 的 Model ID。這三樣?xùn)|西后面會(huì)同時(shí)出現(xiàn)在 settings 配置和源碼里的self._prm_url調(diào)用中。2.1 獲取 API Key 與確認(rèn) Base URL登錄 TaoToken 控制臺(tái)后在 API Keys 頁面創(chuàng)建一個(gè)新的 Key。這個(gè) Key 是后續(xù)所有請求的鑒權(quán)憑證??刂婆_(tái)地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API Keys 管理頁在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。創(chuàng)建完成后你會(huì)拿到一串以sk-開頭的字符串。把它存到環(huán)境變量里不要硬編碼進(jìn)源碼export TAOTOKEN_API_KEYsk-你的實(shí)際Key export TAOTOKEN_BASE_URLhttps://taotoken.net/api注意 Base URL 是https://taotoken.net/api不帶任何路徑后綴。OpenClaw-RL 里 SGLang 的調(diào)用習(xí)慣是往 Base URL 后面拼/v1/chat/completions所以你在配置里填的應(yīng)該是根地址讓框架自己去拼路徑。這一點(diǎn)如果搞反了會(huì)直接導(dǎo)致 404。2.2 PRM Judge 的 Model ID 怎么選OpenClaw-RL 源碼里 PRM 用的是同族 Qwen3 模型做 zero-shot 評(píng)分。你在 TaoToken 通道下選 Model ID 時(shí)要選一個(gè)指令跟隨能力足夠強(qiáng)、能穩(wěn)定輸出\boxed{}格式的模型。因?yàn)?PRM 的 prompt 里明確要求 give your final score inside \boxed{}模型如果格式跟隨不好解析就會(huì)失敗。在 TaoToken 的模型列表里確認(rèn)你要用的 Model ID。常見的做法是選一個(gè)中等規(guī)模的指令模型作為 Judge因?yàn)?PRM 每個(gè) turn 要跑 m3 次投票成本是 Policy 推理的三倍。Model ID 的準(zhǔn)確字符串以控制臺(tái)模型列表為準(zhǔn)不要憑記憶寫。你可以先用模型對(duì)話頁面快速驗(yàn)證一下模型能不能按格式輸出。對(duì)話入口在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。把 PRM 的 system prompt 貼進(jìn)去看它是否返回帶\boxed{1}的回復(fù)。這一步花兩分鐘能省掉后面半小時(shí)的解析調(diào)試。2.3 三件套對(duì)照表把下面這張表填好后面配置時(shí)直接抄配置項(xiàng)值出現(xiàn)位置Base URLhttps://taotoken.net/apisettings、self._prm_urlAPI Keysk-...環(huán)境變量、請求頭Model ID控制臺(tái)確認(rèn)的字符串PRM Judge 調(diào)用參數(shù)這三件套在 OpenClaw-RL 里會(huì)出現(xiàn)在兩個(gè)地方一是 Policy Server 轉(zhuǎn)發(fā)請求時(shí)的上游地址二是 PRM Server 自己作為 Judge 被調(diào)用時(shí)的模型參數(shù)。如果你用的是 CC Switch 或 Cline MCP 這類工具來管理多模型配置也要把這三個(gè)值填進(jìn)對(duì)應(yīng)的 provider 配置里。3. 可復(fù)制配置settings 片段與 PRM 調(diào)用參數(shù)對(duì)齊這一節(jié)給你可以直接復(fù)制的配置片段。OpenClaw-RL 的配置分散在幾個(gè)地方訓(xùn)練腳本的環(huán)境變量、SGLangRouter 的啟動(dòng)參數(shù)、以及 Policy Server 的上游地址。我們逐個(gè)對(duì)齊。3.1 環(huán)境變量配置片段在訓(xùn)練腳本的啟動(dòng)環(huán)境里把 PRM 相關(guān)的變量指向 TaoToken 通道。下面是一個(gè)可復(fù)制的 shell 片段# TaoToken 統(tǒng)一通道 export TAOTOKEN_API_KEYsk-你的實(shí)際Key export TAOTOKEN_BASE_URLhttps://taotoken.net/api # PRM Judge 配置對(duì)應(yīng)源碼里的 self._prm_url 與 PRM_MODEL_PATH export PRM_BASE_URL${TAOTOKEN_BASE_URL} export PRM_API_KEY${TAOTOKEN_API_KEY} export PRM_MODEL_ID你在控制臺(tái)確認(rèn)的Model ID export PRM_M3 # Policy Server 上游對(duì)應(yīng) openclaw_opd_api_server.py 的轉(zhuǎn)發(fā)目標(biāo) export POLICY_UPSTREAM_BASE_URL${TAOTOKEN_BASE_URL} export POLICY_UPSTREAM_API_KEY${TAOTOKEN_API_KEY} export POLICY_MODEL_ID你的Policy模型ID # 服務(wù)端口 export HOST0.0.0.0 export PORT30000這里的關(guān)鍵是PRM_BASE_URL和POLICY_UPSTREAM_BASE_URL都指向同一個(gè) TaoToken 根地址。OpenClaw-RL 的架構(gòu)里PRM Server 和 Policy Server 是兩個(gè)獨(dú)立進(jìn)程但它們可以共用同一個(gè)上游通道只是用的 Model ID 不同。3.2 JSON 格式的 provider 配置如果你用 CC Switch 或類似的配置管理工具下面是一個(gè) JSON 片段把 TaoToken 作為一個(gè) provider 注冊進(jìn)去{ providers: { taotoken: { base_url: https://taotoken.net/api, api_key: ${TAOTOKEN_API_KEY}, models: { prm_judge: 你在控制臺(tái)確認(rèn)的Judge模型ID, policy: 你的Policy模型ID } } }, prm: { provider: taotoken, model: prm_judge, majority_vote_m: 3, timeout_seconds: 60 } }這個(gè)片段里的base_url和api_key就是三件套里的前兩件model字段對(duì)應(yīng)第三件。majority_vote_m對(duì)應(yīng)源碼里的PRM_M3。3.3 TOML 格式如果你用 Codex 風(fēng)格的配置有些工具鏈用 TOML 管理配置。下面是對(duì)應(yīng)的寫法[providers.taotoken] base_url https://taotoken.net/api api_key ${TAOTOKEN_API_KEY} [prm] provider taotoken model 你在控制臺(tái)確認(rèn)的Judge模型ID majority_vote_m 3 [policy] provider taotoken model 你的Policy模型ID3.4 源碼里self._prm_url的對(duì)齊OpenClaw-RL 的openclaw_api_server.py里PRM 調(diào)用是通過self._prm_url發(fā)起的。你需要確保這個(gè) URL 的構(gòu)造方式跟你的配置一致。源碼里通常是這樣的模式# 源碼中的調(diào)用模式示意 self._prm_url f{PRM_BASE_URL}/v1/chat/completions headers {Authorization: fBearer {PRM_API_KEY}} payload { model: PRM_MODEL_ID, messages: _build_prm_judge_prompt(response_text, ns_text, ns_role), temperature: 0.7, max_tokens: 512, }注意temperature這里不是 0。源碼里 PRM 的隨機(jī)性是有意保留的因?yàn)楹竺嬉?majority vote 降噪。如果你把 temperature 設(shè)成 0三次投票結(jié)果會(huì)完全一樣majority vote 就失去意義了。_build_prm_judge_prompt返回的是一個(gè) messages 列表里面包含 system prompt 和 user prompt。system prompt 里寫明了評(píng)分規(guī)則user prompt 里放了response_text和next_state_text。這個(gè)結(jié)構(gòu)跟 OpenAI 兼容的 chat completions 格式一致所以直接指向 TaoToken 的/v1/chat/completions就能用。3.5 一個(gè)容易忽略的點(diǎn)next_state_role源碼里_build_prm_judge_prompt的簽名是(response_text, next_state_text, next_state_role)。next_state_role有兩個(gè)取值user和tool。這個(gè)參數(shù)會(huì)拼進(jìn) user prompt 里告訴 Judge 這條 next_state 是用戶回復(fù)還是工具返回值。如果你在本地構(gòu)造測試數(shù)據(jù)時(shí)忘了傳這個(gè)參數(shù)Judge 的評(píng)分依據(jù)會(huì)不完整可能給出偏中性的分?jǐn)?shù)。在配置層面這個(gè)參數(shù)不需要你設(shè)置它是運(yùn)行時(shí)從對(duì)話歷史里推斷的。但你在寫驗(yàn)證腳本時(shí)要手動(dòng)指定否則測出來的分?jǐn)?shù)不能反映真實(shí)行為。4. 驗(yàn)證請求跑通一次 PRM 打分鏈路配置對(duì)齊之后下一步是實(shí)際發(fā)一次請求確認(rèn) PRM 打分鏈路能跑通。我們分兩步先用 curl 直接打 TaoToken 通道確認(rèn)鑒權(quán)和模型可用再用 Python 模擬_prm_evaluate的完整流程包括 majority vote。4.1 用 curl 驗(yàn)證通道連通性先構(gòu)造一個(gè)最小的 PRM 評(píng)分請求。下面這個(gè) curl 命令模擬了 Judge 收到一條 response 和一條 next_state 后的評(píng)分過程curl -s https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer ${TAOTOKEN_API_KEY} \ -H Content-Type: application/json \ -d { model: ${PRM_MODEL_ID}, messages: [ { role: system, content: You are a process reward model (PRM) evaluating an AI assistant. Decide whether the assistant output successfully fulfilled the user intent, using the next state as evidence. Scoring rules: boxed{1} good, boxed{-1} bad, boxed{0} neutral. Think step-by-step, then give your final score inside boxed{}. }, { role: user, content: ## Assistant response (turn t)\nThe square root of 1764 is 42.\n\n## Next state (turn t1) [role: user]\nGreat, that is correct. Can you also compute the square root of 2025?\n\nNow output your decision. } ], temperature: 0.7, max_tokens: 512 }如果通道正常你會(huì)拿到一個(gè) JSON 響應(yīng)choices[0].message.content里應(yīng)該包含\boxed{1}。這一步驗(yàn)證了三件事Key 有效、Base URL 正確、Model ID 存在。如果返回 401說明 Key 沒傳對(duì)或者過期了。如果返回 404大概率是 Base URL 多寫了或漏寫了路徑。如果返回的 content 里沒有\(zhòng)boxed{}說明模型格式跟隨不好換一個(gè) Model ID 試試。4.2 用 Python 模擬_prm_evaluate與 majority votecurl 通了之后寫一個(gè) Python 腳本完整模擬源碼里的評(píng)分流程。這個(gè)腳本會(huì)調(diào)用三次 Judge然后做 majority voteimport os import re from collections import Counter import requests BASE_URL os.environ[TAOTOKEN_BASE_URL] API_KEY os.environ[TAOTOKEN_API_KEY] MODEL_ID os.environ[PRM_MODEL_ID] PRM_M int(os.environ.get(PRM_M, 3)) def build_prm_judge_prompt(response_text, next_state_text, next_state_roleuser): system ( You are a process reward model (PRM) evaluating an AI assistant. Decide whether the assistant output successfully fulfilled the user intent, using the next state as evidence. Scoring rules: boxed{1} good, boxed{-1} bad, boxed{0} neutral. Think step-by-step, then give your final score inside boxed{}. ) user ( f## Assistant response (turn t)\n{response_text}\n\n f## Next state (turn t1) [role: {next_state_role}]\n{next_state_text}\n\n Now output your decision. ) return [{role: system, content: system}, {role: user, content: user}] def query_judge_once(messages): resp requests.post( f{BASE_URL}/v1/chat/completions, headers{Authorization: fBearer {API_KEY}}, json{ model: MODEL_ID, messages: messages, temperature: 0.7, max_tokens: 512, }, timeout60, ) resp.raise_for_status() content resp.json()[choices][0][message][content] match re.search(r\\boxed\{(-?[01])\}, content) if not match: return None return int(match.group(1)) def majority_vote(scores): valid [s for s in scores if s is not None] if not valid: return 0.0 counter Counter(valid) top counter.most_common(1)[0] if list(counter.values()).count(top[1]) 1: return 0.0 return float(top[0]) def prm_evaluate(response_text, next_state_text, next_state_roleuser): messages build_prm_judge_prompt(response_text, next_state_text, next_state_role) scores [query_judge_once(messages) for _ in range(PRM_M)] return majority_vote(scores), scores if __name__ __main__: score, raw prm_evaluate( response_textThe square root of 1764 is 42., next_state_textGreat, that is correct. Can you also compute the square root of 2025?, next_state_roleuser, ) print(fraw scores: {raw}) print(ffinal score: {score})這個(gè)腳本里的majority_vote函數(shù)跟源碼里的_majority_vote邏輯一致過濾 None取眾數(shù)平票返回 0.0。prm_evaluate對(duì)應(yīng)源碼里的_prm_evaluate內(nèi)部調(diào)用_query_judge_once三次。4.3 預(yù)期結(jié)果與解讀跑通之后你會(huì)看到類似這樣的輸出raw scores: [1, 1, 1] final score: 1.0或者raw scores: [1, 1, -1] final score: 1.0如果三次投票結(jié)果不一致比如[1, -1, 0]最終分?jǐn)?shù)會(huì)是 0.0對(duì)應(yīng)源碼里的平票保守策略。這個(gè)行為在訓(xùn)練時(shí)意味著這個(gè) turn 的loss_mask會(huì)被設(shè)為 0不參與梯度更新。你可以改一下response_text故意給一個(gè)錯(cuò)誤答案比如 The square root of 1764 is 43.看 Judge 是否給出 -1。這一步能驗(yàn)證 Judge 的判別能力是否符合預(yù)期。4.4 驗(yàn)證 at-least-one guarantee源碼里有一個(gè)特殊邏輯當(dāng)一個(gè) session 的所有 turn 評(píng)分都是 0 時(shí)強(qiáng)制把第一條被評(píng)估的 turn 的loss_mask設(shè)為 1。你可以在腳本里模擬這個(gè)場景連續(xù)構(gòu)造幾條中性反饋看最終是否有至少一條樣本被保留。這個(gè)邏輯在源碼里的位置是_submit_turn_sample()核心判斷是self._session_effective.get(session_id, 0) 0。你不需要在驗(yàn)證腳本里完全復(fù)現(xiàn)但要知道它的存在因?yàn)檎{(diào)試訓(xùn)練信號(hào)消失問題時(shí)這個(gè)保底機(jī)制是第一個(gè)要檢查的點(diǎn)。5. 常見報(bào)錯(cuò)排查401、local proxy failed、reading choices、OAuth這一節(jié)對(duì)照真實(shí)報(bào)錯(cuò)給出排查路徑。這些報(bào)錯(cuò)是 OpenClaw-RL 本地配置時(shí)最常遇到的。5.1 401 Unauthorized報(bào)錯(cuò)長這樣{error: {message: Invalid API key, type: invalid_request_error}}原因通常是 Key 沒傳對(duì)。檢查三處環(huán)境變量TAOTOKEN_API_KEY是否導(dǎo)出成功、請求頭里的Authorization是否是Bearer sk-...格式、Key 是否在控制臺(tái)被禁用或刪除。一個(gè)容易忽略的點(diǎn)如果你在 shell 里export了 Key但在另一個(gè)終端窗口跑腳本那個(gè)窗口是拿不到這個(gè)環(huán)境變量的。用echo $TAOTOKEN_API_KEY確認(rèn)一下。5.2 local proxy failed報(bào)錯(cuò)長這樣local proxy failed: connection refused這個(gè)報(bào)錯(cuò)通常出現(xiàn)在 Policy Server 轉(zhuǎn)發(fā)請求到上游時(shí)。OpenClaw-RL 的 Policy Server 監(jiān)聽 30000 端口它會(huì)把請求轉(zhuǎn)發(fā)到POLICY_UPSTREAM_BASE_URL。如果這個(gè)地址填的是localhost或某個(gè)不存在的端口就會(huì) connection refused。檢查POLICY_UPSTREAM_BASE_URL是否指向https://taotoken.net/api。如果你之前把它填成了本地 SGLang 的地址比如http://localhost:8000改成 TaoToken 的根地址。另一個(gè)可能你的本地網(wǎng)絡(luò)環(huán)境對(duì)taotoken.net的解析有問題。用curl -v https://taotoken.net/api/v1/chat/completions看一下連接過程確認(rèn) DNS 解析和 TLS 握手正常。5.3 reading choices 相關(guān)報(bào)錯(cuò)報(bào)錯(cuò)長這樣KeyError: choices或者IndexError: list index out of range這個(gè)報(bào)錯(cuò)說明響應(yīng) JSON 里沒有choices字段或者choices是空列表。原因通常是上游返回了一個(gè)錯(cuò)誤響應(yīng)但你的代碼直接去取choices[0]了。排查方法在解析響應(yīng)之前先把原始響應(yīng)打出來。在query_judge_once里加一行print(resp.text)看上游到底返回了什么。常見的情況是返回了{(lán)error: ...}但代碼沒檢查resp.status_code就直接解析。源碼里的_query_judge_once有對(duì)響應(yīng)的校驗(yàn)邏輯你在本地復(fù)現(xiàn)時(shí)要確保這部分沒被跳過。5.4 OAuth 相關(guān)報(bào)錯(cuò)報(bào)錯(cuò)長這樣OAuth token expired或者invalid_grant如果你用的是 Codex 風(fēng)格的auth.json來管理憑證可能會(huì)遇到這個(gè)。auth.json里的 token 有過期時(shí)間過期后需要刷新。檢查你的auth.json里expires_at字段是否已經(jīng)過了當(dāng)前時(shí)間。如果你同時(shí)用 TaoToken 的 API Key 和某個(gè) OAuth 憑證確認(rèn)請求走的是哪條路徑。OpenClaw-RL 的 PRM 調(diào)用應(yīng)該走 API Key 路徑不走 OAuth。如果配置里混了把 OAuth 相關(guān)的字段清掉只保留base_url、api_key、model三件套。5.5 報(bào)錯(cuò)對(duì)照表報(bào)錯(cuò)關(guān)鍵詞最可能原因檢查點(diǎn)401 UnauthorizedKey 無效或未傳環(huán)境變量、請求頭格式local proxy failed上游地址錯(cuò)誤POLICY_UPSTREAM_BASE_URLreading choices響應(yīng)無 choices 字段先打印原始響應(yīng)OAuth token expired憑證過期auth.json的expires_atboxed 解析失敗模型格式跟隨差換 Model ID 或調(diào) prompt5.6 一個(gè)隱蔽的坑temperature 與投票如果你把 PRM 的temperature設(shè)成 0三次投票會(huì)返回完全一樣的結(jié)果。這時(shí)候 majority vote 看起來總是通過但實(shí)際上沒有起到降噪作用。源碼里默認(rèn) temperature 是大于 0 的你在配置時(shí)不要為了穩(wěn)定把它改成 0。反過來如果 temperature 太高比如 1.5三次投票可能給出三個(gè)不同結(jié)果最終平票返回 0.0導(dǎo)致大量樣本被丟棄。建議保持在 0.7 左右跟源碼默認(rèn)值對(duì)齊。6. 繼續(xù)深入從 PRM 打分到 OPD 與 Combine 的配置延伸跑通 PRM 打分鏈路之后你可以沿著源碼繼續(xù)往下讀。OpenClaw-RL 的 PRM 在兩個(gè)分支里扮演不同角色Binary RL 分支里它是評(píng)分員輸出 ±1/0 直接作為 rewardOPD 分支里它是 hint 提取器輸出[HINT_START]...[HINT_END]文本再喂給 teacher 做 forward pass。如果你要驗(yàn)證 OPD 分支需要額外配置 teacher 模型的調(diào)用。teacher 也可以走 TaoToken 通道只是 Model ID 換成 teacher 對(duì)應(yīng)的模型。配置結(jié)構(gòu)跟 PRM 一樣三件套對(duì)齊即可。Combine 分支則是同時(shí)跑兩條路徑同一個(gè) turn 并發(fā)發(fā)起 PRM eval 和 hint judge 兩種 prompt分別決定是否發(fā) RL 樣本和 OPD 樣本。這時(shí)候你的 TaoToken 通道會(huì)同時(shí)承載 Judge 調(diào)用和 teacher 調(diào)用注意并發(fā)量和超時(shí)設(shè)置。對(duì)于長期跑編碼或 Agent 任務(wù)的場景可以考慮用 Coding Plan 來管理調(diào)用配額入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。如果你的驗(yàn)證腳本需要頻繁調(diào)用模型接入文檔在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 有更詳細(xì)的參數(shù)說明。最后留一個(gè)實(shí)用技巧在本地調(diào)試 PRM 時(shí)把每次 Judge 的原始響應(yīng)寫到日志文件里包括response_text、next_state_text、raw_scores、final_score。這樣當(dāng)你發(fā)現(xiàn)某個(gè) turn 的評(píng)分不符合預(yù)期時(shí)可以回溯到具體的 Judge 輸出看是 prompt 構(gòu)造問題還是模型判斷問題。這個(gè)日志在源碼里沒有現(xiàn)成的需要你自己在_query_judge_once外面包一層。