浙江大学联合小米做奖励模型,TaoToken 只提供 Key 1. 判分脚本翻车的两个高频现场给 GUI Agent 轨迹打 0/1 的同学大概率都遇到过这两种翻车一种是 VLM judge 返回的 rubric 字段永远只有任务是否完成这一句万能话同一批轨迹换个 App 就集体误判另一种是换了更强的视觉模型当 judge准确率没涨多少token 账单先翻了倍。复现这类奖励模型第一步往往不是调 prompt而是先把 judge 的模型访问通道配通——去 TaoToken 官网 创建 KeyBase URL 写https://taotoken.net/api其余才是 rubric 工程。TaoToken 在这里只做一件事提供 Key 和兼容端点判分逻辑、准则生成、指标计算全部在本地脚本里完成。浙大联合小米MiLM Plus的 ADAPT RUBRIC 工作恰好把判错的根因说得很清楚验证器在打分之前手里根本没有一条贴合当前指令的判断标准。静态模板只关心做完没不关心对象、数值、范围、格式让模型自由推理又容易漏掉关键约束或者自己加戏变成过度严苛。这篇笔记不复述论文而是把它的粗到细流水线拆成能在本地跑的工程代码给出可复现的 judge 调用示例与评测指标脚本。论文题目是Task-Adaptive Rubrics for GUI Reward Modeling核心链路只有三段类别级粗准则检索、实例级细准则生成、准则融合与奖励验证。工程上最有价值的一点是——它完全不动 judge 的架构只改喂进去的判分标准和轨迹上下文。这意味着你可以把任意 VLM 换进 judge 位只要把准则拼对。2. 粗准则与细准则把出题这一步做对2.1 类别级粗准则先给任务族立边界粗准则解决的是这一类任务该查什么。论文的做法是做一次离线归纳把类别级准则库固化下来之后推理阶段不再变更胜在可复现、可对比。具体流程是从现有 GUI Agent 基准的开发轨迹池里采样成功与失败样本让 LLM 总结出能区分两者的验证维度再把维度归并成若干大类。每个类别条目里包含四块内容——验证步骤、常见坑点、特殊规则、输出格式。推理时新指令先经过一个轻量任务路由器预测类别再从库里取出对应粗准则如果路由器认不出专门类别就退回通用兜底条目。这一步的工程价值在于给验证器立下清晰的任务族边界。比如通信类要重点核对收件人、正文内容、发送确认三处创建/修改类则要确认对象是否真正落地成功而不是停留在编辑态。它回答的是跨任务时统一查什么的框架问题。一个容易踩的坑是准则库一旦离线固化新增应用类别就得重新走一遍归纳流程。论文自己也提到评分银行离线建好、评测期间固定可复现性好但可能跟不上新出现的应用或领域专属流程。工程上的折中方案是把准则库存成 JSON用版本号管理路由器预测置信度低于阈值时走兜底条目并单独记日志后续按日志回流补类。2.2 实例级细准则补上粗准则看不到的细节粗准则只知道这一类查什么但当前指令里的具体数值、范围、约束它一无所知。同样归到通信任务里把 Mike 的安全公告同步到 Mastodon、保持原文、仅粉丝可见、并打上 openCompany 标签——收件人、可见性、标签、正文格式这些都是只属于这一条指令的细粒度要求粗准则不可能预先写死。于是第二级让一个 Rubric 生成器根据指令、类别、粗准则产出最多两条实例级细准则。它不去重写粗准则只补当前指令独有且必须检查的额外项。论文给生成器加了三条硬约束这三条在工程实现里建议直接写进 system prompt并且用后置校验兜底指令扎根Instruction Grounding每条细准则都必须能在用户指令原文里找到明确的短语、数值或约束作为依据。杜绝模型自己加戏。紧凑Compactness最多 2 条只高亮最有用的实例级要求避免退化成一份冗长 checklist。可弃权Abstention当指令确实不需要额外细项时直接返回空不强行补。这三条约束的工程含义是把细准则的发散风险关在笼子里。如果放开条数限制生成器会开始制造准则judge 的误判率反而上升。2.3 融合策略主体 独立任务块拿到粗准则和细准则之后融合方式比想象中简单粗准则作为主体细准则作为独立的任务专属块追加在后面如果细准则弃权就只保留粗准则。不建议把两级准则做语义压缩再合并。保持分块、保持编号judge 在输出命中项时能直接引用准则编号便于事后归因。下面是本地可跑的准则融合函数def build_rubric(coarse: dict, fine: list[str]) - str: 把粗准则与细准则拼成稳定可复现的判分标准。 lines [f[类别] {coarse[category]}, [粗准则]] for i, step in enumerate(coarse[steps], 1): lines.append(fC{i}. {step}) if coarse.get(pitfalls): lines.append([常见坑点]) lines.extend(fP{i}. {p} for i, p in enumerate(coarse[pitfalls], 1)) if fine: lines.append([本任务专属细准则]) lines.extend(fF{i}. {t} for i, t in enumerate(fine[:2], 1)) return \n.join(lines)注意fine[:2]这个截断——它是紧凑约束在代码层的最后一道保险无论生成器返回多少条进 judge 的细准则不会超过两条。3. 用 TaoToken 的兼容端点驱动 VLM judge3.1 Key 与 Base URL 的正确写法在调用 judge 之前先在 TaoToken 控制台 创建 API Key然后按下面的方式配置环境变量。Base URL 只写https://taotoken.net/api不要附加任何查询参数——UTM 只用于官网跳转统计混进 SDK 的 base_url 会导致路径拼接异常。# macOS / Linux写入 shell 配置后重新打开终端 export TAOTOKEN_API_KEYYOUR_API_KEY # Windows PowerShell$env:TAOTOKEN_API_KEY YOUR_API_KEY三个必须在工程里固定的约定base_url恒为https://taotoken.net/api不随环境切换而变Key 只从环境变量读取绝不硬编码进仓库模型名从控制台可用列表里选不要凭经验猜。3.2 最小可跑的 judge 调用judge 的输入是精选上下文 用户指令 融合准则输出是 0/1 判断。下面这段是可直接复用的最小实现图片按帧顺序传入且强制要求结构化输出import base64 import json import os import re from openai import OpenAI BASE_URL https://taotoken.net/api client OpenAI( api_keyos.environ.get(TAOTOKEN_API_KEY, YOUR_API_KEY), base_urlBASE_URL, ) JUDGE_SYSTEM 你是 GUI 轨迹结果验证器。 你只能依据给定的判分准则做二值判断不得引入准则之外的新要求。 输出严格 JSON不要输出任何解释性前后缀 {success: true 或 false, hit: [命中的准则编号], reason: 简短依据} def to_image_block(png_path: str) - dict: with open(png_path, rb) as f: b64 base64.b64encode(f.read()).decode(utf-8) return { type: image_url, image_url: {url: fdata:image/png;base64,{b64}, detail: low}, } def judge_trajectory(instruction: str, rubric: str, frames: list[str], model: str) - dict: content [{type: text, text: f用户指令\n{instruction}\n\n判分准则\n{rubric}}] content [to_image_block(p) for p in frames] resp client.chat.completions.create( modelmodel, temperature0, max_tokens256, messages[ {role: system, content: JUDGE_SYSTEM}, {role: user, content: content}, ], ) raw resp.choices[0].message.content or match re.search(r\{.*\}, raw, re.S) if not match: return {success: None, hit: [], reason: parse_error, raw: raw} try: parsed json.loads(match.group(0)) except json.JSONDecodeError: return {success: None, hit: [], reason: json_error, raw: raw} parsed[usage] { prompt_tokens: resp.usage.prompt_tokens, completion_tokens: resp.usage.completion_tokens, } return parsed两个工程细节值得强调temperature0是判分任务的基本要求同一轨迹两次调用结果漂移会让归因彻底失效detail: low能显著压低图片 token 消耗对看状态是否切换这类判断足够用只有在需要读取细小文本时才切成 high。3.3 轨迹上下文精选先砍帧再谈 token完整轨迹动辄几十帧全部喂进 judge 既贵又容易让模型看花眼。论文的思路是只保留高信号帧初始帧、终止帧以及文本输入、提交、状态切换等关键动作附近的帧。本地实现可以把这一步做成一个纯规则函数不依赖任何模型调用KEY_ACTIONS {type, press, submit, click_submit, toggle} def select_frames(steps: list[dict], max_frames: int 10) - list[str]: 按动作类型挑选高信号帧首帧 尾帧 关键动作帧。 if len(steps) max_frames: return [s[screenshot] for s in steps] picked [0, len(steps) - 1] for idx, s in enumerate(steps): if s.get(action) in KEY_ACTIONS: picked.append(idx) picked sorted(set(picked)) if len(picked) max_frames: head, tail picked[0], picked[-1] mid [i for i in picked if i not in (head, tail)][: max_frames - 2] picked [head] mid [tail] return [steps[i][screenshot] for i in picked]帧预算建议固定成常量并写进实验配置。论文的离线对比是在最多看 10 张截图这个同等条件下做的帧预算不一致的对比没有意义。也别把帧数当成可调超参去刷分它影响的是成本与稳定性不是方法本身的贡献。4. 细准则生成器的实现与三条约束校验生成器本身是一次普通文本调用成本远低于 judge 的多图调用。但它的输出质量直接决定 judge 的判分上限。FINE_SYSTEM 你负责为一条 GUI 指令生成实例级细准则。 规则 1. 每条准则必须能在用户指令原文中找到对应短语、数值或约束 2. 最多输出 2 条只保留最容易漏检的实例级要求 3. 如果该指令不需要额外细项直接返回 {rules: []}。 输出 JSON{rules: [..., ...]} def gen_fine_rules(instruction: str, coarse_summary: str, model: str) - list[str]: resp client.chat.completions.create( modelmodel, temperature0, max_tokens200, messages[ {role: system, content: FINE_SYSTEM}, {role: user, content: f指令{instruction}\n类别准则摘要{coarse_summary}}, ], ) raw resp.choices[0].message.content or {} try: rules json.loads(raw).get(rules, []) except json.JSONDecodeError: return [] return rules[:2]光靠 prompt 约束不够建议再加一层词面校验把每条细准则里的关键实体数字、专有名词、标签逐一在指令原文里做子串匹配匹配不上就直接丢弃该条。这一步能挡掉大部分模型自己加戏的情况而且完全不额外消耗 token。生成器和 judge 建议使用不同角色配置生成器面向指令做抽取judge 面向准则做判定。两者共用同一个 Base URL 和 Key不必再开第二套账号。5. 评测指标准确率、F1 与失败误判率一起看判分器好不好不能只看准确率。GUI 轨迹判分天然是不平衡任务失败样本占比高时一个全判失败的退化模型也能拿到看起来很漂亮的准确率。所以本地评测脚本至少要同时输出四个数字准确率、F1、召回、以及把失败轨迹错判为成功的比例FSR。def evaluate(y_true: list[int], y_pred: list[int]) - dict: tp sum(1 for t, p in zip(y_true, y_pred) if t 1 and p 1) fp sum(1 for t, p in zip(y_true, y_pred) if t 0 and p 1) fn sum(1 for t, p in zip(y_true, y_pred) if t 1 and p 0) tn sum(1 for t, p in zip(y_true, y_pred) if t 0 and p 0) prec tp / (tp fp) if tp fp else 0.0 rec tp / (tp fn) if tp fn else 0.0 f1 2 * prec * rec / (prec rec) if prec rec else 0.0 total len(y_true) or 1 return { acc: (tp tn) / total, precision: prec, recall: rec, f1: f1, fsr: fp / (fp tn) if fp tn else 0.0, }论文在 OGRBench 上1409 条跨 Ubuntu / 安卓 / Windows / macOS / Web 的轨迹给出的数字是准确率 86.7%、F1 86.6在同等最多看 10 张截图条件下比两个对照方法的平均 F1 高 3.6 个点提升主要来自召回——能认出更多实际成功的轨迹同时没有把误判率推高。在线训练侧用这套判分器给 GRPO 当奖励信号训练 MAI-UI-8B任务成功率从 19.70% 提到 23.93%净增 4.23 个点是对照奖励方案里最高的。测试时筛选场景中同一道题采样多条候选轨迹再用判分器挑最优相比随机挑选EarlyStop 与 Best-of-N 两种策略下分别多 11.88 和 13.28 个点失败轨迹被误判为成功的比例压在 11.17%。消融实验显示两级准则是互补的去掉细准则 F1 掉 2.0去掉粗准则同样掉 2.0两级都不要、直接让模型看截图硬判掉 5.9。成本侧它的模型调用次数与 token 消耗低于几个对照方法。本地复现时建议把这张表做成实验台账每换一次准则库版本就重跑一遍配置accF1recallFSR备注粗准则 细准则待填待填待填待填主方案仅粗准则待填待填待填待填消融仅细准则待填待填待填待填消融无准则裸判待填待填待填待填下界参照表格里的数字必须来自你自己的轨迹集论文数字只能作为量级参照不能直接填进去当结论。6. 把 judge 调试流接进 Claude Code / Codex / CC Switch判分脚本写完之后日常调 prompt、看日志、改准则库大多在终端里完成这部分可以顺手配好。6.1 Claude Codesettings.json 与 ANTHROPIC_*Claude Code 走ANTHROPIC_*系列变量配置文件放在项目级.claude/settings.json或用户级目录下{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: claude-sonnet-4-5 } }ANTHROPIC_MODEL请以控制台实际提供的模型 ID 为准不要照抄。改完配置后重启终端会话让环境变量重新加载。6.2 Codexconfig.toml 独立配置Codex 用的是config.toml变量体系与 Claude Code 完全不同切忌把ANTHROPIC_*套过来——套过去的结果通常是连接正常但模型名解析失败。model gpt-5-codex model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chatenv_key指向的是环境变量名而不是 Key 本身真正的值仍在 shell 里通过TAOTOKEN_API_KEY注入。6.3 CC Switch三件套配好就能来回切CC Switch 的价值在于同时管理多个供应商配置避免手改配置文件切来切去。填三件套即可供应商名称TaoTokenBase URLhttps://taotoken.net/apiAPI KeyYOUR_API_KEY需要为 Claude Code 与 Codex 分别建一个 profile因为两者的变量键名不同。切换后记得新开终端窗口旧会话仍然读的是启动时的环境变量。如果切换后请求 401先检查是不是旧进程还在用缓存配置。配置完成后可以在 TaoToken 官网 的文档区对照当前支持的模型列表确认 profile 里的模型 ID 没有过期。7. 上线前必须做的三次排障第一次鉴权探针。单独跑一次最小请求确认 Key 与 Base URL 拼装正确。报 401 优先查 Key 是否带了多余空格或引号报 404 优先查 base_url 是否被误加了路径或查询参数。curl -s -o /dev/null -w %{http_code}\n \ https://taotoken.net/api/models \ -H Authorization: Bearer YOUR_API_KEY这条命令在本地执行即可不要把它接进任何自动化链路去探测服务状态。第二次输出格式探针。judge 和准则生成器都要求严格 JSON但模型偶尔会输出带 markdown 代码块包裹的内容。上面的re.search(r\{.*\}, raw, re.S)就是为此准备的兜底。上线前统计一下parse_error与json_error的比例超过 1% 就要继续收紧 system prompt。第三次帧预算探针。固定同一条轨迹分别用 5 帧、10 帧、20 帧跑一遍观察判分结果是否稳定。如果结果在帧数变化时大幅摇摆说明关键帧选择规则没抓住真正的状态切换点应该回头改select_frames里的动作集合而不是靠加大帧数硬压。8. 小结与下一步ADAPT RUBRIC 最值得借鉴的地方不是某个 prompt 模板而是把判分标准从一套通用模板或模型自由发挥改造成了类别边界 指令要点的组合。它没有更换判分模型而是在出题这一步下功夫——把题出对往往比把分打细更影响最终结果。工程落地时记住三件事粗准则离线固化并用版本号管理、细准则严格卡在两条以内、judge 只依赖准则做二值判断。剩下的是成本与稳定性问题交给帧预算和输出校验解决。按下面的顺序把这套流程跑通先用 模型对话 快速验证 judge 的返回格式是否符合预期确认可行后用 Coding Plan 承接持续跑批的调用量接着去 创建 API Key 拿到正式 Key 并写进环境变量最后对照 Claude Code 文档 检查本地配置项是否齐全。整套链路里 TaoToken 负责的始终只有 Key 与 Base URL 这一层准则库、帧选择、指标脚本全部由你自己掌控。