做一套响应质量的回归测试框架
目标
从零开始构建评估 harness,同时测量质量与延迟,并完成一个自动判断相对 baseline 是否发生 regression 的 CI gate。
为什么重要
没有评估 harness 就更换模型或 prompt,等同于不写测试就进行重构。常见的循环是:问几个问题后凭“好像变好了”作出决定;两周后收到某类问题质量下降的反馈;却没有判断是否应回滚的依据。LLM 输出并非确定性,因此不可能做到完美评估,但完全可以测量到足以发现 regression 的程度。本实验中特别重要的是第 5 步:只测质量仅完成了一半。如果质量提高 2 个百分点,但延迟翻倍,那并不算改进。而第 7 步的 CI gate 会让这一切真正持续运行。依靠人记得执行的评估,最终一定不会执行。
步骤
- 读取
/opt/fixtures/llms/evalset.jsonl(40 条,每行包含id、prompt、expected、grader),并在/root/ev/loaded.txt中写入cases=40 graders=<쉼표로 이은 종류>。 - 使用
/root/ev/run.py在 8170 server 上执行全部 case,生成/root/ev/results.jsonl。每行必须包含id、output、latency_ms,共 40 行。 - 对
grader为exact的 case 进行精确匹配评分。在/root/ev/exact.txt中写入cases=<n> passed=<n> score=<0~1 소수>。 - 对
grader为contains的 case 按 keyword 包含比例评分。在/root/ev/contains.txt中使用相同格式,且score必须在 0 到 1 之间。 - 将 latency SLO 设为 800ms,并统计违反次数。在
/root/ev/latency.txt中写入slo_ms=800 violations=<n> p99_ms=<수>。 - 将总分保存到
/root/ev/baseline.json,格式为{"score":<수>,"p99_ms":<수>,"cases":40}。然后使用/root/ev/compare.py将新执行结果与 baseline 比较,在/root/ev/regression.txt中写入baseline=<수> current=<수> delta=<부호 있는 수> verdict=<PASS|FAIL>。阈值为 -0.03。 /root/ev/gate.sh在发生 regression 时以退出码 1 结束,否则以 0 结束。测试两种情况,并在/root/ev/gate.out中写入pass_exit=0 fail_exit=1。
参考
- 127.0.0.1:8170 的 backend 不会预先运行在本 Pod 中。它只需接收
POST /generate的{"prompt":..., "max_tokens":n}并返回{"text":..., "usage":{...}};因此,可以直接使用前面的 token streaming 实验中创建的 server,也可以启动满足相同 contract 的最小 server 后再开始。若要制造 regression,最好提供一个可从外部调整质量的控制项。 - 评估集应反映真实流量分布。只收集表现良好的 case,就无法发现 regression。
- 阈值必须大于 noise。3 个百分点可以作为起点;评估集较小时,应设置得更大。
- 建立把用户反馈发现的失败 case 加入评估集的循环,就不会重复发生同一失败。
- 常见错误 1:只测质量,遗漏延迟和成本。
- 常见错误 2:构建 harness 后却不放入 CI。依靠人记得执行的评估最终一定不会运行。
加载评估集
读取 /opt/fixtures/llms/evalset.jsonl(40 条,每行包含 id、prompt、expected、grader),并在 /root/ev/loaded.txt 中写入 cases=40 graders=<쉼표로 이은 종류>。
JSONL 中每行是一个 case。不同 case 可以使用不同评分方式。
使用 runner 执行全部 case
使用 /root/ev/run.py 在 8170 server 上执行全部 case,生成 /root/ev/results.jsonl。每行必须包含 id、output、latency_ms,共 40 行。
必须把结果与原始内容一起保留,之后才能查看具体哪里出错。
进行精确匹配评分
对 grader 为 exact 的 case 进行精确匹配评分。在 /root/ev/exact.txt 中写入 cases=<n> passed=<n> score=<0~1 소수>。
这种方式适合结构化输出。请先 normalization 空白和大小写。
进行部分分数评分
对 grader 为 contains 的 case 按 keyword 包含比例评分。在 /root/ev/contains.txt 中使用相同格式,且 score 必须在 0 到 1 之间。
自由文本按 keyword 包含比例计算分数。结果必须介于 0 和 1 之间。
统计 latency SLO 违反次数
将 latency SLO 设为 800ms,并统计违反次数。在 /root/ev/latency.txt 中写入 slo_ms=800 violations=<n> p99_ms=<수>。
只测质量仅完成一半。变慢同样是 regression。
保存 baseline 并判断 regression
将总分保存到 /root/ev/baseline.json,格式为 {"score":<수>,"p99_ms":<수>,"cases":40}。然后使用 /root/ev/compare.py 将新执行结果与 baseline 比较,在 /root/ev/regression.txt 中写入 baseline=<수> current=<수> delta=<부호 있는 수> verdict=<PASS|FAIL>。阈值为 -0.03。
没有比较对象就无法作出判断。阈值必须大于 noise。
创建 CI gate 脚本
/root/ev/gate.sh 在发生 regression 时以退出码 1 结束,否则以 0 结束。测试两种情况,并在 /root/ev/gate.out 中写入 pass_exit=0 fail_exit=1。
目标是让它无需依靠人的记忆。请通过退出码表示是否通过。