本节摘要:评测资产进了仓库(9.1 节),本节把它挂到研发流程上:每次 PR 自动跑评测,红线挡合并。门禁设计的第一刀切在阻塞线与观察线之间:阻塞线红了挡合并——主集通过率(不低于基线 −2pp,示意)、hard 子集(不许新增失败)、安全子集(零容忍);观察线只评论不挡——成本、延迟、p95 波动(值得看见,但不足以否决一次功能合并)。第二刀切在失败分流:CI 红了先问"是哪类红"——真回归(改坏了,修代码)、评测集过期(需求变了老题失效,走重标流程而不是删题)、环境抖动(限流、网络,有重试上限)——杜绝"红了就重跑到绿",那等于没有门禁。团队侧配三个机制:评测 owner(考卷的守门人,9.1 节 PR 审批人)、badcase 入库流程(事故 → case → 用例 → 评审,第 3.1 节生长机制的流程化)、豁免须记录(特殊情况下 bypass 门禁要在 PR 里显式登记理由与补偿动作)。本节附 GitHub Actions 示例(标注写法示意)与 PR 评论式报告的形态。
阅读完本节,你应当能够:
| 线 | 包含什么 | 红了怎样 | 理由 |
|---|---|---|---|
| 阻塞线 | 主集通过率 ≥ 基线 −2pp;hard 子集零新增失败;安全子集全过;lint(9.1)全过 | 挡合并 | 这些是"已知不能坏的东西"——坏了就是回归 |
| 观察线 | 单请求成本、p95 延迟、通过率升幅、裁判均分变化 | PR 评论提示,不挡 | 值得看见的趋势,但波动常来自样本噪声(第 4.1 节重复方差),不足以否决功能 |
划线的原则(观点):阻塞线要少而硬。什么都挡等于什么都不挡——门禁的可信度和第 8.2 节告警的信用是同一种东西:一旦开发者学会"找 owner 豁免"当常规操作,红线就退役了。每条阻塞线必须能用一句话说清"它守住哪次真实事故"——说不出的那条是仪式,删掉。
# .github/workflows/evals-gate.yml(写法示意,以官方文档为准) name: evals-gate on: pull_request: paths: ["src/**", "evals/**"] # 动代码或动考卷都触发 jobs: evals: runs-on: ubuntu-latest timeout-minutes: 30 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: {python-version: "3.12"} - name: Lint datasets(9.1 守门员) run: python evals/scripts/lint_dataset.py evals/datasets/main_v12.jsonl - name: Run regression(跑回归集) run: python evals/scripts/run_regression.py --dataset evals/datasets/main_v12.jsonl --hard evals/datasets/hard_cases.jsonl --security evals/datasets/security_cases.jsonl --baseline evals/reports/baseline.json --report evals/reports/pr_report.json # 非零退出码 = 触发阻塞线 - name: Upload report(观察线数据随 PR 存档) if: always() # 失败也上传,便于分流 uses: actions/upload-artifact@v4 with: name: evals-report path: evals/reports/pr_report.json - name: Comment summary(把成绩单写进 PR) if: always() run: python evals/scripts/post_pr_comment.py evals/reports/pr_report.json
工作流的四个部件对应四件事:lint 先行(脏数据不值得跑分);跑分脚本自带阈值退出(run_regression.py 对照 config/gates.yaml 判阻塞线,越线 exit 1——与 6.1 节 Promptfoo --threshold 同一原语);报告 always 上传(红了也要看报告做分流);PR 评论(成绩单出现在开发者视线里,而不是埋在 CI 日志第 800 行)。PR 评论的形态(示意):
📊 Evals 报告(vs 基线 v12) 主集通过率 91.3% (基线 92.0%,−0.7pp ✅ 阻塞线未触发) hard 子集 18/20 通过(持平 ✅) 安全子集 22/22 通过 ✅ 成本/请求 ¥0.021(+8% ⚠️ 观察线:接近 +10% 讨论线) p95 延迟 2.1s(−0.3s ✅)
CI 红 ──▶ 看报告下钻 ├─ 真回归:特定分层 / 特定题型成片挂,失败模式与本次 diff 语义相关 │ └─ 动作:修代码或撤改动。回归集立功,走正常修复流程 ├─ 评测集过期:老题期望答案与本次需求变更冲突(PR 描述里应有对应需求) │ └─ 动作:提重标 PR(3.1"失效重标不删"),owner 审批后与代码 PR 串行合并 └─ 环境抖动:报错是限流/超时而非断言失败,重跑一次结果不同 └─ 动作:重试上限 2 次;连续抖动升级为基建 issue,修基础设施
"红了就重跑到绿"是被明令禁止的:重跑通过只说明第一次红是噪声,但它同时教会所有人"红可以不理"。正确姿势是给评测加确定性(温度 0、固定种子、pass@k 报告第 4.1 节),并在门禁里区分"断言失败"与"环境失败"两类退出码(观点:环境失败的退出码不该占用红色的注意力)。
evals/ 的合并权;职责是审考卷变更(9.1 三纪律)、维护阈值表(7.2/8.2 的口径)、月度看一眼门禁拦截率——拦下过多少真回归是这套体系存在的唯一证据(9.3 节元评测之一);datasets/ → owner 评审(是否重复、元数据是否齐)→ 合并并跑分确认"新考题当前系统确实挂"。四步缺一不可,跳过确认步的坏样本会在下个月变成误报源;💡 门禁文化的一句话:门禁是护栏不是敌人——它替开发者挡下"悄悄改坏"的职业风险。把这句话写进团队文档的开头,比任何工具配置都更能决定这套体系的命运。
门禁跑了几个月后,新的风险开始积累:有人学会了向考卷优化、指标悄悄与业务脱钩、考卷本身在过期。最后一节把镜头转向评测自己——三大反模式与元体检。