← 返回信息流
技术博客Hugging Face Blog·1 小时前

olmo-eval:面向模型开发闭环的评估工作台

原标题:olmo-eval: An evaluation workbench for the model development loop

速览

olmo-eval是一个专为模型开发闭环设计的评估工作台。它旨在简化模型迭代过程中的评估环节,提升开发效率。该工具支持快速集成与自动化测试,帮助研究人员更精准地监控模型性能变化。

AI 深度解读

olmo-eval:面向模型开发闭环的评估工作台

背景

在构建大型语言模型(LLM)的过程中,评估并非一次性任务,而是一个反复迭代的过程。每当对模型的数据、架构或超参数进行调整,或者在规模上进行扩展时,开发者都需要重新运行相同的评估循环:添加或重新配置基准测试(benchmarks),在每个新的模型检查点(checkpoint)上运行这些测试,记录结果,并验证在小规模实验中有效的改进在全量训练中是否依然有效。

然而,现有的大多数评估工具并非为此设计。它们通常要么用于在已完成模型上运行既定的基准测试,要么在沙盒环境中让模型通过多步骤、使用工具的问题。这些工具无法跟上模型不断变化的步伐,也无法反映模型在特定真实世界条件下的行为表现。

此前,为了解决这一评估挑战,我们发布了 OLMES(Open Language Model Evaluation Standard,开放语言模型评估标准)。OLMES 于 2024 年推出,旨在使不同版本间的 LLM 基准分数更具可比性。过去,同一模型在不同研究中往往以不同方式评分——提示词格式和任务定义等方面常因论文而异,导致关于“哪个模型表现最好”的声明往往不可复现。OLMES 通过开放、文档化的标准固定了基准测试的选择,并成为我们从 Olmo 到 Tulu 系列开源模型评估的基础。

但是,模型的最终得分仅是评估过程的一部分。鉴于此,我们发布了 olmo-eval,这是一个新的工作台,它在 OLMES 的基础上构建,并将评估扩展至 LLM 开发的其余环节。与 OLMES 相比,olmo-eval 减少了实现新评估的工作量,在定义评估运行位置和方式上提供了更大的灵活性,并使得将各个组件组合成更大工作流变得更加容易。它原生支持代理(Agentic)和多轮评估,并提供了更强的分析工具,帮助开发者判断某项干预措施是否真正提升了基线水平,还是仅仅产生了噪音。

核心内容

与现有工具的区别:以 Harbor 为例

olmo-eval 在某些方面与 Harbor 重叠。Harbor 是一个用于在容器化、沙盒环境中评估 AI 代理的开放框架。但两者的侧重点不同:Harbor 主要面向运行和发布代理基准测试;而 olmo-eval 则是为模型开发的日常工作而构建——包括添加和配置基准测试、跨检查点运行测试,以及逐提示词(prompt-by-prompt)而非仅作为单一总分来分析结果。

1. 运行环境的灵活性 Harbor 采用统一的方式运行所有内容——即在密封、可复现的容器内。由于容器资源消耗较大,olmo-eval 允许用户选择每个基准测试的运行方式。

  • 轻量级路径(默认): 仅需模型回答问题的基准测试可直接运行,速度更快、成本更低。
  • 隔离容器路径: 需要锁定环境的基准测试(例如运行模型编写的代码)则使用隔离容器设置。 olmo-eval 仅在基准测试确实需要时才选择重型设置。

2. 基准测试的添加流程 Harbor 的基准测试添加流程旨在支持计划公开分享和发布的评估,因此包含额外的验证步骤。olmo-eval 则旨在加速开发过程,其添加基准测试的方式取决于需求:

  • 对于基本评估,只需简短定义。
  • 允许模型在通过基准测试时使用工具。
  • 对于已有自有代码和流程的基准测试,只需添加一个薄包装(thin wrapper),olmo-eval 即可直接运行并与其他基准测试分数以相同格式报告。

