评测与比较结果
评测需要可复现的输入,也需要能解释的结果。EnvLoop 分别记录执行状态、verifier reward、结构化输出和评分覆盖率,帮助区分运行失败、模型得分低和测量缺失。
先运行一个小评测
- 选择可读的 Dataset revision 及其固定 Runner。
- 选择包含 Runner 所需模型或 Agent 参数的 Profile。只有 Runner 实际读取的参数才会生效。
- 先提交一道题,检查日志、reward 和产物,确认流程正确后再提交完整 Dataset。
- 对比实验保持 Dataset、Runner、Task 集合和 attempts 一致,同时记录 Profile、模型与 request ID。
el job submit --dataset DATASET_NAME@VERSION --attempts 2 --profile team/eval@1
el job get JOB_ID
el job result JOB_ID
所有资源占位符都应替换成目录中的实际值。Attempts 是独立执行次数,会增加工作量。提交成功表示开始执行,不代表 Agent 已通过 benchmark。
按顺序读取结果
进入 Jobs → 目标 Job → Metrics。先看已完成和已评分的 attempts 数,再看聚合指标与每个 Task 的结果。reward 缺失或异常时,打开对应 Trial。
| 信号 | 回答的问题 |
|---|---|
| Job/Trial 状态 | 执行完成、失败,还是被取消? |
| 退出码和错误 | 报告了什么执行问题? |
| Verifier reward | 声明的评测给出多少分? |
| 结构化结果 | 产生了哪些额外维度或 judge 摘要? |
| 评分覆盖率 | 请求的评测中,有多少实际产生数字 reward? |
| 产物持久化 | 文件能否独立查看和下载? |
completed、succeeded 描述执行结果,不代表 reward 为 1。failed Job 仍可能包含有效得分。返回 checkpoint 或 artifact 引用,本身也不能证明评测成功。
聚合指标
| 字段 | 含义 |
|---|---|
score | 所有有数字 reward 的 attempts 的算术平均值 |
pass | 所有已评分 reward 都为 0 或 1 时的平均值 |
pass@k | 完整评分成员中,至少一次 attempt 通过的比例 |
pass^k | 完整评分成员中,请求的每次 attempt 都通过的比例 |
这里的 k 是每个成员请求的 attempts 数。只有恰好派发了该数量、且每次都有分数的成员,才进入两个 k 指标的分母。没有完整评分成员时,两者均为 null。非二值 reward 会让二值指标为 null;没有任何已评分 attempt 时,所有指标均为 null。Console 显示实际 k,例如 pass@2 / pass^2,通过率显示为百分比。Job scores、逐 Task 结果与项目排行榜统一展示主分:0~1 使用百分比(0.75 → 75%、1 → 100%),超出该范围保留原始尺度。API 的 score 仍是 reward 均值,独立综合分和维度沿用自身单位。
例如每题运行两次,A 的 reward 为 [1, 0],B 为 [1, 1],C 为 [0, 缺失]。API 的平均分和 pass 都是 3/5 = 0.6,Console 显示为 60%。只有 A、B 进入 k 指标,所以 pass@2 = 1.0、pass^2 = 0.5。C 缺失的一次不会被当成零,高 pass@2 也不代表全部请求题目已经完整评测。
与 benchmark 估计量的关系
同一题做 n 次二值评测、其中 c 次通过时,一般公式为 pass@k = 1 - C(n-c,k)/C(n,k)、pass^k = C(c,k)/C(n,k),要求 1 ≤ k ≤ n。先计算每题结果,再按题目等权平均。例如 n=5、c=3、k=2 时,结果为 90% 和 30%;将实测成功率直接代入 1-(1-p)^k 或 p^k 会得到不同的估计值。
Job 目前只提供 n=k 的特例:至少一次成功与全部成功,不提供独立选择 k 的多点曲线。参考 Terminal-Bench 使用的 Harbor pass@k 实现及 τ-bench pass^k 实现。Harbor 把缺失 verifier reward 算作失败;EnvPlatform 保留未知并报告覆盖率。只有缺失处理政策与评测协议一致时,分数才能直接比较。
报告分数时同时报告覆盖率
API 的每个聚合结果都有 score_counts:
total:请求 Task 数 × 每题 attempts,包含尚未派发的槽位。scored:具有数字 reward 的 attempts。missing:请求中没有 reward 的 attempts,包括尚未派发、等待中或运行中的尝试。invalid:已经结束但没有 reward 的 attempts。total_members:选中的 Dataset 成员数。complete_members:所有请求 attempts 都已评分的成员数。
建议记录“score 0.6,5/6 attempts 已评分,2/3 成员完整”,而不只写“score 0.6”。比较得分时同时检查失败与缺失数量,尤其要关注不同模型的超时比例。部分覆盖不能代表完整测试集的成绩。
结构化指标
受支持的声明结果文件可以提供 composite、命名维度和 judge 摘要。Trial 的 Metrics 会把它们与 reward 一起展示,但 Job 排名的评分来源仍是 verifier reward。结构化提取不可用或无效时,可继续在 Artifacts 查看原始输出。
比较自定义维度时,应确认名称、量纲、优劣方向和 verifier 版本一致。两份结果都叫 accuracy,不足以证明它们测量同一件事。
查看项目内排行榜
在 Jobs → Metrics → Project leaderboard 只读查看已保存的结果、排名、得分与覆盖率;Console 不提供添加结果的写入按钮。
排行榜比较主动提交、且冻结 Dataset revision、Runner 引用、Task 名称/digest 和 attempts 都相同的 Job,模型和 Profile 可以不同。每行包括排名、模型或 Job ID、得分、已评分数、缺失数和已有 composite 指标。点击行内链接可回到来源 Job。
失败但有部分得分的 Job 也可能上榜,所以不能忽略缺失数量。重复添加同一个 Job 会返回已保存的快照。榜单仅在项目内可见,不会自动发布到公开网站。公开提交流程见研究与排行榜。
从失败决定下一次实验
执行错误先看 stderr 和输入兼容性;reward 为 0 时看 verifier 输出与最终产物;reward 缺失时,判断失败发生在执行、评测还是产物收集。每次只改变一个受控变量,必要时发布新 Profile 版本,再用新 request ID 提交。保留原 Job 作为比较依据。
评测训练后的模型
训练和评测是独立的 Job。连接方式是:在训练前后,用同一份留出集评测,并按任务选择评测阶段:
| 阶段 | 做法 | 适用于 |
|---|---|---|
| 训练后 | 检查托管 Job 已保存的 checkpoint,再用正常 inference API 评估相同的留出输入 | 选择 checkpoint 并验证泛化;不提供交互式训练中采样 |
| 部署后 | 用相同 prompt 和生成参数分别调用端点的 /sft 与 /base 别名(推理) | 用自己的评分器做前后对比 |
| Agent benchmark | el job submit --dataset ... 搭配 Profile | 带 verifier 和 pass@k 的多步 Agent 任务 |
下面是对端点做前后对比的最小脚本。把评分函数换成你任务的 verifier,留出集不要进入训练数据:
import json, os
from openai import OpenAI
client = OpenAI(base_url="https://api.envloop.ai/v1/job/YOUR_JOB_ID/Inference",
api_key=os.environ["ENVLOOP_API_KEY"], timeout=120)
rows = [json.loads(line) for line in open("heldout.jsonl")] # {"prompt": ..., "answer": ...}
def score(model):
correct = 0
for row in rows:
out = client.chat.completions.create(
model=model, messages=[{"role": "user", "content": row["prompt"]}],
max_tokens=256, temperature=0).choices[0].message.content or ""
correct += out.strip() == row["answer"]
return correct / len(rows)
for alias in ("YOUR_ENDPOINT_MODEL/base", "YOUR_ENDPOINT_MODEL/sft"):
print(alias, score(alias))
用 Agent benchmark 评测训练后的模型
推理端点同时提供 Anthropic Messages API,托管的 Claude Code Agent 可以直接使用你训练的模型。先部署 checkpoint,再发布一个以该端点为模型的 Profile:
{
"schema_version": "envplatform.profile/v2",
"name": "team/eval-my-model",
"version": "1",
"secret_params": ["MODEL_API_KEY"],
"spec": {
"params": {
"AGENT_NAME": "claude-code",
"AGENT_VERSION": "2.1.285",
"MODEL_PROTOCOL": "anthropic",
"MODEL_BASE_URL": "https://api.envloop.ai/v1/job/YOUR_INFERENCE_JOB_ID/Inference",
"MODEL_NAME": "YOUR_ENDPOINT_MODEL/sft",
"MODEL_API_KEY": "YOUR_ENVLOOP_KEY",
"CLAUDE_CODE_MAX_OUTPUT_TOKENS": "4096",
"CLAUDE_CODE_EFFORT_LEVEL": "medium"
}
}
}
el profile create team/eval-my-model 1 --file eval-profile.json
el job submit --dataset DATASET_NAME@VERSION --profile team/eval-my-model@1 --attempts 2
- 将
CLAUDE_CODE_EFFORT_LEVEL设为模型接受的推理强度。否则 Claude Code 会请求high,qwen38-27b@1会以 400 “Unexpected reasoning effort” 拒绝;Qwen3.8 接受low、medium和xhigh。 - 托管 Claude Code Agent 仅在 EnvLoop 为你的项目开通后可用。若提交被拒绝,请联系 EnvLoop 支持;你也可以按上面的方式设置
ANTHROPIC_BASE_URL和ANTHROPIC_MODEL,自行运行 Claude Code 调用该端点。 MODEL_API_KEY是有权调用该端点的 EnvLoop Key,建议使用只限该端点的推理专用 Key;它以 Secret 形式保存在 Profile 中。- 再发布一个
MODEL_NAME为YOUR_ENDPOINT_MODEL/base的 Profile,用相同的 Dataset、Runner 和 attempts 运行,即可在项目排行榜上比较训练前后。 - Claude Code 的指令和工具定义会占用较多上下文。
CLAUDE_CODE_MAX_OUTPUT_TOKENS要足够小,使提示词加输出不超过推理 profile 的上下文(qwen38-27b@1与glm53-flash@1为 32,768 token);较长的多步任务仍可能超出。 - 端点需要正在运行或可被唤醒,冷启动会推迟 Agent 的第一步。推理时间照常计入端点费用。
当前限制:
- 平台不会在训练结束后自动发起评测。每一轮需自行记录:用
agent_run/agent_round标记训练 Job(模型循环),并用同一 run 名称保存评测 Job ID 或分数。 - 在训练用过的 prompt 上分数更高,不能证明模型进步。比较前先冻结留出集和评分器。