最小实验
local。agent 放的是已经配置好的 Adapter 实例,被测应用的地址、鉴权这类连接参数传给 Adapter 工厂,不写在别处。
比较两个模型
一个 Experiment 文件就是一个配置。要比较两个模型,写两个文件,只改model 那一行:
model 会作为 ctx.model 传给 Adapter。Adapter 要把它放进发给应用的请求里,应用才真的会换模型,写法见接入你的 Agent。
attempts: 3 让每条评估用例跑 3 次。Agent 每次的回答都不一样,只跑一次的通过率说明不了多少问题。
比较两版 prompt
prompt 版本在应用内部,NiceEval 看不到。做法和产品里的 A/B 测试一样:应用接受一个 flag,按 flag 切换 prompt;Experiment 负责给这个 flag 赋值。experiments/prompts/v2.ts 把 promptVariant 改成 "v2",其余逐字相同。两个配置之间差得越少,分数的差别就越能归因到 prompt 上。
Adapter 把 ctx.flags 原样转给应用:
flags 是扁平对象,值只能是字符串、有限数字或布尔值。嵌套对象、数组、null 和显式 undefined 都会在运行前被拒绝。评估用例里也能用 t.flags 读到同一份值。
需要检查 flag 是否合法或补默认值时,在 Adapter 上声明同步的 parseFlags(input: unknown)。它的返回值决定实验里 flags 的类型,规范化后的值参与结果沿用的判定。
最常见的失误是两个文件写成了同一个 flags 或同一个 model,例如两边都读同一个环境变量的默认值。运行和报告都正常,但两列数字比的是同一套配置。
跑一组,或者只跑一格
位置参数按 ID 前缀选择 Experiment。目录只用来组织 ID 和批量选择:--dry,见选择并预览运行范围。
看对比结果
两个配置都跑完后,在终端分别查看:Summary 里会列出这几项:
Observed 是有结果的 Attempt 数和计划数。两个数不相等时,说明有些 Attempt 还没有结果,这时的通过率不能直接和另一边比较。
除了通过率,还要看耗时、token、成本和失败的类型。一个配置通过率高一点,成本却翻了一倍,不一定值得换。把两次 Run 并排比较,见比较多个固定 Run;在浏览器里看,用 niceeval view。
让比较有意义
- 比较期间保持评估用例集合不变,否则两边比的不是同一批题。
- 非确定性强的 Agent,尤其是 Coding Agent,每个配置至少跑 3 次。
- 每次只改一个变量。同时换模型又换 prompt,就分不清是谁的功劳。
- 失败要按原因归类看,不只看总分。
只跑部分评估用例
每个 Experiment 用evals 选择要跑哪些评估用例,默认是全部。可以写 ID 前缀数组,也可以写一个函数:
eval.id 是从文件路径推导出的项目内 ID,不是绝对路径,可以直接用 startsWith 判断。
常用字段
字段全集见 defineExperiment 参考。
不同评估用例需要不同环境
一批真实任务可能需要不同版本的运行时,例如有的题要 Python 3.9。这时把 Sandbox 直接写在评估用例上,让任务和它需要的环境放在一起:一个应用用多个模型
应用内部有规划、回复、审查等不同角色,各用一个模型时,用models 按用途分别指定:
ctx.models 读取这份配置交给应用,每次请求模型时在 ctx.recordUsage 里写上对应的 modelSlot。这样用量和费用能按用途分开统计;没被调用的角色不会产生费用。
models 不能和 model、reasoningEffort 同时写。Agent 类的 Adapter 只用单个 model。
运行后用 niceeval show @<locator> --usage 查看一次运行里各个模型的用量和费用。Judge 的用量没有上报时会显示为不可用,总费用只给出已知部分。