3. 模块化与组件互换性 虽然 Harbor 和 olmo-eval 都将基准测试与运行时策略(模型如何生成答案)分离,但 olmo-eval 设计了更高的模块化程度。在 olmo-eval 中,被评估的模型、可用的工具、容器化环境以及任何辅助模型(如作为裁判的 LLM)都是可互换的组件。开发者可以在多个框架中重用工具,或将评分模型插入某个基准测试而不干扰其他测试,且无需大量努力即可调整细微设置(如提示词的具体措辞)。

4. 结果报告的深度 Harbor 报告每个模型的整体得分。olmo-eval 同样报告整体得分,但每个得分都附带标准误差(standard error)和最小可检测效应(minimum detectable effect,即可靠区分于噪音的最小差异)。更重要的是,olmo-eval 提供了更实用的视图:将两个模型检查点的相同问题逐一对齐进行比较,同时保持其他变量不变。这有助于开发者判断整体平均值的微小变化是真正的改进,还是仅仅是噪音。

集成的评估栈

olmo-eval 由四个组件组成,这些组件既可单独使用,也可协同工作以收紧实验性的 LLM 开发循环:

  1. 任务/套件/框架抽象(Task/Suite/Harness Abstraction): 将基准测试逻辑与运行时策略解耦。

    • 任务(Task): 定义基准测试(即评估什么)。
    • 套件(Suite): 将任务分组为一起运行的一组。
    • 框架(Harness): 控制每个任务的运行方式。 这种分离使得同一任务可以在标准基线或带有工具和脚手架的情况下运行,而无需改变其测量内容。
  2. 沙盒和能力路由层(Sandbox and Capability-Routing Layer): 包括异步沙盒规划器。支持那些模型响应取决于其使用工具行动(如编写和运行代码或浏览网页)的评估。其核心在于评估模型的真实工具使用能力:当基准测试需要工具时,olmo-eval 会运行这些工具并将结果反馈给模型。

  3. 标准化实验模式(Normalized Experiment Schema): 以相同的结构化格式记录每次运行、其配置和结果。这使得对相关实验进行分组、随时间推移比较检查点成为可能,并避免了在长期模型开发工作流程中经常积累的不一致性。

  4. 结果查看器(Results Viewer): 用于成对模型比较。将两个模型或检查点逐问题对齐,可以揭示整体平均值可能掩盖的微小但真实的性能变化。

代码实现示例

在大多数模型评估设置中,添加基准测试是一个庞大的集成项目。而在 olmo-eval 中,只需定义一个“任务”即可。任务定义了基准测试数据集、评估请求的构建方式以及模型答案的评分方式。

以下是一个定义 InternalFreshQA 任务的 Python 代码示例:

from olmo_eval.common.formatters import ChatFormatter
from olmo_eval.common.metrics import AccuracyMetric
from olmo_eval.common.scorers import ExactMatchScorer
from olmo_eval.common.types import Instance, SamplingParams
from olmo_eval.data import DataLoader, DataSource
from olmo_eval.evals.tasks.common import Task, register, register_variant

@register("internal_freshqa")
class InternalFreshQA(Task):
    data_source = DataSource(path="s3://evals/internal/freshqa.jsonl", split="test")
    formatter = ChatFormatter()
    sampling_params = SamplingParams(temperature=0.0)
    metrics = (AccuracyMetric(scorer=ExactMatchScorer),)

    @property
    def instances(self):
        loader = DataLoader()
        for idx, doc in enumerate(loader.load(self.config.get_data_source())):
            yield Instance(
                question=doc["question"],
                gold_answer=doc["answer"],
                metadata={"id": doc.get("id", f"freshqa_{idx}")},
            )

变体(Variants) 可以在不复制基准测试的情况下表达评估策略的变化:

register_variant("internal_freshqa", "3shot", num_fewshot=3, fewshot_seed=1234)
register_variant("internal_freshqa", "zero", num_fewshot=0)

套件(Suites) 将基准测试分组为标准集合,以便一起运行:

from olmo_eval.evals.suites import Suite, register
register(Suite(
    name="base_qa_few_shot",
    tasks=(
        "sciq:mc:3shot",
        "arc_challenge:mc:3shot",
        "internal_freshqa:mc
查看原文 →huggingface.co