EvalHarness/README.md

189 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# EvalHarness
插件式 LLM/Agent 评测框架28 个 benchmark 开箱即用,官方口径 prompt 与判分,任意 OpenAI 兼容端点,断点续跑。
```
提供端点 → 拉数据 → 渲染官方 prompt → 并发生成 → 官方判分 → 报告
```
## 0. Benchmarks
| 族 | benchmark |
|---|---|
| 数学 | `gsm8k` `competition_math` `aime24/25/26` `hmmt26` `imo_answerbench` |
| 知识/选择题 | `mmlu` `mmlu_pro` `cmmlu` `gpqa_diamond` `arc` `hellaswag` `winogrande` `bbh` |
| 问答 | `trivia_qa` `drop` `simple_qa` `hle` |
| 长上下文 | `longbench_v2` `openai_mrcr` |
| 代码Docker 沙箱) | `humaneval` `bigcodebench` `live_code_bench` |
| Agent/工具 | `bfcl_v3` `general_fc` `tau2_bench` `swe_bench_verified` |
```bash
evalharness data list # 28 个数据集:源/子集/few-shot/split
evalharness eval list # 28 个判分 recipe
```
## 1. 安装
Python ≥ 3.10;代码执行类 benchmark 需宿主机 Docker镜像判分时自动拉取
```bash
git clone https://git.meta-stone.net/sora/EvalHarness.git
cd EvalHarness
conda create -n evalharness python=3.10 -y
conda activate evalharness
pip install .
```
离线自检(不联网、不接模型,应得 acc 100%
```bash
evalharness eval run gsm8k --model mock-boxed --limit 8
```
## 2. 运行命令
单端点:
```bash
evalharness eval run gsm8k \
--api-url http://localhost:8000/v1 \
--model qwen3-8b \
--disable-thinking \
--limit 200 --resume \
--out-dir results/run1
```
多端点池(轮询 + 自适应并发 + failover
```bash
evalharness eval run mmlu \
--provider openai-pool \
--api-url 'http://gpu1:{8123..8130}/v1,http://gpu2:{8200..8203}/v1' \
--model qwen3-8b --disable-thinking
```
需要 judge 的 benchhle / simple_qa / imo
```bash
evalharness eval run hle \
--api-url http://localhost:8000/v1 --model qwen3-8b --disable-thinking \
--judge-model dp4-flash \
--judge-api-url http://judge-host:30000/v1 \
--limit-per-task 25
```
Agent bench多轮工具调用
```bash
evalharness eval run bfcl_v3 --api-url http://localhost:8000/v1 --model qwen3-8b \
--env bfcl_mock
```
Python API
```python
import evalharness
rep = evalharness.run('gsm8k', 'openai/http://localhost:8000/v1?qwen3-8b', limit=200)
rep.save('gsm8k.report.json')
# notebook / async 环境用 await evalharness.arun(...)
```
## 3. 参数速查
| 参数 | 作用 |
|---|---|
| `--api-url` `--model` `--provider` | 端点、模型名(纯名字,无需拼 spec、协议`openai-chat`/`openai-pool` |
| `--api-key` | 显式 key优先于环境变量只进请求头不写入 spec/报告) |
| `--disable-thinking` | `enable_thinking=false`Qwen3 类模型推荐;带 tools 的请求自动退回兼容软开关) |
| `--judge-model` `--judge-api-url` `--judge-api-key` `--judge-provider` | judge 端四件套,语义与主模型对称 |
| `--limit N` / `--limit-per-task N` | 全局前 N / 每子集前 N多科目 bench 用后者;可组合取交集) |
| `--subset` `--split` `--source` | 覆盖子集 / split / 数据源(可指本地路径离线跑) |
| `--concurrency N` | 并发(默认 32长输出 bench 建议 8-16 |
| `--resume [PATH]` | 断点续跑;默认 `<cache-dir>/ckpt/<bench>.jsonl` |
| `--profile NAME` | 命名生成参数集(`dp4-nothink` / `qwen3-es-parity` / `t1-short` 或自定义) |
| `--env NAME` | agent 环境(`bfcl_mock` 等) |
| `--perf` | 采集流式 TTFT / ITL / 重试率入报告 |
| `--hf-endpoint URL` | 数据下载端点(如 `https://hf-mirror.com`,免手动 export |
| `--cache-dir DIR` | 缓存根(数据缓存 + 断点同根) |
| `--out FILE` / `--out-dir DIR` | 报告落盘;多 bench 时写 `reports/` + `viz/` + `summary.md` |
| `--style text\|md\|md_compare\|excel\|radar\|errors` | 结果渲染样式 |
| `--no-progress` | 关闭 Rich 进度条(重定向日志时用) |
API key 解析顺序:`--api-key` > 按端点域名的环境变量(`api.openai.com``OPENAI_API_KEY``anthropic.com``ANTHROPIC_API_KEY``dashscope``DASHSCOPE_API_KEY``bigmodel``ZAI_API_KEY`> `OPENAI_API_KEY`。自建端点无鉴权可不管。
## 4. 评测结果
```bash
evalharness viz show gsm8k.report.json # 控制台表格
evalharness viz show a.json b.json --style md_compare # 多模型对照(含差值标记)
evalharness viz show report.json --style excel # 4-sheet 仪表盘
evalharness viz show report.json --style errors # 失败样本下钻
```
`--out-dir` 自动产出:`reports/<bench>.report.json`每样本原始预测、分数明细、token 用量、agent 轨迹)、`viz/<bench>.txt``summary.md`(全 bench 一张表)与 `summary.csv`(含 perf 列)。
## 5. 缓存与断点
```bash
evalharness data fetch gsm8k mmlu --workers 8 # 预取(首次运行也会自动下载)
evalharness data stats cmmlu # 条数/长度/答案分布
evalharness data show gsm8k -n 2 # 看前 2 条样本
evalharness data unload gsm8k # 删缓存
```
- 数据缓存内容寻址subset/split/source 变更自动新条目),位置 `<cache-dir>/datasets/`
- 断点每条预测即写盘;**改了 prompt 模板须删旧断点**`rm <cache-dir>/ckpt/<bench>*.jsonl`),否则复用旧预测
- 网络抖动三层防护15s 连接超时快速失败 → 池内换端点 → 分钟级退避重试,断网不丢批次
- 判分与生成解耦:换 recipe / grader 对存量预测直接重判(`evaluate(ds, preds)`),模型不被重复调用
- Docker 镜像源回退链可用 `EVALHARNESS_DOCKER_MIRRORS` 覆盖(逗号分隔模板,`{img}` 占位)
## 6. 扩展
加数据集(单文件放入 `evalharness/data/datasets/`,自动注册):
```python
@register_dataset(DatasetSpec(name='mybench', source='org/mybench',
split='test', task_type='mcq'))
def mybench():
return FieldSpec(input='question', choices='options', target='answer_key')
```
绑定判分recipe = 注册原语的声明式组合):
```python
@register_eval('mybench')
def mybench():
return EvalRecipe(
extract=['my_answer', 'answer_phrase'], # 级联,首个成功者胜
scorers={'acc': 'exact'}, # math_equal/em_f1/execution/env_reward/llm_judge
aggregators={'acc': 'mean'}, # pass_at_k/grouped_avg/binned_avg
)
```
其余插件点同构:`@register_prompt_renderer``@register_extractor/scorer/aggregator``@register_adapter``@register_sandbox``@register_env``@register_renderer`
## 7. 架构
```
data/ 统一 Sample schema惰性物化内容寻址缓存28 个单文件插件)
model/ adapter协议+ pool端点池/AIMD/failover+ prompt_renderers + gen_profiles
eval/ extract → score → aggregate 流水线 + recipes
sandbox/ docker 硬隔离执行 / local镜像引用计数
agent/ 消息泵 + Environment 插件bfcl/tau2/swe
viz/ text/md/md_compare/excel/radar/errors
progress/ Rich 每样本进度(缺 rich 自动降级)
```
层间严格分离:数据层只回答"题目与金标",判分层只回答"如何评判",模型层只回答"如何触达";预测是不可变 artifact。
## 8. 对齐验证
prompt 与判分器经双层验证(字符串级:同一记录双侧渲染逐字节一致;分数级:同题同参数对比 evalscope
- Qwen3-8B23/28 分差 < 0.05
- DeepSeek-V4-Flash20+/25 分差 < 0.05mmlu_pro 0.0000
残差均已定性金标集差异 / 排列敏感 / benchmark 侧缺陷见各 recipe 注释