prime-radiant-inc/smevals
GitHub: prime-radiant-inc/smevals
一个用于对小型及大型语言模型运行评测并用可扩展的 Checker 机制进行评分的 Python 框架。
Stars: 16 | Forks: 0
# smevals
[](https://pypi.org/project/smevals/)
[](https://github.com/prime-radiant-inc/smevals/releases)
[](https://github.com/prime-radiant-inc/smevals/actions?query=workflow%3ATest)
[](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: "
标签:DLL 劫持, Python, 人工智能, 大语言模型, 文档结构分析, 无后门, 模型评估, 用户模式Hook绕过, 逆向工具