Skip to main content
Yanked

This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
Consider using release 1.2.5 instead.
Reason given by maintainers: Stale build without router support; superseded by 1.1.0

统一 rubric 判分器

凡是靠 tests/rubric.json 让大模型逐条打分的 instance,判分代码都用这一份 tests/judge.py,在这个目录改,改完拷到各个 instance 里去。

这个目录本身就摆成一个 harbor instance 的样子:把 tests/ 下那三个文件拷进目标 instance 的 tests/,再把 task.toml[verifier.env] 那段照抄过去,就算装好了。

这三个文件各干什么:

文件 干什么
test.sh harbor 调的入口。收集产物、归档、然后调 judge.py
judge.py 真正打分的。只有这个文件需要维护
reward_exit_message.py 判分器自己崩了的时候,从日志里反推一个错误码

目录里有什么

judger/
├── task.toml                  instance 示例,只有 [verifier.env] 那段要照抄
├── README.md                  本文件
├── CHANGELOG.md               每一版改了什么、为什么改(带实测数据)
├── REVIEW.md                  2026-08-16 对 1.2.0 做的一次代码评审,还有 1 个 P0 没修,见文末
├── tests/                     ← 要拷进 instance 的就是这里的东西
│   ├── judge.py               判分器,唯一需要维护的文件
│   ├── reward_exit_message.py 错误码兜底(照抄 FIN-0071 的原件,一个字没改)
│   ├── test.sh                harbor 入口(FIN-0071 原件 + 2 处改动,见 CHANGELOG 1.0.0)
│   ├── pptx_evidence.py       ppt 取证库,只装进 GDP ppt 那 126 个
│   ├── rubric.json            示例文件,各 instance 用自己的
│   ├── judge_instruction.md   示例文件,各 instance 用自己的
│   └── task_prompt.md         示例文件,各 instance 用自己的
└── selftests/                 自测,跑法见文末

怎么装

单个 instance:

cp judger/tests/{judge.py,reward_exit_message.py,test.sh} <instance>/tests/
chmod 755 <instance>/tests/{judge.py,test.sh}
# 再照 judger/task.toml 的 [verifier.env] 把目标 instance 的对齐,然后重新打包传 OSS

几件容易踩的事:

  • 这三个文件是打进每个 instance 的 content.tgz。改完不重新打包上传 OSS, 线上跑的还是旧版本——本地改了等于没改。
  • rubric.json / judge_instruction.md / task_prompt.md / expected_output/ 不要动judger/tests/ 下那几个只是示例,别拷过去把 instance 自己的覆盖了。
  • 判分说明一个字都不用改。(1.2.0 曾往里加过严格交付的说法,1.3.0 已经逐字节退回原文。 装机脚本遇到被 1.2.0 改过的实例,会从包内 .pre-unify.<md5>.bak 还原。)
  • 原来的判分脚本备份成 <名字>.pre-unify.<md5>.bak 留在包里。OSS 那个桶只能写, 下载会 403,所以回滚点只能放在包内。
  • 装完 test.sh 调的是同目录的 judge.py。原来 test.sh 里写死 python3 tests/agent_judge.py 的实例会一起被换掉——test.sh 也是要替换的文件之一,不是保留文件。

改一版要重新装哪些包

判断标准很简单:judger/tests/judge.py 变了没有。

改了什么 要重新装
judge.pyVERSION 会跟着变) 4312 个(GDP 1229 + WLE 1157 + DR 1800 + ppt 126)+ long_horizon 204 个
只改 pptx_evidence.py / instruction_ppt.md / ppt 的 env 只有 ppt 那 126 个
只改 [verifier.env] 里已声明的变量的值 不用重装,rollout 侧直接覆盖就行

judge.py 一变,VERSION 就和包里的对不上(校验脚本的期望版本号是直接读 judge.py 里的 VERSION 的),所以必须全部重装。

