游乐游手机版
首页/AI教程/文章详情

评审分歧时别投票,用执行结果作为代码评估标准

时间:2026-06-17 15:11
当 judge 们吵起来时,别再投票了:用执行结果给 code eval 一个 ground truth 上一篇把数据集扩到了30个case、5个领域、3个judge、3个被测模型。结果比预想更有结构:judge分歧不是均匀的噪声,它集中在某些领域。 最典型的是code。固定被测模型为deepsee

当 judge 们吵起来时,别再投票了:用执行结果给 code eval 一个 ground truth

上一篇把数据集扩到了30个case、5个领域、3个judge、3个被测模型。结果比预想更有结构:judge分歧不是均匀的噪声,它集中在某些领域。

当 judge 们吵起来时,别再投票了:用执行结果给 code eval 一个 ground truth

最典型的是code。固定被测模型为deepseek,只换judge,看同一批HumanEval输出,三个judge给出的code域均分如下:

judgecode 域 pass-rate
deepseek0.80
qwen0.00
glm0.93

逐题看更扎眼:

casedeepseek judgeqwen judgeglm judgespread
he-humaneval-1511.000.001.001.00
he-humaneval-280.400.001.001.00
he-humaneval-1630.800.000.800.80
he-humaneval-1080.800.000.800.80
he-humaneval-620.800.001.001.00
he-humaneval-701.000.001.001.00

这是很难靠“多挂几个judge”解决的分歧。

如果deepseek说0.80,qwen说0.00,glm说0.93,我们当然可以做majority vote。问题是,vote出来的不是事实,只是另一个聚合规则。三个人站在一段代码旁边争“能不能过”,最直接的方法不是开会,是运行。

这就是v0.8的动机。

文章4的panel解决了前半个问题:发现judge之间在吵。v0.8要解决后半个问题:在能客观判定的领域,别让judge继续吵。

二、为什么code域不该继续用LLM裁判

LLM judge评代码时经常混在一起看三件事:

  1. 代码是不是语法正确。
  2. 代码是不是覆盖了题意。
  3. 代码风格、解释、边界情况看起来是不是像一个“好答案”。

第三件事有时有用,但HumanEval这种题真正关心的是前两件事。函数能不能处理docstring里的输入,返回值对不对,边界条件过不过。它不是作文题。

上一篇里qwen judge把deepseek的code输出全部打成0。也许qwen对代码质量更严,也许它过度惩罚了风格和边界描述,也许deepseek和glm太宽。单看judge理由,根本没有办法裁决。

但HumanEval自己带测试:

def check(candidate):
    assert candidate([5, 4]) == 25
    assert candidate([0.1, 0.2, 0.3]) == 0
    assert candidate([-10, -20, -30]) == 0

这类题有一个朴素到不性感的判据:把模型输出当成函数实现,拼上测试,跑一下。全过就是过,assert挂了就是挂。

这不是说单测等于全部真理。HumanEval的测试也可能不完备,隐藏边界也可能漏。但它至少比“另一个LLM觉得像不像对”多了一层可复现的物理约束。代码真的执行了,异常真的抛了,返回值真的错了。这个事实不依赖judge的口味。

三、v0.8做了什么

v0.8加了两个hard-metric scorer:

scorer解决的问题
code_exec把模型输出的Python代码放进子进程,跑HumanEval式单测
numeric_match从输出中抽最后一个数字,按rel_tol / abs_tolexpected比对

numeric_match是math域的补丁。以前用exact_match时,“3.14”、“3.1400”、“答案约为3.14”会被字符串格式牵着走。数值题应该比数值,不该比标点。

code_exec是这篇的主角。它的配置长这样:

scorers:
- type: code_exec
  params:
    timeout: 5
    memory_mb: 256

用例不需要改TestCase模型,只把HumanEval的entry_pointtest放到metadata:

- id: he-humaneval-151
  domain: code
  input: "补全下面的 Python 函数..."
  metadata:
    entry_point: double_the_difference
    test: |
      def check(candidate):
          assert candidate([]) == 0
          assert candidate([5, 4]) == 25

