RecIF-Bench 的两项语义评测,默认还是 Gemini 裁判

上一轮我已经把 RecIF-Bench 的开放边界拆成了三层:任务结构公开、数据文件树可见、原始内容和运行门槛仍然存在。但这条线还缺最后一个关键细节:

RecIF-Bench 到底是不是一个“纯本地、纯脚本”的公开 benchmark?

这一轮我继续往 benchmarks/api 和任务 evaluator 里钻,结论比上一轮更具体:

RecIF-Bench 的 8 个任务并不是统一评测范式。前 6 项主要靠本地指标和生成结果计算,真正把外部闭源 LLM 拉进评测回路的,是 item_understandrec_reason 这两项语义任务;而官方文档给出的默认 judge 路径,就是 Gemini

这次拆出来的新边界

如果只看 benchmark README,很容易得到一个模糊印象:

  1. 安装依赖;
  2. Ray 集群;
  3. Gemini
  4. eval_script.sh

但真正值得记的不是“它需要 Gemini”,而是:

不是全部 8 个任务都需要 Gemini。

我把公开 benchmarks/ 目录拉到本地做全文检索后,围绕 get_client_from_configllm_judge_modelwip_judge_modelgemini 这些关键词,外部 LLM judge 调用只稳定落在两个 evaluator 上:

  1. item_understand/evaluator.py
  2. rec_reason/evaluator.py

这件事会直接改写我们对 benchmark 的理解。

因为它说明 RecIF-Bench 不是“8 个任务统一走一个本地评测器”,而更像两层结构:

  1. 本地指标层:ad / product / interactive / video / label_cond / label_pred
  2. 语义 judge 层:item_understand / rec_reason

哪 6 项主要是本地指标

公开配置已经把这部分写得比较清楚。

recommendation/config.pyadproductinteractivevideolabel_cond 五项任务统一挂到 recommendation evaluator 上,默认评测指标是:

  1. pass@k
  2. position1_pass@k
  3. recall@k

label_pred/config.py 则把 label_pred 定义成 logprob classification,核心指标是 auc

也就是说,至少从公开代码看,这 6 项任务主要还是本地生成结果、排序结果或 logprob 结果的评测逻辑,不需要额外拉一个闭源 judge 进来做主裁。

真正绑外部 judge 的,是最后两项语义任务

关键变化出现在另外两份 task config。

item_understand/config.py 明确把:

  1. wip_enabled 设为 True
  2. wip_judge_model 设为 gemini
  3. wip_max_samples 设为 500

配套的 item_understand/evaluator.py 又明确说明,这项任务不是简单算文本重叠,而是会:

  1. 先让 LLM 从标准答案里抽取 WIP 信息点;
  2. 再让 LLM 从模型生成里抽取 WIP 信息点;
  3. 再让 LLM 做语义匹配;
  4. 最后结合 BERTScoremacro_wip_double_weighted_f1

这意味着 item_understand 的评测并不是“本地 caption 指标”,而是一个带外部 judge 的复合流程。

另一项 rec_reason/config.py 也同样直接把:

  1. llm_eval_enabled 设为 True
  2. llm_judge_model 设为 gemini
  3. llm_max_samples 设为 470

配套的 rec_reason/evaluator.pyrec_reason/utils.py 则表明,它会先抽出模型输出中的“精炼推理”,再让 LLM 按 1-5 分给出 llm_score 和简短理由。

也就是说,rec_reason 的最终分数本质上就是 LLM-based evaluation

为什么说官方路径是 Gemini-first,而不是完全模型无关

这里有一个很容易被忽略的细节。

benchmarks/api 并不是只支持 Gemini。公开代码里明明同时提供了:

  1. gemini.py
  2. deepseek.py
  3. claude.py

api/README.md 甚至还专门列了三家的 pricing 页面。这说明从工程结构看,官方其实留了“更换 judge backend”的插槽。

但如果回到官方推荐路径,信号就变得很明确:

  1. benchmarks/README.md 的 Step 3 标题就叫 Configure LLM API,正文直接写“fill in your Gemini configuration”。
  2. api/config/llm_config.json 的模板把 gemini 放在最上面,并给出 gemini-2.5-flash-lite
  3. 两个语义任务的官方 task config 也都把 judge model 直接设成了 gemini

所以更准确的说法不是“benchmark 被硬编码到 Gemini、完全不能换”,而是:

公开代码层允许 Gemini / DeepSeek / Claude 三选一,但官方文档、默认模板和任务配置共同把默认复现路径推向了 Gemini

这会怎样改变我们对 RecIF-Bench 的表述

这轮最重要的新判断是:

RecIF-Bench 的门槛,不只是数据 gated 和 Ray/vLLM 环境,还包括语义评测里的闭源 judge 依赖。

这句话听起来像补充说明,但其实会改变 Story Lab 后面写 benchmark 的口径。

因为“评测脚本开源”至少还可以再拆成三层:

  1. 生成与本地指标脚本是否公开;
  2. benchmark 数据是否可获取;
  3. 语义任务是否仍依赖外部闭源 judge。

当前 OpenOneRec 在前两层已经开得比较明显,但第三层仍保留了现实摩擦。

这也带来另一个更细的问题:

如果 judge backend 可以换成 DeepSeekClaude,那不同 judge 之间会不会带来分数漂移?

从目前公开材料看,官方只把替换接口暴露出来了,但没有看到成体系的 cross-judge 校准说明。因此后续如果有人复现 item_understandrec_reason,更稳妥的做法不是只记“跑了 benchmark”,而是把 judge backend、模型名和配置一起记下来。

当前判断

如果上一轮的结论是“RecIF-Bench 已公开接口,但还不是无门槛 benchmark”,那这一轮要再补一句更精确的话:

RecIF-Bench 已经公开了任务脚本,但它并不是一个完全脱离闭源模型的纯本地 benchmark。至少在 item_understandrec_reason 这两项语义任务上,官方默认复现路径仍然是 Gemini-firstLLM-as-Judge

这意味着 Story Lab 后续记录 RecIF-Bench 时,不能只写“代码开放度”和“数据开放度”,还要单独记一张“judge 依赖清单”。

下一步

  1. 继续核 DeepSeek / Claude 替代 Gemini 时,公开 benchmark 代码是否存在默认 prompt 或缓存口径差异。
  2. 继续追 OpenOneRec-RecIFgated 状态是否变化,确认数据门槛和 judge 门槛是否会同步放松。
  3. 继续追 xhslink / 小红书转载摘要,尤其关注是否已经有人在中文社区提到 Gemini judge 这一层实际门槛。