long_horizon 那 204 个(long_horizon_0707_fix不走批量装机那条链:每个包自带一份 judge.py,没有单一来源,装机和校验脚本都不认它们。同源的改动两边都要打, 否则线上一半新一半旧。

打分怎么算

记第 i 条 rubric 的权重 w_i、判词命中 hit_i(没判到的按 hit=false), gate_i = 它 depends_on 的行是否全部命中(没写 depends_on 时恒为真),则

分母 W = Σ w_i                                  w_i > 0 的行(含 hurdle 行)
分子 E = Σ w_i · lvl_i · [gate_i]               w_i > 0 且非 hurdle
       + Σ w_i · [hit_i]                        w_i < 0 且非 hurdle(w_i 是负数,这项在扣分)
fatal  = 存在 hurdle 行且 hit_i = true

lvl_i  = 判分模型给的档位(分级项,`"type": "gradient"`,取值只能是 levels 的键)
       = 1 if hit_i else 0                      二值项(也是分级项漏回 level 时的兜底)

score_normalized = 0                            若 fatal
                 = clamp(E / W, 0, 1)           否则

reward = score_normalized                       JUDGE_REWARD_MODE=continuous(默认)
       = 1.0 if 判分成功 and 过线 else 0.0       JUDGE_REWARD_MODE=binary(迁移期才用)

task_score 就是 reward,原样透给 harbor。分子分母都在 judge.py:_compute(), 对应自测在 selftests/test_score.py

逐条说明:

  • w > 0 加分项:命中且过 gate 才加 w;不管判没判到都记进分母。分级项加 w × level
  • w < 0 扣分项:命中就从分子里减 |w|不进分母。所以扣分只压已得分、不改天花板, 扣成负数会被 clamp 抬回 0。扣分项不看 gate,依赖没满足也照扣。
  • hurdle: true 致命门槛项:无论权重多少,本行永不产生分子,命中一条整题直接 0 分。 但权重 > 0 的门槛项仍然留在分母里(代码没排除),等于白占天花板 —— 门槛项应当写 weight: 0,线上 3124 条门槛项都是这个形态。
  • depends_on 是 DAG gate:依赖没全命中 → 该行不计分,但分母保留,否则模型可以靠 不做前置步骤来抬分。依赖 id 悬空(指向不存在的行)按未满足处理(fail-closed)。
  • 一条正权重都没有、且没有 hurdle 行时,权重为 0 的行按等权 1.0 兜底(对齐 GDPval 原实现的 if not primary: primary = criteria);有 hurdle 就不兜底,否则命中门槛反而变成加分。 兜底之后依然没有正权重 → judge:scorer_error,整题不出分。

阈值(JUDGE_PASS_THRESHOLD)默认不参与算分,只写进 extra_fields.passed 供统计过线率。 JUDGE_REWARD_MODE=binary 是迁移期才用的开关,见下文。

门槛项的 hit 该怎么读(1.7.0)

门槛项的描述几乎都是负向的("最终交付缺失或为空"),所以 hit=true 的意思是 "确实发现了这个问题",不是"这条要求达到了"。判分模型很容易读反。

原来指望判分说明来讲清楚,但说明里只写了"weight > 0 加分、< 0 扣分",而线上 3124 条门槛项 全都是 weight == 0hurdle == true,两条规则一条都不覆盖它,模型只能按正向猜—— 交付明明合规也判 hit=true,整题 0 分。实测这种假 0 占了命中门槛项的 job 的 28%。

1.7.0 的做法:judge.py 发给模型的那份 block rubric.json 里,除了原有字段,再补两个 派生字段(不是标注字段,标注文件里没有):

  • polaritynegative / positive,由 weight 符号 + hurdle 推出来。
  • hit_means:一句话写清这条的 hit=true 到底是什么意思。negative 那档明确写 "要求已满足、没发现这个违规 → 必须 hit=false"。

算分代码一个字没改,纯粹是给模型的输入里多说一句。改前后的实测对比见 CHANGELOG 1.7.0。

分级项 "type": "gradient"(1.9.0)

标注侧新增的第二种 rubric 形态:不是「做到/没做到」,而是「做到几成」。

{"id": "R06", "description": "DCF 用的 WACC 应落在 [10%,12%],越接近得分越高",
 "tag": "内容质量-数值与计算准确性", "criterion_type": "Objective",
 "criterion_necessity": "Explicit", "type": "gradient", "weight": 7.0,
 "levels": {"1": "落在 [10%,12%] 内", "0.75": "偏离 ≤±1%", "0.5": "偏离 ±1%~±3%",
            "0.25": "偏离 ±3%~±5%", "0": "未给出或偏离 >±5%"}}
  • levels 的键就是该档的得分比例,必须是 0~1 的数、至少两档。得分 = weight × level, 所以分级项和二值项可以在同一份 rubric 里混用,分母口径完全不变(还是 Σ w)。
  • 档位表原样发给判分模型(block rubric.json 里带 levels + level_choices + 分级版 hit_means),并且 level 字段是结构化输出 schema 里 required 的—— 这是关键的接线点:4186 个已铺包各自带着一份只讲二值的 judge_instruction.md, 靠指令文件讲不通,靠 schema 才强制得住。
  • 模型回了表外的数(0.8、0.9)会吸附到最近的合法档位,并列时取低的一档(宁严不宽); 漏回 level 则退回按 hit 算(满档/零分)并照常出分——分级项判不了也不能让整题没分。
  • hurdle 行和 w < 0不吃 levels:门槛是「有没有踩」、扣分是「有没有犯」, 没有「做到几成」这回事。写了也按二值判。
  • 结果里分级项多一个 results[].level(和 criteria[].level_raw,模型回的原值), 二值项的输出形状一个字不变
  • 顺带把 clawgym 那批的 scores 档位表({"0":…,"0.25":…,…},无 weight)也接上了: 它没有权重 → 走「全零权重按等权 1.0 兜底」 → 分数恰好等于原 clawgym_grader 的 「各条分级得分算术平均」(等价性用例 t_clawgym_scores_alias_equals_original_mean)。 1.8.x 之前这批被按二值判,0.75 档当 0,分数系统性偏低。

环境变量

"线上可调" 那一列很关键:harbor 只会注入 [verifier.env] 里声明过的变量, 没声明的等于线上不存在,改代码默认值也只对新装的包生效。 标 ✗ 的那几个只在本地调试有用。

本仓 task.toml 只声明了凭据和常动的那几个旋钮,标「模板未声明」的默认值等价、 但新装的包线上调不了,要调先把那行加回 [verifier.env]。已铺的 4186 个包里 这些变量当初都声明着,对它们仍然线上可调。

变量 默认 线上可调 说明
JUDGE_API_KEY / JUDGE_BASE_URL 判分模型的凭据,必须显式给。少任一个就直接以 judge:no_credential 退出,不会拿不到凭据还接着跑
OPENAI_API_KEY / OPENAI_BASE_URL 老配置兜底,JUDGE_* 优先。解析结果会回写进两套变量名,codex 的 config.toml 用哪个 env_key 都取得到
JUDGE_MODEL gpt-5.5 判分模型名
JUDGE_BATCH 4 一个会话判几条。块数 = 会话数 = 请求量,代价是一个块超时就丢这么多条。1.5.1 从 8 减到 4、1.8.1 回到 8、1.8.2 又回到 4(8 条一块把长 rubric 实例判崩,覆盖率 0.980 → 0.903),三条 CHANGELOG 都要看
JUDGE_CONCURRENCY 2 同时跑几个块。这是全 fleet 峰值 RPM 的直接倍数,1.8.0 从 4 降到 2(ppt 那 126 个还是 8,没跟着改)
JUDGE_PER_TIMEOUT 150 单次调用超时(秒)。单次耗时 ≈ 固定开销(起会话 + 读完所有产物,实测 ~100s)+ 条数 × ~3s。ppt 那族一条 rubric 的边际成本是几十秒,所以单独装 240
JUDGE_MAX_TRIES 6 一个块最多试几次。别调小:ppt 上试过 1,覆盖率反而从 0.825 掉到 0.722,见 CHANGELOG 1.6.0-ppt.2
JUDGE_RESPLIT 1(= 开) 块失败后拆成单条重判。1.8.0 关掉(怕放大限流)、1.8.3 重新打开:块失败的实因是单次调用越过 PER_TIMEOUT,不是限流。必须和 DEADLINE=1800 一起开,只开这个是把块预算漏换成撞总墙漏
JUDGE_DEADLINE 1800 判分总时长上限(秒,从 judge.py 启动算)。超了就停,已判到的照常算分。1.8.0 从 780 提到 1200(配合 K=2 和 180s 抖动),1.8.3 提到 1800(给 resplit 留时间)
JUDGE_START_JITTER 180 模板未声明 第一波每个块各自随机等 0~N 秒再发请求,摊平瞬时速率。1.8.0 从 30 提到 180
JUDGE_RETRY_BACKOFF_MAX 20 模板未声明 被限流时的最长等待秒数,uniform(1, min(20, 2·3^(n-1))) = 2→6→18→20
JUDGE_REWARD_MODE continuous continuous = reward 就是连续分(默认);binary = 按阈值压成 0/1。认不出的值按 continuous 处理并告警
JUDGE_PASS_THRESHOLD 0.75 continuous 下只写统计字段;binary 下它决定分数
JUDGE_PASS_COMPARE gte 模板未声明 gt / gte。开 binary 迁移时要连比较符一起对齐,见下文
JUDGE_LENIENT_DELIVERY 空(= 严格) 模板未声明 设真值 → 把写在 /app 根和 /output 的产物也搬进来判分。默认严格:只认 /app/output
JUDGE_CHAT_FALLBACK 1(= 开) 模板未声明 output/ 空但对话里有答案 → 照常判分。0 恢复 1.2.0 的硬 0
JUDGE_EVIDENCE 180 模板未声明 交付物是 .pptx 时,先离线抽一份结构 + 页图给判分模型的预算秒数(0 = 关)。抽一次所有块共用,见下文
JUDGE_METRIC_ID rubric_llm_judge 模板未声明 写进 result.json,下游按它归类
JUDGE_AUX_FILES ppt 那 126 个声明了 判分说明要 import 的辅助模块(逗号或空格分隔)。ppt 的 pptx_evidence.py 就靠它。不声明就不拷,模型 import 必失败
JUDGE_BACKEND codex codex / claude
JUDGE_INSTRUCTION_FILE 判分说明的路径。不给就按 judge_instruction.mdjudge_instructions.mdrubric_instruction.mdjudge_prompt.md 找,都没有就用内置的默认说明并告警
JUDGE_SYSTEMIC_FRACTION 0.4 未判比例超过它才算系统性失败
JUDGE_SYSTEMIC_MIN 2 且未判条数至少这么多
JUDGE_SKIP 设真值 → 只归档产物不判分,reward.txtSKIPPED

几个关键行为

产物写错地方 = 没交付;但"没写文件" ≠ "什么都没做"

题面对交付路径是硬要求,三批 yuanrang 数据一字不差(/app/output/result.md把唯一的最终产物写入 /app/output/),gdpval0701 是同一句的英文版。所以默认口径是 只认 /app/output 下的非空文件。写到 /app 根或 /output不算分, 但会归档到 /logs/artifacts/output/_stray_not_scored/,不然"模型到底写哪了"查不出来。

但这批数据里有一批题题面本身就要求答在对话里,和 harbor 的样板要求直接冲突。数过:

分类 实例数 rubric 里一条文件性要求都没有 文件性权重占比中位数
纯对话题(题面明确不让建文件) 61(WLE 48 + GDP 13) 31 个(51%) 0.0%
混合题(要交文件 + "洞察请在文本直接回复") 49(GDP 45 + WLE 4) 11 个(22%) 29.3%

那 31 个纯对话题,一刀切给 0 分丢掉的是全部能判的权重:rubric 一条文件性要求都没提, 每条都能从对话回复里判出来,结果一条没判就给 0。所以 1.3.0 改成让 rubric 条目自己决定 看哪儿的证据

  • 判分说明保持原样。原文本来就写着"纯文本题(output/ 为空)以 model_response_text.txt 为判据",1.2.0 把它改坏了,1.3.0 逐字节退回去。
  • 不需要造假文件judge.py 无条件把 agent 最后那句回复写进判分工作区的 model_response_text.txt,判分模型本来就看得到。反过来,把回复写成 output/ 下一个文件 会让"output/ 为空"这个前提不成立,和刚退回去的原文打架。
  • 所以 JUDGE_CHAT_FALLBACK=1(默认开)放宽的只是这道判断本身:没交文件、但对话里有答案 → 照常判分,并记一笔。
  • 文件性条目该扣的分不用另加机制。判分说明第 1 条就是"有 output/ 交付文件时优先以其为判据", 真·文件题只答对话,点名要文件的那些条目自然判不中。于是罚分是按权重成比例的 (混合题中位数 29.3%),比一刀切 0 分准得多,也不用给每个实例配开关。
  • details.delivery.from_chat / extra_fields.delivery_from_chat 会记下来, 下游能把"真交付"和"只答对话"分开统计。

两个渠道都空(文件没写、对话里也没答案)才是真的什么都没交:

  • 直接给 0,一次判分 API 都不发。没有产物就没有证据可命中,逐条判一遍结果一样, 白花一轮钱。extra_fields.judge_called = false 标记这件事。
  • status 仍是 success,不给 exit_code。没交付是任务没做完,不是判分坏了。 给了错误码,下游会按"基础设施故障"把这条过滤掉,等于没交付还免罚。这个 0 必须原样进训练集。
  • 原因写进 exit_reasonextra_fields.delivery_missing = truedetails.delivery 记下 files / missing / from_chat / stray

想回到老口径:JUDGE_CHAT_FALLBACK=0 恢复 1.2.0 的"没写文件就 0 分"; JUDGE_LENIENT_DELIVERY=1 恢复原来的宽松路径(并且会连带打开纯文本题那条)。 已部署的实例有 2957 个,所以这两处都做成可配置而不是写死。

少判了几条也照常出分,但要留下痕迹

口径是:没判到的 rubric 按未命中算、照常出分,只有系统性失败才标 exit_code。 好处是判分端抖一下不会丢掉整条 rollout,代价是局部降级原来一点痕迹都没有——实测 group-0a04ac64(GDP 全量)3582 个真判过的 job 里,有 1862 个(52%)少判但没到门槛, 平均丢 20.3% 的 rubric(reward 均值 0.400,满覆盖的是 0.448),分被静默压低, 下游按 exit_code 也筛不出来。所以 1.4.0 起 extra_fields 里恒定写这几个字段:

字段 含义
judge_coverage 判到的比例。想只用满覆盖的样本就按 == 1.0
judge_unjudged 漏判几条
judge_degraded 有没有降级
judge_error_kind 漏判的真因(限流是 rate_limit、撞总时长墙是 deadline
judge_seconds 判分花了多少秒(1.6.0 加)
judge_evidence_pages 离线取证渲出几页(0 = 镜像里没有渲图链路,1.6.0 加)

这几个字段在所有出分路径上都写,下游不用处理缺字段。局部降级也写 exit_reason, 但仍然不给 exit_code——分是真的,只是覆盖率不满;给了错误码下游会当故障整条丢掉。

超时和限流

三层时间上限:单次调用 PER_TIMEOUT ⊂ 单块 2 × PER_TIMEOUT ⊂ 全局 DEADLINE。 中间那层是推出来的,不给单独的参数——并发和重试的参数堆多了没人看得懂。

能这么推,是因为两种失败的代价本来就不一样:超时失败一次就烧掉一个 PER_TIMEOUT (所以块预算天然只够试 2 次),限流是秒级失败、不吃预算(所以 MAX_TRIES=6 才用得上)。

  • 只有限流才退避,等待时间是 uniform(1, min(JUDGE_RETRY_BACKOFF_MAX, 2·3^(n-1))) = 2→6→18→20 秒。超时类失败不走这个,按 1s 定值重试。
  • 限流关键词要包含 dashscope 的原文 Request rate increased too quickly它不带 429 字样)。
  • 判分端限的是增速,尖峰来自"几千个 job 同时进判分、每个又一瞬打出好几个请求"。 所以真正对症的是 JUDGE_START_JITTER(第一波各自随机延迟再发),而不是等更久—— 窄区间的抖动会让全 fleet 近乎同步重试,自己造出第二个尖峰。
  • 配额分两种:quota exceeded(配额窗口打满)退避重试;insufficient_quota(账号没额度) 立刻放弃,不白烧重试。
  • exit_code 的取值集合没有变(不给下游造新码),限流归 judge:api_error, 细分看 judge_error_kind
  • DEADLINE 时:墙前判到的照常计分,剩下的按未命中算,judge_error_kind=deadline, 和端点故障区分开。没这道墙的时候,实测有 job 烧掉 4320s(= 9 × 480s)还在重试。
  • 单次调用的成本主要是固定开销(起会话 + 把长文档和所有产物读一遍,实测 ~100s), 每条 rubric 的边际成本只有 ~3s。所以块要尽量大(调小 BATCH 只会多付几倍固定开销), 拆出来的单条也不比整块便宜,照样给满 PER_TIMEOUT

峰值 RPM 是怎么算出来的(1.8.0 改默认值的依据)

限流是全 fleet 一起打同一个 workspace 造成的,单看一个 job 永远看不出问题。 把 pod 里的 logs/litellm-proxy.log 一行行数出来,两个 group 的对比:

group-55acd93e GDPval(炸) group-2d2fe36f AQ(正常)
判分方式 本判分器,codex agent 判分 直接调 API,/v1/responses 用了 0 次
单 job 判分请求数(中位) 正常 98,失败 564~638 34
job 时长中位 736s 2653s
一个 step 内完成时间跨度(p10~p90) 13 分钟 72 分钟
峰值同时判分的 job 576(step 0 实测 1350) 77
估算峰值 RPM 正常 ~19.6k,失败态 ~52k ~460

三条结论直接落到默认值上:

  1. CONCURRENCY 就是峰值倍数。 job 数和请求数都不由判分器决定,K 是唯一能直接除的因子,4→2 峰值减半。
  2. RESPLIT 是失败态的放大器。 正常 job 起 10 个 codex 会话,失败 job 起 68~78 个(最高 137)—— 31 条拆 31 个会话、每条又最多 6 次。而块失败本身多半就是限流造成的,重判只会更堵。
  3. 抖动窗口要盖住整个爆发。 一个 step 的几百个 job 在 13 分钟内集体进判分,30s 的窗口 摊不平,等于没抖;放到 180s 才有意义。

限流在 HTTP 层看不见:失败 job 的 proxy log 里 737 个请求全是 200, 限流是在 SSE 流里返回的(stream disconnected before completion,codex 侧 168 次 Reconnecting)。 所以网关 metrics 上一个错误都没有,只能下 artifact 查。

ppt 交付物先离线抽一次证据

块是独立进程,几 MB 的 .pptx 每个块都从零解析一遍,块块撞满超时(ppt split 的 judge:timeout 一度 60.3%)。所以 JUDGE_EVIDENCE 打开时,judge.py 先对每个交付的 .pptx 确定性地抽一份 evidence/<文件名>/{digest.json, pages/slide-NNN.json, slides/slide-NNN.png},再硬链进每个块——抽一次,所有块共用。纯 python-pptx + lxml + LibreOffice,没有 LLM 调用。

预算剩不到 45s 就只抽结构不渲图;缺 LibreOffice 或 PyMuPDF 只少抽一层、不报错, 日志里写清抽了几份、渲了几页。

取证绝不整份放弃:被判的 deck 是模型生成的,经常有 python-pptx 解析不了的结构, 所以做了字段级 → 页级 → 整份级三层隔离,连 Presentation() 都打不开时照样渲图 (渲图不经过 python-pptx)。失败原因写进 digest.jsonstructure_ok / extract_errors / structure_note,判分说明里也明确写了抽不到 ≠ 原件里没有, 让模型自己去解 zip,别据此判未命中。

codex 自定义端点必须走 config.toml

codex(Rust) 不认 OPENAI_BASE_URL / JUDGE_BASE_URL 这两个环境变量。所以只要 JUDGE_BASE_URL 不是 api.openai.com,判分器就往 $CODEX_HOME/config.toml 写一段 [model_providers.judge_endpoint]env_key = "JUDGE_API_KEY"wire_api = "responses"), 而不是走 codex login --with-api-key。routify 的 compatible-mode 端点实测 /chat/completions/responses 都返 200,用 responses 没问题。