scorer做四步:

  1. 从模型输出里抽第一段fenced code;没有围栏就取整段输出。
  2. 拼成模型代码 + test + check(entry_point)
  3. 放进受限子进程执行。
  4. exit code为0就pass,否则fail,并把timeout / AssertionError / stderr尾部写进detail。

这条路径没有改engine、report、diff。它仍然只是一个普通scorer,产出普通Score。这点很重要,因为Evalith的核心抽象不应该因为一个新评分器变复杂。

四、为什么要有EVALITH_ALLOW_CODE_EXEC=1

执行模型代码不是普通scorer。contains最坏只是误判,code_exec是真的在本机跑不可信代码。

所以v0.8没有让它静默启用。配置里写了code_exec,但没显式设置环境变量时,build_scorer会直接报错:

EVALITH_ALLOW_CODE_EXEC=1 evalith run examples/eval.code-exec.yaml

这个开关有点啰嗦,但宁愿它啰嗦。一个eval工具如果在用户没意识到的情况下执行模型生成的代码,那就是设计错误。

sandbox这层做了几件防护:

  • 每次执行都起独立Python子进程。
  • -I隔离Python环境,减少用户site/env的影响。
  • 在子进程内注入resource limit:CPU、地址空间、文件大小。
  • 在前导代码里禁掉一批危险调用,比如os.systemos.removeos.killsubprocess.runshutil.rmtree
  • 设定wall-clock timeout,死循环会被主进程杀掉。

有一个实现细节值得单独说:没有用preexec_fn

Evalith的engine会在线程池里并发跑case。Python文档明确警告,多线程程序里用preexec_fn有死锁风险。传统写法是在subprocess.Popen(..., preexec_fn=set_limits)里给子进程设RLIMIT,但这条路在这里不合适。

v0.8的做法是把resource.setrlimit注入到子进程代码最前面。它仍然发生在用户代码之前,但不经过preexec_fn。这不是为了炫技,是为了避开一个真实的多线程坑。

当然,这不是Docker,不是强安全沙箱。它是一个面向本地eval的最小隔离层。边界要说清楚:别拿它跑恶意对抗样本,别把它当云端代码执行服务。它解决的是“模型偶尔写死循环、乱分配内存、误调危险函数时不要拖死整轮eval”,不是解决所有安全问题。

五、验收数据集:复用文章4的同一批HumanEval题

为了让v0.8和文章4接上,没有另选题,而是把文章4的6个code case原样映射回HumanEval:

article 4 caseentry point
he-humaneval-151double_the_difference
he-humaneval-28concatenate
he-humaneval-163generate_integers
he-humaneval-108count_nums
he-humaneval-62derivative
he-humaneval-70strange_sort_list

新的文件是:

examples/code.humaneval.yaml
docs/blog/article4/build_code_exec_dataset.py
docs/blog/article4/configs/eval.code-exec-accept.yaml

这组数据的意义不是“又多了一个demo”。它让文章4的judge分歧有了一个后续裁判面板:

层次问的问题
v0.7 judge consensus paneljudge之间是否分歧,分歧落在哪些领域
v0.8 code_exec对code题,模型输出到底能不能通过单测

之前只能写:

现在可以继续写:

这一步还没有把article 4的历史raw outputs全部重跑成执行表,所以这篇不伪装成“最终实验结论”。目前仓库里已经有的是数据集、scorer、验收配置和全量测试。真正的judge-vs-exec对照表,应该作为下一轮实验跑出来,而不是在文章里脑补。

这点要老实。没有跑过的表,不写。

六、TDD结果:这次更像补地基,不像加功能

v0.8的实现拆成8个小任务:

  1. extract_code 剥围栏纯函数。
  2. sandbox.run_program 隔离子进程。
  3. CodeExec scorer。
  4. NumericMatch scorer。
  5. build_scorer 接线和环境变量闸门。
  6. engine端到端测试,证明生产引擎零改动。
  7. 用真实HumanEval重建article 4同题号验收集。
  8. 版本、示例和README。

