从定义到执行:Evals框架评估全流程解析

从定义到执行:Evals框架评估全流程解析

引言

你是否在评估大语言模型(LLM)时遇到过流程混乱、指标不统一的问题?本文将带你深入了解Evals框架的核心实现原理,从EvalSpec定义到评估任务执行的完整流程,帮助你轻松掌握LLM评估的关键技术。读完本文后,你将能够:

  • 理解Evals框架的核心组件与数据结构
  • 掌握评估任务的定义与注册方法
  • 熟悉评估执行的全流程与关键步骤
  • 学会如何自定义评估指标与报告结果

核心概念:EvalSpec与评估元数据

Evals框架通过一系列数据结构定义评估的元信息,其中最核心的是EvalSpec。在evals/base.py中,EvalSpec类封装了评估的关键信息,包括评估类、参数、注册路径等:

@dataclass
class EvalSpec:
    """Specification for an eval."""
    cls: str
    registry_path: Path
    args: Optional[Dict[str, Any]] = None
    key: Optional[str] = None
    group: Optional[str] = None

EvalSpec通过YAML配置文件注册在evals/registry/evals目录下,例如:

# 示例:evals/registry/evals/test-match.yaml
test-match:
  cls: evals.elsuite.basic.match.Match
  args:
    samples_jsonl: test-match.jsonl

除了EvalSpec,框架还定义了CompletionFnSpec(完成函数规范)、EvalSetSpec(评估集规范)和RunSpec(运行规范)等数据结构,共同构成评估的元数据体系。

评估执行核心:Eval类与评估流程

评估执行的核心逻辑在evals/eval.py中实现,Eval类是所有评估任务的基类,定义了评估的基本接口:

class Eval(abc.ABC):
    @abc.abstractmethod
    def eval_sample(self, sample: Any, rng: random.Random):
        raise NotImplementedError()
    
    @abc.abstractmethod
    def run(self, recorder: RecorderBase) -> Dict[str, float]:
        raise NotImplementedError()

评估流程概览

评估执行流程主要包括以下步骤:

  1. 加载评估样本:通过get_samples()方法从JSONL文件加载评估数据
  2. 初始化记录器:创建RecorderBase实例记录评估过程与结果
  3. 执行样本评估:调用eval_all_samples()并行处理所有样本
  4. 计算评估指标:通过get_metrics()汇总计算评估结果

评估流程

关键方法解析

  • eval_all_samples():该方法负责并行处理所有样本,支持多线程执行,通过ThreadPool实现并发评估:
def eval_all_samples(
    self,
    recorder: RecorderBase,
    samples,
    show_progress=True,
    record_raw_sample=True,
    **_kwargs: Any,
):
    work_items = _index_samples(samples)
    threads = int(os.environ.get("EVALS_THREADS", "10"))
    with ThreadPool(threads) as pool:
        iter = pool.imap_unordered(eval_sample, work_items)
        idx_and_result = list(tqdm(iter, total=len(work_items), disable=not show_progress))
    return [r for _, r in sorted(idx_and_result)]
  • record_event():记录评估过程中的关键事件,如匹配结果、函数调用等,实现于evals/record.py
def record_event(self, type, data=None, sample_id=None):
    event = self._create_event(type, data, sample_id)
    self.events.append(event)
    if not self.is_paused():
        self.flush_events()

评估任务注册与发现

Evals框架采用插件化设计,通过注册表机制管理所有评估任务。evals/registry.py中的Registry类负责加载和管理评估任务、完成函数等资源:

class Registry:
    def __init__(self, registry_paths: Sequence[Union[str, Path]] = DEFAULT_PATHS) -> None:
        self.registry_paths = list(registry_paths)
        self._completion_fns = None
        self._evals = None
        # ...其他初始化逻辑

    def get_eval(self, name: str) -> Optional[EvalSpec]:
        """获取指定名称的评估规范"""
        return self._evals.get(name)

评估任务通过YAML文件注册在evals/registry/evals目录下,例如test-match.yaml定义了一个简单的匹配评估:

test-match:
  cls: evals.elsuite.basic.match.Match
  args:
    samples_jsonl: test-match.jsonl
  key: test-match
  group: test

评估执行入口:CLI工具

Evals框架提供了oaievaloaievalset两个命令行工具,分别用于执行单个评估和评估集。以oaieval为例,其实现位于evals/cli/oaieval.py,核心逻辑如下:

def run(args: OaiEvalArguments, registry: Optional[Registry] = None) -> str:
    registry = registry or Registry()
    completion_fns = [registry.make_completion_fn(fn) for fn in args.completion_fns]
    eval_spec = registry.get_eval(args.eval)
    run_spec = RunSpec(...)
    recorder = build_recorder(args, run_spec, record_path)
    eval_class = registry.get_class(eval_spec)
    eval_instance = eval_class(completion_fns, eval_spec.registry_path, **eval_spec.args)
    result = eval_instance.run(recorder)
    return json.dumps(result, indent=2)

执行评估的命令示例:

oaieval gpt-3.5-turbo test-match

该命令会加载test-match评估规范,使用gpt-3.5-turbo模型执行评估,并生成评估报告。

自定义评估开发

开发步骤

  1. 定义评估类:继承EvalSolverEval类,实现eval_samplerun方法
  2. 准备样本数据:创建JSONL格式的样本文件,存放于evals/registry/data目录
  3. 注册评估规范:在evals/registry/evals目录下创建YAML配置文件
  4. 测试评估任务:使用oaieval命令执行评估并验证结果

示例:简单匹配评估

evals/elsuite/basic/match.py实现了一个简单的匹配评估,核心代码如下:

class Match(Eval):
    def __init__(self, completion_fns, samples_jsonl, *args, **kwargs):
        super().__init__(completion_fns, *args, samples_jsonl=samples_jsonl, **kwargs)
    
    def eval_sample(self, sample, rng):
        prompt = sample["prompt"]
        result = self.completion_fn(prompt=prompt)
        sampled = result.get_completions()[0]
        correct = sampled.strip() == sample["expected"]
        self.record_match(correct, expected=sample["expected"], picked=sampled)
    
    def run(self, recorder):
        samples = self.get_samples()
        self.eval_all_samples(recorder, samples)
        return {"accuracy": get_accuracy(recorder.get_events("match"))}

评估结果记录与分析

评估过程中的所有事件都由RecorderBase记录,实现于evals/record.py。记录的事件包括样本匹配结果、函数调用、错误信息等。默认情况下,记录会保存为JSONL文件,存放于tmp/evallogs目录。

评估结果的分析工具位于scripts/make_plots.py,可以生成各种可视化图表,帮助理解模型性能。

总结与展望

Evals框架通过清晰的架构设计和灵活的插件机制,为LLM评估提供了全面的解决方案。本文详细介绍了从EvalSpec定义到评估执行的完整流程,包括核心数据结构、评估逻辑、CLI工具和自定义评估开发。未来,Evals框架将继续扩展评估任务库,支持更多复杂场景的LLM评估需求。

要深入了解更多细节,建议参考以下资源:

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值