binary 模式是迁移期才用的

JUDGE_REWARD_MODE=binary 只在"要和历史 reward 分布逐批对齐"时才开,开了会在 stderr 大声告警。 代价是同一批 rollout 之间的梯度全丢:GDPval1107 那 8 条 rollout 的原始分是 53/53、46/53、38/53(×3)、37/53、30/53(×2)(= 1.0 / 0.868 / 0.717 / 0.698 / 0.566), 在 binary 0.75 gte 下只有 2 条给 1,另外 6 条全被压成同一个 0。

要开的话比较符也得一起对齐:原来各批口径不一致(DR/GDP >=0.75、WLE >0.70、 GDP other_file 和 gdpval_v3 multi_files >=1.0)。恰好等于阈值的样本在 gtgte 两种写法下 reward 是相反的。

自测

cd Cowork-RL-Data-Pipeline/judger
for t in test_parse test_score test_degrade test_harbor test_pptx_evidence; do
  python3 selftests/$t.py
done

当前 111 例全过(1.8.0):

文件 例数 测什么
test_parse.py 15 模型输出的判词解析(五级还原:整体 JSON → 剥代码块 → 配平扫描 → 逐条抢救 → 兜底)
test_score.py 44 算分规则、reward 语义、系统性失败门槛、限流退避、极性字段、gradient 分级项(含与 clawgym 原口径的等价性)
test_degrade.py 46 判分坏成各种样子的时候还能不能出分(用假 codex 跑真 main()),外加交付判断、覆盖率字段、gradient 端到端
test_harbor.py 13 真的 bash tests/test.sh 跑一遍,只把 codex 换成假的,验三个文件之间调用对不对
test_pptx_evidence.py 5 取证的三层容错:单个字段坏 / 一页坏 / 整份打不开,都不能丢掉整份

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cowork_judge-1.10.0.tar.gz (66.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cowork_judge-1.10.0-py3-none-any.whl (57.0 kB view details)

Uploaded Python 3

File details

Details for the file cowork_judge-1.10.0.tar.gz.

File metadata

  • Download URL: cowork_judge-1.10.0.tar.gz
  • Upload date:
  • Size: 66.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.19

File hashes

Hashes for cowork_judge-1.10.0.tar.gz
Algorithm Hash digest
SHA256 6019134fcf451f6c8355cfb42e748090447696bc7297227bc5ab3b96bef7db88
MD5 369054beb5d8527a00fe2ca090dcc9b3
BLAKE2b-256 ef120b9ffeffd8ee916a5527fc1ee360121ea2d8e862a73bebfb0ee5818429d0

See more details on using hashes here.

File details

Details for the file cowork_judge-1.10.0-py3-none-any.whl.

File metadata

  • Download URL: cowork_judge-1.10.0-py3-none-any.whl
  • Upload date:
  • Size: 57.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.19

File hashes

Hashes for cowork_judge-1.10.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6060cf90ea83bec8efb9bb1f02f117b440af8f1cc2e66941a89da9df7b15a646
MD5 a4bcb181f94f309b6c5b7c761144000e
BLAKE2b-256 d1f47fd2088fd0b1f680abef9de10810ad5d5e7c244b9b48da7dc36f0201c7ef

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.10.0 This release

2 files

1.2.5

2 files

1.2.4

2 files

1.2.3

2 files

1.2.2

2 files

1.2.1

2 files

1.2.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page