更让人欣赏的是,engine没动。报告也没动。diff也没动。

这说明scorer抽象承住了新能力。code_exec看上去是一个很不一样的东西,实际上对外仍然是:

score(case, output) -> Score

一个eval工具如果每加一种评分方式都要改engine,后面很快会变成一锅汤。v0.8没有走到那一步。

测试覆盖也基本沿着风险来:

  • fenced code、裸代码、多代码块、空输出。
  • assert失败、死循环timeout、内存冲击波、危险调用。
  • 缺metadata时优雅失败。
  • EVALITH_ALLOW_CODE_EXEC未开启时拒绝构建scorer。
  • engine通过echo provider做一次完整end-to-end。
  • numeric_match覆盖exact、容差内、容差外、无数字、expected非数字。

服务器上那次全量回归跑到134 passed,只剩一个旧版本号smoke test。这个测试后来从0.1.0同步到0.8.0。发布前还应该再用服务器环境跑一遍全量,这是最后的门闩。

七、这篇真正想说的不是“我们支持代码执行了”

如果只把v0.8理解成“Evalith加了code_exec scorer”,那它有点小。

它真正补上的,是这条eval工作流:

先用LLM judge / panel找到可疑分歧
再在有客观判据的领域切换到hard metric
最后只把没有客观判据的部分留给judge

这比“多找几个judge投票”稳得多。

对code,跑测试。
对math,比数字。
对事实题,尽量用可检索答案或结构化gold。
只有开放式解释、审美、语气、安全边界这类确实没有单一答案的问题,再交给LLM judge,而且最好挂panel看分歧。

LLM judge不是不能用。文章2、3、4其实都在用它。但它应该放在合适的位置:处理那些hard metric覆盖不到的语义判断。能不用它的地方,就别用它。

这是从前四篇里越来越确定的一点。

八、给团队的工程判断

如果你的eval set里有code题,不要只用LLM judge。至少为关键case加一层code_exec

如果你的eval set里有数值题,不要只用字符串匹配。至少用numeric_match抹平格式差异。

如果你的eval set里混着code、math、knowledge、safety、open-ended explanation,不要幻想一个judge criteria能公平量所有题。先按领域拆,再决定每个领域该用什么scorer。

一个比较实用的组合是:

领域首选scorer辅助信号
codecode_execjudge panel看可读性/解释,但不做主裁判
mathnumeric_matchllm_judge只看推理过程质量
knowledgecontains / regex / gold answerllm_judge看解释完整性
safetyllm_judge panel人审抽样
concept explanationllm_judge panel + expected_conceptsbootstrap / adaptive sampling

这样做会让eval配置更复杂一点,但复杂度是诚实的。问题本来就不是同一种题,硬压成一个scorer只是把复杂度藏进误判里。

九、局限和下一步

这次v0.8还有几个边界:

  1. code_exec只支持Python/HumanEval式函数补全,不支持stdin/stdout竞赛题。
  2. sandbox是本地最小隔离,不是强安全容器。
  3. HumanEval单测不是形式化证明,测试覆盖不到的bug仍然可能漏。
  4. 文章4的历史模型输出还没有全部通过code_exec生成judge-vs-ground-truth对照表。
  5. Windows上没有resource模块,当前实现的RLIMIT路径主要面向Linux发布/CI环境。

下一步最值得做的不是继续加scorer,而是把article 4的code raw outputs全部接到code_exec上,生成一张表:

casedeepseek judgeqwen judgeglm judgecode_exec
he-humaneval-1511.000.001.00?
he-humaneval-280.400.001.00?

这张表才会真正回答上一篇最想回答的问题:

如果qwen全打0但code_exec大多通过,说明qwen在这批code题上过严。
如果qwen全打0且code_exec也大多失败,说明deepseek/glm在自评或宽松judge上放水。
如果三者都和execution有系统偏差,那就更有意思,说明LLM judge对代码正确性的口味和真实执行之间存在结构性错位。

