指南
从 Node 进行评测
Node SDK 在 Node 中、在你自己的测试运行器里运行你的系统及其评估器,并把分数交给作出决定的 Python 引擎。TypeScript 团队保留自己的代码、fixture 和测试运行器;每一个区间、比较和决定都仍由引擎给出,SDK 一个都不计算,连平均值也不算。
安装
npm install --save-dev @oloproof/sdk
pip install oloproof第一行是 SDK,第二行是它把分数交给的引擎(Python 3.11 或更高版本)。SDK 会在你的 PATH 中查找 oloproof;如果找不到,它会停下来并说明如何安装。
在测试中为系统打分
测试套件就是引擎读取的那个 JSON Lines 文件(编写测试套件),每行一个用例,每个用例带一个 id。把测试套件、系统以及每个判据一个评估器交给 evaluate:
import { test } from "vitest";
import { type Case, decide, evaluate } from "@oloproof/sdk";
import { answer, rateHelpfulness } from "./support-bot.js";
type SupportCase = Case<{ question: string }, { label: string }>;
type Answer = { label: string; text: string };
test("the support bot is good enough to release", async () => {
const scored = await evaluate<SupportCase, Answer>({
suitePath: "data/support.jsonl",
system: (testCase) => answer(testCase.input.question),
evaluators: {
exact_label: (output, testCase) => ({ passed: output.label === testCase.expected?.label }),
helpfulness: {
scale: [0, 1],
judge: "gpt-4o-mini",
evaluate: async (output, testCase) => ({ score: await rateHelpfulness(output, testCase) }),
},
},
concurrency: 8,
out: "scores/candidate.jsonl",
});
console.log(scored.counts);
}, 600_000);评估器返回 { passed } 或 { score },可附带一个 reason。一个函数判定通过或失败;打分的评估器要声明它的 scale,因为均值上的区间只在读取分数之前就已知的范围内才成立。由模型评判时,请在 judge 中写明该模型:引擎随后会把它当作评判模型,在它获准对发布做门禁之前先与人对照检验(评判模型)。
concurrency 限制同时运行的用例数(默认为四个)。分数文件按测试套件给出的顺序列出用例,无论它们以什么顺序完成。
让引擎来决定
const decided = await decide({
scores: "scores/candidate.jsonl",
baseline: "scores/baseline.jsonl",
policy: "release.yaml",
});
console.log(decided.exit, decided.comparison?.gate?.decisions);decide 在 cwd 指定的目录(默认为当前目录)中运行你本来会手动输入的命令:
oloproof scores import scores/baseline.jsonl scores/candidate.jsonl --tool node
oloproof compare RUN_ID BASELINE_RUN_ID --policy release.yaml --json有基线时,引擎按用例逐一比较两次运行,decided.comparison 就是 oloproof compare --json 打印出的记录。没有基线时,decide 对导入的运行执行 oloproof gate,并在 decided.decision.stdout 中返回它打印的内容。无论哪种情况,decided.exitCode 都是引擎的退出码,原样不变,decided.exit 则是它的名称:EXIT_CODES 把每个名称映射到引擎的值,与 在 CI 中运行 列出的一致。
文件包含什么
该文件就是 oloproof scores import 读取的文件(第二意见):每个用例和判据一行,只有用例 id 和分数。答案、输入或 reason 绝不会进入其中;它们留在 Node 中的 scored.results 里。
- 系统抛出异常的用例,会在每个判据上写入空值;评估器抛出异常的用例,会在该判据上写入空值。引擎把每一个都计为缺失,并按最坏情况界定,因此一次失败会降低证据所能表明的内容,而不是从证据中消失。scored.errors 列出每一个及其消息。
- 文件无法承载的结论会以错误终止运行,且什么都不写入:没有量表或超出量表的分数、同时带有分数和通过,或者引擎无法命名为指标的判据。
- 每个文件都是一个由其内容标识的系统版本,因此再次导入同一个文件会复用引擎已存储的内容。
无需安装引擎
secondOpinion 把两个分数文件发送到托管页面,该页面无需安装任何东西即可回答“这是真的吗?”,并原样返回引擎写出的答案:
import { secondOpinion } from "@oloproof/sdk";
const result = await secondOpinion({
baseUrl: "https://oloproof.com",
baseline: "scores/baseline.jsonl",
candidate: "scores/candidate.jsonl",
});
if (result.ok) console.log(result.opinion.answers);
else console.log(result.error, result.description);该页面不保留任何东西,也无需账户。它每个文件最多读取 2 MB,并按客户端限流;被拒绝时会返回引擎指出需要修改哪一行的那句话。
尚未构建的功能
- 将 @oloproof/sdk 发布到 npm。在此之前,请从仓库中的 packages/sdk 构建它。
- Node 中任何形式的统计量,这是有意为之:SDK 写出分数并读取引擎的答案。
- 测试套件中的 group_id 或 time_order 不会带入导入,导入只读取用例 id 和分数,因此引擎把这些用例视为相互独立。
下一步
- 第二意见:文件格式以及一次比较回答什么。
- CI 门禁:decide 传给引擎的发布策略。
- Python API:同样的评测,由引擎自己运行。