prime-radiant-inc/smevals

GitHub: prime-radiant-inc/smevals

一个用于对小型及大型语言模型运行评测并用可扩展的 Checker 机制进行评分的 Python 框架。

Stars: 16 | Forks: 0

# smevals [![PyPI](https://img.shields.io/pypi/v/smevals.svg)](https://pypi.org/project/smevals/) [![Changelog](https://img.shields.io/github/v/release/prime-radiant-inc/smevals?include_prereleases&label=changelog)](https://github.com/prime-radiant-inc/smevals/releases) [![Tests](https://static.pigsec.cn/wp-content/uploads/repos/cas/ce/ce733292a922c08274cf5a2096f8fa4cf01023bfa51a36ef6beecaaef371a9d9.svg)](https://github.com/prime-radiant-inc/smevals/actions?query=workflow%3ATest) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/prime-radiant-inc/smevals/blob/main/LICENSE) 一个用于针对小型(及大型)模型运行 evals 的框架 ## 安装说明 ``` uv tool install smevals ``` 或者 `pip install smevals`,或者直接使用 `uvx smevals --help`。 ## 本项目使用的词汇表 最顶层的概念是 **Eval**:一系列 Task 的集合,用于确定特定模型或模型与 harness 配置在特定高级能力(如 text-to-SQL、画一只骑自行车的鹈鹕,或评估某个实现是否满足提供的规范)上的表现。 Evals 可以选择性地分组到相关 Evals 的 **Suites** 中,这主要作为一种在磁盘上组织它们的机制。 一个 **Eval** 是 **Tasks** 的集合。这些是模型必须完成的单个练习,以便评估其能力。 **Config** 描述了用于尝试 Task 的设置。它指定了一个模型,并且可以包含模型参数、系统 prompt、工具和其他设置。 为了收集证据,我们创建一个 **Run**。Run 是使用 **Runner** 对一个 Task 执行一个 Config 的不可变记录。Runner 是一个可重用的 CLI 程序,可以直接向模型发送 prompt,也可以构建于 agent harness(如 Codex 或 Pi)之上。 同一个 Task 和 Config 可以被执行多次,产生多个 Run,以帮助考虑非确定性的结果——`smevals run -n 5` 会将每个 Task 补充至五次 Run。每个 Run 都包含一个时间戳以帮助跟踪。 Runner 以非零状态退出的 Run 是一个**失败的 Run**:一个 harness 层面的错误(如网络故障),而不是关于模型的证据。失败的 Run 会保留在磁盘上用于调试,但永远不会被评分,会被排除在报告之外,并且不计入 `-n` 目标。 一旦我们收集了 Run,我们就会对每个 Run 应用 **Grader** 以产生一个 **Grade**。Grader 是一个配置好的 **Checks** 序列,以及将其结果组合成 Grade 的规则。 Checks 是单个断言或测量。有些可能很简单,例如“输出是否包含此文本?”另一些可能更复杂,例如“将此 SVG 渲染为图像,并让 LLM 评估员进行评估”。每个 Check 都指定了执行它的 **Checker**,以及该 Checker 的配置(如模式、评分标准或预期值)。一个 Check 可以被标记为必需的,在这种情况下,它的失败将停止 Grader 并跳过其余的 Checks。 **Checker** 是一个命名操作*或*一个实现了某种 Check 的可重用 CLI 程序。`contains` 和 `xml-valid` 是命名操作,`../checkers/render-svg` 可能是一个自定义程序。同一个 Checker 可以被多个 Grader 中的许多 Check 使用。Grader 中的 Checks 按顺序执行并共享一个工作目录,因此 Checker 可以创建文件——例如渲染的图像——这些文件作为 artifact 与 Grade 保存在一起,并可供序列中的后续 Check 使用。 **Grade** 是将 Grader 应用于 Run 的结果。它记录了每个 Check 的结果,并可以包含整体的通过/失败结果和/或数字评分。Grade 还可以包含附加说明,这些说明不用于评分,但可能有助于在未来解释结果。 我们稍后可以更改用于评估 Run 的 Grader,而无需再次执行 Run。因此,单个 Run 可以被多次评估,使用不同的 Grader 产生多个 Grade。 ## 构建 Eval 一个 Eval 是任何包含 `eval.yaml` 文件的目录: ``` my-eval/ ├── eval.yaml # name and description ├── tasks/ # one YAML file per Task ├── configs/ # one YAML file per Config ├── graders/ # one YAML file per Grader ├── checkers/ # custom Checker executables (by convention) ├── run-llm # Runner executable (any name, any location) └── runs/ # created by smevals run - never edit by hand ``` ### Eval 示例:评估 Haiku 以下是如何构建一个完整的 Eval,它要求模型编写 haiku 并根据其结构进行评分。 该 Eval 由五个文件组成。 `my-eval/eval.yaml` 定义了名称和描述: ``` name: haiku description: >- Can the model write a haiku on demand? Graded on structure: the reply must be exactly three lines. ``` 一个 Eval 必须有一个或多个 Task。其中每一个都定义为 `tasks/*.yaml` YAML 文件。 `my-eval/tasks/pelicans.yaml` 必须有一个 `name`;一个 `prompt` 是最常见的情况,但也允许任何其他键,并将作为环境变量传递给 Runner: ``` name: pelicans prompt: Write a haiku about pelicans. Reply with only the haiku, three lines. ``` 一个 Eval 还需要至少一个在 `configs/*.yaml` 中定义的 Config。如果只有一个,则应将其命名为 `default`。 `my-eval/configs/default.yaml` - 名为 `default` 的 Config 在未向 `smevals run` 传递 `-c` 选项时使用。 `runner` 指定一个相对于此文件的可执行程序路径: ``` name: default runner: ../run-llm model: gpt-4.1-mini ``` 这是该 Runner 脚本: `my-eval/run-llm` - 这个脚本使用 [llm](https://llm.datasette.io/) CLI,但任何遵守以下契约的可执行文件都可以。使用 `chmod +x` 使其可执行: ``` #!/usr/bin/env bash set -euo pipefail llm -m "$SMEVALS_MODEL" "$SMEVALS_PROMPT" llm logs -c --json > log.json ``` 该 Eval 还需要一个默认的 Grader,它将用于对每个 Run 的结果进行评分: `my-eval/graders/default.yaml`: ``` name: default checks: - checker: ../checkers/three-lines required: true scoring: pass_threshold: 1.0 ``` `checker` 可以是脚本的相对路径——类似于上面的 `runner:`——也可以是下面列出的内置 checker 的名称。 `my-eval/checkers/three-lines` - 一个自定义 Checker,同样需要 `chmod +x`: ``` #!/usr/bin/env python3 import json, os, pathlib, sys raw = (pathlib.Path(os.environ["SMEVALS_RUN_DIR"]) / "output.txt").read_text() lines = [line for line in raw.strip().splitlines() if line.strip()] print(json.dumps({ "score": 1.0 if len(lines) == 3 else 0.0, "metrics": {"line_count": len(lines)}, "notes": f"{len(lines)} non-empty line(s)", })) sys.exit(0 if len(lines) == 3 else 1) ``` 要运行 eval,对其进行评分,然后查看结果: ``` smevals run my-eval -g # run every task, grade as each finishes smevals run my-eval -m gpt-4.1-nano -m gemini-2.5-flash -g # more models smevals run my-eval -n 5 -g # top every task up to five graded runs smevals report my-eval # markdown report in the terminal smevals serve my-eval # live web UI on http://127.0.0.1:7001 ``` ## Runner 契约 `smevals run` 每个 Task/model 组合执行一次 Runner,不带任何参数。所有内容都通过环境变量传递: - `SMEVALS_MODEL` - 要使用的模型,来自 Config 或 `-m` 选项。 - `SMEVALS_TASK` - Task 的名称。 - `SMEVALS_PROMPT` - Task 的 `prompt`,仅在 Task 具有该属性时设置。 - `SMEVALS_TASK_` - Task 的每个标量键,大写:一个带有 `submission: mutant-003` 的 Task 会提供 `SMEVALS_TASK_SUBMISSION=mutant-003`。 - `SMEVALS_RUN_DIR` - Run 目录的绝对路径。 工作目录是 Run 的目录。契约如下: - 标准输出被捕获为 Run 的 `output.txt` - 它应该是模型的响应。 - 标准错误被捕获为 `stderr.txt`。 - 非零退出码将 Run 标记为**失败**。失败的 Run 是一个 harness 错误 - 网络中断、工具崩溃 - 而不是关于模型的证据,因此它永远不会被评分,被排除在报告之外,并且不计入 `-n` 目标(重新运行相同的命令会执行一个替换)。只有在遇到基础设施问题时才退出非零;只要输出是你希望被评判的真实模型响应,无论多糟糕,都退出 0。 - Runner 写入其工作目录的任何其他文件都将作为 Run artifact 保留(上面示例中的 `log.json`)。 驱动 agent harness 而不是纯模型调用的 Runner 遵循相同的契约:组装 Task 的键描述的任何输入,运行 harness,将最终结果打印到标准输出。 ## Graders Grader 是 `graders/` 中的一个 YAML 文件: ``` name: default checks: - checker: contains # a built-in Checker, by name value: "` - Check 的每个标量键,大写:`rubric:` 变为 `SMEVALS_CHECK_RUBRIC`。 - `SMEVALS_TASK` 和 `SMEVALS_TASK_` - Task 的名称和标量键,以便 Checker 可以定位每个 Task 的特定资源,例如预期答案文件。 工作目录是 grade 工作区,由 Grader 中的所有 Check 按顺序共享:一个 Check 写入的文件(渲染的图像、提取的文档)可供后续 Check 使用,并作为 artifact 与 Grade 保存在一起。 Checker 通过其退出码(0 为通过)发出通过或失败信号。它还可以在标准输出上发出一个包含最多五个键的 JSON 对象,这些键会被记录在 Grade 中: - `score` - 从 0.0 到 1.0 的浮点数。 - `metrics` - 将名称映射到数字或布尔值的对象,例如 `{"precision": 0.9, "status_correct": true}`。报告将数字聚合为平均值 ± stderr,将布尔值聚合为比率。 - `tags` - 短标签列表,例如 `["wearing_a_hat", "correct_bicycle_frame_shape"]`。标签是开放词汇表且仅限存在性的:缺失的标签意味着“未观察到”,而不是“假”。它们被标准化为小写 snake_case,并且 Grade 会记录其所有 Check 标签的并集。报告将它们聚合计数为数量和份额,Web UI 使用它们进行过滤。 - `notes` - 解释结果的人类可读字符串。从不进行聚合。 - `details` - 结构化诊断的对象,例如预测与预期对比的列表。与 Grade 一起保留,但会被聚合忽略。 任何其他键都会被合并到 `details` 中。失败的 Checker 仍然可以发出评分(部分学分测量);在评分之前崩溃的 Checker 会使 Grade 保持未评分状态,如上所述。 ## 磁盘上的 Run 和 Grade 每个 Run 都是一个目录: ``` runs///// ├── run.yaml # the record: full task, resolved config, timing, exit code ├── output.txt # the model's response (runner stdout) ├── stderr.txt # only present if the runner wrote to stderr ├── ... # any other artifacts the runner wrote └── grades/ └── / ├── grade.yaml # outcome, score, tags, per-check results ├── grader.yaml # snapshot of the Grader that produced this Grade └── ... # artifacts written by Checkers ``` 模型名称会被 slugify 用于路径;确切的名称位于 `run.yaml` 中。`run.yaml` 是最后写入的,因此它的存在标志着 Run 的完整性。Run 是不可变的 - 评分只会在 `grades/` 下添加文件。 每个 Grade 都包含其 Grader 的逐字节快照。`smevals grade` 利用这一点来实现可重复性: - 默认情况下,它只对没有来自指定 Grader 的 Grade 的 Run 进行评分,并报告有多少现有的 Grade 是由旧版本的 Grader 规范产生的。 - `--regrade` 删除并为该 Grader 重新创建每个 Grade,因此不会有任何过期的内容保留下来。在编辑 Grader 后使用它。 - 多个 Grader 共存:每个 Grader 都会评分到其自己的 `grades//` 目录中,因此一个 eval 可以同时拥有例如一个廉价的确定性 `default` grader 和一个 LLM 评估员 `judge` grader。 默认情况下,`runs/` 位于 Eval 目录中。向 `run`、`grade` 和 `report` 传递 `--runs-dir DIR` 可以将运行保留在其他地方;然后它们会按 Eval 名称进行命名空间划分。 ## 命令 ``` smevals run EVAL [-m MODEL]... [-c CONFIG] [-t TASK]... [-n N] [-g [GRADER]] [--runs-dir DIR] ``` 使用由 `-c` 指定的 Config(默认为:`default`),针对每个由 `-m` 指定的模型(默认为:Config 的模型)执行每个 Task(或仅执行由 `-t` 指定的 Task)。`-g` 在每次 Run 完成时立即对其进行评分;`-g NAME` 使用该 Grader,光秃秃的 `-g` 使用 `default`。如果任何 Run 失败或评分失败,则以非零状态退出。 `-n N` 是一个目标样本大小:每个 task/model 对都会被补充到至少 N 次成功的 Run,只执行差额部分,因此一旦达到目标,重新运行相同的命令就是一个空操作,并且中断的 session 可以通过重复它来恢复。Run 在所有对上进行完整遍历执行 - 部分中断会留下的样本,而不是第一个 Task 有很多 Run 而最后一个 Task 一个都没有。失败的 Run(非零 Runner 退出)不计入目标:重新运行该命令会为它们执行替换,每次调用尝试一次每对的差额,因此持续失败的 Runner 永远不会在循环中重试。如果没有 `-n`,则每对恰好执行一次新的 Run。 ``` smevals grade EVAL [-g GRADER] [--regrade] [--runs-dir DIR] ``` 将 Grader 应用于每个未评分的 Run。失败的 Run 会被跳过 - harness 错误不值得作为证据进行评分。`--regrade` 丢弃并重做该 Grader 的现有 Grade。 ``` smevals report EVAL [-g GRADER] [--by-task] [--json] [--runs-dir DIR] ``` 打印一份 Markdown 报告:config × model 的排行榜,包含平均值 ± stderr 评分和失败计数、标签份额,以及带有指标的单个 model 区块。失败的 Run 被排除在所有统计数据之外;标题报告了有多少被排除在外。`--by-task` 添加每个 task 的评分。`--json` 则发出原始的 grade 行数据。 ``` smevals serve EVAL_OR_SUITE... [-p PORT] [--host HOST] [-g GRADER] ``` 在一个或多个 Eval 上提供实时 Web UI(默认端口 7001)。每次轮询时都会从磁盘重新读取数据,因此随着新的 Run 和 Grade 落地,页面也会随之更新。一个本身不是 Eval 的目录会被视为 Suite,并递归搜索其中的 Eval。 ``` smevals build EVAL_OR_SUITE... [-o DIR] [-g GRADER] ``` 将相同的 Web UI 构建为一个独立的静态站点(默认为 `build/`),将运行时的 artifact 复制到其中。每次调用都会在输出目录中添加或刷新给定的 Eval,并保持已在其中的其他 Eval 不变,因此一个站点可以聚合来自多个代码库的 Eval。 ``` smevals docs ``` 输出此文档。
标签:DLL 劫持, Python, 人工智能, 大语言模型, 文档结构分析, 无后门, 模型评估, 用户模式Hook绕过, 逆向工具