这会是下一篇实验文最有价值的表。

十、结论

前四篇一路走下来,Evalith做了几层防护:

  • 文章1:不要点对点看回归,要用bootstrap CI处理LLM抖动。
  • 文章2:LLM judge自己也在抖,工具之间的判定语义会分叉。
  • 文章3:统计方法影响有限,judge identity才是核心变量。
  • 文章4:judge分歧有领域结构,code分歧最大,safety更容易共识。

文章5的结论更朴素:

能执行就执行,能算数就算数,能查gold就查gold。LLM judge留给那些真的需要语义判断的地方。

v0.7的panel像烟雾报警器。它告诉你哪里烧起来了。
v0.8的code_exec是灭火器的一种。它不负责所有火情,但在code这个房间里,比继续开会有效。

pip install -U evalith
EVALITH_ALLOW_CODE_EXEC=1 evalith run examples/eval.code-exec.yaml

代码、验收数据集和复现实验都在:

github.com/dominciyue/…

来源:https://juejin.cn/post/7651338917444386825
上一篇智谱ZCode国产版Codex初体验 下一篇DeepSeek V4 Pro免费无限用还能接入Claude-Code
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
RAG四标融合企业知识资产体系四库协同GEO优化实践
AI教程 · 2026-07-01

RAG四标融合企业知识资产体系四库协同GEO优化实践

生成式AI正在彻底改写信息检索的底层逻辑。传统SEO依赖关键词堆砌和外链建设的策略,在大模型的内容采信规则下已经基本失效。取而代之的,是生成式引擎优化(GEO)。它不再关注外链数量,而是重点衡量你的知识是否结构化、证据链是否坚实、信源是否可靠——这些维度才是RAG(检索增强生成)架构真正看重的核心指

一个普通上班人分享WorkBuddy使用心得与真实体验
AI教程 · 2026-07-01

一个普通上班人分享WorkBuddy使用心得与真实体验

前言 最近我开始使用WorkBuddy——这是腾讯推出的一款AI办公工作台。差不多用了一周时间,趁印象还新鲜,把真实的使用感受记录下来,给还在犹豫的朋友做个参考。不吹不黑,只说实际体验。 初印象:不只是聊天机器人 之前用过不少AI工具,大多数就是个对话框,你问它答,答完就结束了。WorkBuddy不

AI幻觉变真功能实战教程:App Inventor 2视频录制拓展一周开发实录
AI教程 · 2026-07-01

AI幻觉变真功能实战教程:App Inventor 2视频录制拓展一周开发实录

先讲一个颇具戏剧性的开端。 这件事的开端颇显荒诞——有用户前来咨询,称AI Pro版的介绍中提到我们有一款“视频录制拓展”。团队全体成员都感到困惑,翻遍产品列表,发现根本不存在该组件。AI那种“一本正经胡说八道”的能力,这次确实让我们陷入尴尬。 按常理,此事到此便可结束——一句“抱歉,暂时没有这个拓

别再混淆OLAP和SQL-on-Hadoop两者查询本质不同
AI教程 · 2026-07-01

别再混淆OLAP和SQL-on-Hadoop两者查询本质不同

OLAP和SQL-on-Hadoop虽都使用SQL查询数据,但本质不同。SQL-on-Hadoop负责海量数据批量计算与ETL,查询速度秒级至分钟级;OLAP通过预聚合实现毫秒级多维分析,适合BI报表。两者在数据平台分工协作,前者是后厨加工,后者是前台快速服务。

GEO优化深度解析:AI偏好FAQ还是长文内容?
AI教程 · 2026-07-01

GEO优化深度解析:AI偏好FAQ还是长文内容?

在GEO优化中,AI对内容形式无统一偏好:FAQ在简单查询中引用率41%,长文在复杂查询中达58%。内容应基于用户意图选择形式,FAQ适配简单事实类问题,长文建立主题权威,两者互补而非替代。