# 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 的 bench(hle / 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]` | 断点续跑;默认 `/ckpt/.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/.report.json`(每样本原始预测、分数明细、token 用量、agent 轨迹)、`viz/.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 变更自动新条目),位置 `/datasets/` - 断点每条预测即写盘;**改了 prompt 模板须删旧断点**(`rm /ckpt/*.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-8B:23/28 分差 < 0.05 - DeepSeek-V4-Flash:20+/25 分差 < 0.05(mmlu_pro 0.0000) 残差均已定性(金标集差异 / 排列敏感 / benchmark 侧缺陷),见各 recipe 注释。