一个做评测平台的团队被要求「顺手把交付门禁也做了」,理由很朴素:两边都是数据集、被测对象、跑一遍出结果,为什么不能一套系统?这个直觉有一半是对的——两者确实共用一副骨架,平台层可以复用。但另一半错得很隐蔽:真正决定一个系统是评测还是门禁的部件,在这个三元组里根本没被列出来。它叫 oracle。这篇先把这个被藏起来的部件找出来,再照着完整的元组,把门禁系统每一格能用的开源底座配齐——目标是读完能开工。
上一篇《交付门禁 vs 评测系统》讲的是两者在质量回路上的位置:评测是传感器,门禁是执行器。本篇讲的是两者的内核为什么不同,以及门禁这一侧怎么搭。两篇合起来是一份「为什么分开」加「分开之后门禁怎么造」。
名词速查
| 术语 | 一句话解释 |
|---|---|
| harness | 把「喂输入、跑被测对象、收结果」这套流程自动化起来的框架,pytest、Inspect AI、Playwright Test 都是 |
| oracle(测试预言) | 判断一次输出「对不对」的依据。可以是一个断言、一份参考答案、一个裁判模型、一个人 |
| held-out | 被测对象在构建时没见过的数据;评测数据一旦被训练集或提示词吸收,叫「污染」 |
| flaky | 同一测试在同一代码上时好时坏;在门禁语义下是 bug,在评测语义下是被测对象的固有性质 |
| 世界状态 | 被测系统运行时依赖的一切:数据库、配置、依赖服务、模型版本、时间。门禁测的是「变更」对这些的影响 |
| PROMOTE / HOLD / ROLLBACK | 门禁的三种离散判决:放行、拦下等人、回滚。来自 Automated Self-Testing (2603.15676) |
| 契约测试 | 把服务之间「我调你时你要这么回」写成可执行的例子,双方各自验证;Pact 是代表实现 |
| Wilson 下界 | 通过率的置信区间下限,样本少时比点估计诚实得多;详见评测统计篇 |
一、共用的骨架:三元组为什么两边都成立
任何 harness 拆开都是三样东西:
- 资产:喂给被测对象的输入集合。评测叫数据集,门禁叫测试用例。
- 目标:被测对象。评测是一个模型或一条 Agent 链路,门禁是一个业务系统在某次变更之后的状态。
- Runner:把资产逐条喂给目标、收集输出、汇总报告的执行器。评测是 Inspect AI、promptfoo,门禁是 Playwright、pytest、JUnit。
这不是巧合,也不只是形似。Inspect AI 的文档把一个评测任务定义为 Dataset + Solver + Scorer 三件,pytest 的一次运行是 fixture + 被测函数 + assert——它们是同一个抽象在两个领域的实例化。所以「平台层复用」这个直觉成立:调度、并发、重试策略、报告存储、trace 归档,两边确实能共享一套基础设施。上一篇里 Test Before You Deploy 的「兼容性契约」(拿评测集做回归、不掉分才放行),就是评测在这副骨架上直接长成门禁的活例。
但请注意上面那句话里 Inspect 的第三件叫 Scorer,而 pytest 那边我写的是 assert。三元组里没有它的位置。它被藏起来了。
二、被藏起来的第四个部件:oracle
软件测试领域对这个部件有专门的名字和一篇经典综述:Barr、Harman、McMinn、Shahbaz、Yoo 在 IEEE TSE 2015 发表的《The Oracle Problem in Software Testing: A Survey》把它定义为:给定一个输入,把「期望的正确行为」与「可能错误的行为」区分开的那个难题。综述列出的 oracle 来源依次是规格、模型、契约、蜕变关系,「当这些都不够用时,最终的 oracle 信息来源仍然是人」。
传统测试之所以让人觉得 oracle 不存在,是因为它被写进了 assert x == 42 这一行里——oracle 和 Runner 长在同一处,看起来是一体的。LLM 评测把这个部件重新拆了出来,Inspect 把 Scorer 做成一等公民、DeepEval 把 G-Eval 裁判做成可插拔的指标,都是同一个动作:oracle 从「解决了的问题」变回「未解决的问题」。
一旦把 oracle 单独摆出来,评测和门禁就在这一格上分开了,而且几乎所有下游差异都从这一格长出来:
| 门禁的 oracle | 评测的 oracle | |
|---|---|---|
| 形态 | 规格(spec):期望输出精确已知,assert status == 200 | 参考答案、评分 rubric、裁判模型:本身模糊、本身带误差 |
| 被测对象能不能「见过」它 | 应当见过——测试驱动开发就是照着测试写代码;契约测试的消费者先写期望、提供方照着实现 | 绝不能见过——见过叫污染,分数立即失效 |
| 资产的组织目标 | 穷举式覆盖变更面:每个分支、每条契约都跑到 | 从不可穷举的分布里采样,要的是代表性而非枚举 |
| 重跑的语义 | flaky 是 bug,retry 是坏味道;Playwright 默认 retries: 0,通过重试才过的测试单独标成 flaky | 多次重跑是必需——目标本身是随机函数;Inspect 用 --epochs 加 reducer(mean / pass_at_k / …)把多轮压成一个分 |
| 失败意味着什么 | 变更引入了回归,或规格错了 | 目标能力不足,或 oracle 本身偏了 |
所以「门禁需要测试用例覆盖」这句话没问题,但「覆盖」这个词搬到评测那边意思就变了:测试覆盖率是「diff 的每一支都被执行过」,评测覆盖是 HELM 意义上的「能力格子每一格都有采样」(覆盖地图篇展开过)。同一个词,一个是枚举,一个是抽样。
有一个来自实践的证据把这条分叉钉得很死。Automated Self-Testing (2603.15676) 在 60 个分层抽样的案例上,让 LLM 裁判和它的结构化门禁各判一遍,两者的一致性只有 kappa = 0.13。作者的解释是:门禁抓住的是延迟越界、路由错误这类在回复文本里看不见的结构性失败;裁判抓住的是门禁的结构检查测不到的内容质量问题。这两个 oracle 不是谁更准,而是根本在看不同的东西——这正是「确定性规格」和「采样式裁判」两种 oracle 的分工。把它们混成一个分数,等于把温度计和秤的读数加起来。
三、由此推出门禁的完整元组:不是三个,是六个
把 oracle 补进来之后,门禁还多出两个评测没有的部件。评测的输出是估计量,到分数就结束了;门禁的输出是一个不可逆动作的判决,所以它必须再加一个把分数变成判决的决策器,和一个记录「为什么这么判」的台账——判决可以被质疑,台账是被质疑时的证据。
flowchart LR
A["资产<br>用例 · 契约 · golden 集"] --> R["Runner<br>执行、收集、重试策略"]
T["目标<br>变更后的世界状态<br>(代码+配置+数据+模型版本)"] --> R
R --> O["Oracle<br>确定性规格为主<br>采样式裁判为辅"]
O --> D["决策器<br>阈值 · 组合规则<br>PROMOTE / HOLD / ROLLBACK"]
D --> L["台账<br>证据 · trace · 判决记录"]
D -->|PROMOTE| P["合入 / 发布 / 放权"]
D -->|HOLD| H["等人复核"]
D -->|ROLLBACK| B["回滚到上一稳定版"]
六个元组各自要回答的问题:
- 资产:哪些输入必须每次都跑?它们由谁维护、怎么随业务漂移更新?
- 目标(世界状态):变更前后到底改了什么?依赖的数据库、外部服务、模型版本怎么固定住,让两次运行的差异只来自变更本身?
- Oracle:对错依据是什么?哪些是确定性规格、哪些是裁判判断?两者的结论怎么分开报告?
- Runner:谁来执行?执行本身是否确定性?AI 参与执行时,它的不确定性怎么隔离?
- 决策器:分数怎么变成 PROMOTE / HOLD / ROLLBACK?阈值精度是否匹配 oracle 的方差?判定器自己失败时默认放行还是拦截?
- 台账:每次判决的证据存在哪里?能不能回放?能不能看趋势?
下面逐格配开源底座。选型原则只有一条,来自第二节:AI 可以出现在门禁的执行位置和辅助断言位置,但门禁的主 oracle 必须是确定性规格。违反这条,你造出来的是一个评测系统,不是门禁。
四、逐格配开源底座
先给总表,再讲每一格里的取舍。许可信息核实自各项目 2026-09-03 当日的仓库页或文档;未亲手部署的项目在文末「诚实的提醒」里单列。
| 元组 | 首选底座 | 许可 | 它在门禁里的角色 | 备选 |
|---|---|---|---|---|
| 资产 | Git 仓库内的用例 + Langfuse Datasets | MIT(ee/ 目录除外) | 用例与代码同库同审;LLM 相关 golden 集用 Langfuse 版本化、从生产 trace 反哺 | Opik、Phoenix(产品化篇有对比) |
| 目标 / 世界状态 | Testcontainers + Pact | MIT / MIT | 依赖服务每次现起现销;跨服务边界用契约代替「部署全世界」 | Docker Compose 手写、WireMock |
| Oracle(确定性) | Playwright expect / pytest assert / Conftest + OPA | Apache-2.0 | 功能断言、契约验证、配置策略;失败即 exit 非零 | Rego 之外:CUE、JSON Schema |
| Oracle(采样式,辅助) | promptfoo / DeepEval / Midscene aiAssert | MIT / Apache-2.0 / MIT | 被测系统含 LLM 时的内容质量检查;只能出 HOLD,不能单独出 PROMOTE | Inspect AI(用于回归型评测时) |
| Runner(Web) | Playwright | Apache-2.0 | 确定性执行主干,进程级隔离、trace 录制 | Cypress、Puppeteer |
| Runner 之上的 AI 定位层 | Midscene.js / Stagehand | MIT / MIT | 选择器脆弱或不存在(canvas、跨域 iframe、原生 App)时的元素定位;不替代 Runner | 直接用 Playwright getByRole |
| 决策器(合入闸) | CI 的 exit code 组合 + Conftest | — | 多个 oracle 的结果按声明的规则合成一个判决 | 自写 20 行脚本 |
| 决策器(发布闸) | Argo Rollouts Analysis | Apache-2.0 | 灰度期间按指标自动 abort/回滚;Inconclusive 自动 pause 等人 | Flagger |
| 台账 | Playwright Trace + Allure Report + OpenTelemetry(GenAI 语义约定) | Apache-2.0 | 每次判决的回放证据、历史趋势、flaky 追踪;LLM 调用进统一 trace | Langfuse 作为 LLM trace 后端 |
4.1 资产:用例进 Git,golden 集进可版本化的数据集
门禁用例的第一原则是和被改的代码同一个仓库、同一个 PR 审——这是「被测对象应当见过 oracle」的直接推论:改了行为就必须同时改契约,reviewer 在同一个 diff 里看到两者。
被测系统含 LLM 时,多出一类资产:golden 集(输入 + 期望输出)。它不适合塞进 Git,因为它需要从生产 trace 持续反哺。Langfuse 的数据集把每个 item 定义为 input + 可选 expected_output + metadata,并且「每一次 add / update / delete / archive 都产生一个新的数据集版本」,item 可以通过 source_trace_id 挂回它来自的那条生产 trace。这两个特性刚好对应上一篇讲的「golden set 是活资产」:门禁跑的是钉住版本的数据集,运营侧另开一条线往里加新翻车案例。
4.2 目标 / 世界状态:让两次运行的差异只来自变更
门禁测的是「变更对世界状态的影响」,前提是除了变更之外的一切都被固定住。两个工具各管一半:
- Testcontainers 管进程内依赖:数据库、消息队列在测试开始前用 Docker 现起,测完由 Ryuk 边车按标签清掉——文档强调「即使测试进程被 SIGKILL 异常退出也能可靠清理」,并发流水线之间「不会有测试数据污染」。这解决的是「上一次运行留下的脏状态让这次结果不可解释」。
- Pact 管服务边界:消费者在自己的测试里写「我会这样调你、你应当这样回」,生成契约;提供方拉取契约回放验证。它的口号是让你不用「先部署全世界」就能确认两边合得上。契约就是跨服务的确定性 oracle,而 Pact Broker 的
can-i-deploy直接把它变成门禁:命令按 exit code 回答「这个版本能不能进这个环境」——0 是能,1 是不能——部署后再用record-deployment告诉 Broker 环境里现在跑的是哪个版本。
被测系统里有 LLM 时,世界状态多了一个维度:模型版本。供应商会在版本号不变的情况下更新权重(上一篇里 Test Before You Deploy 论文的出发点)。门禁能做的是把模型 ID 和快照日期写进配置并纳入 diff——它变了就是一次「变更」,触发门禁,而不是悄悄漂过去。
4.3 Oracle:确定性为主,采样式为辅,两者分开报告
确定性 oracle 三种来源:功能断言(Playwright 的 expect、pytest 的 assert)、契约(Pact)、策略(Conftest 用 OPA 的 Rego 语言对 YAML / JSON / HCL / Dockerfile 等结构化配置写 deny / warn 规则,「默认只在策略失败时返回 exit code 1」,加 --fail-on-warn 后变成 0 / 1 / 2 三级)。共同点是期望值精确、结果二元、可重放。
采样式 oracle 是被测系统含 LLM 时不得不引入的。promptfoo 和 DeepEval 都把「LLM 裁判打分 + 阈值」包装成 pytest 风格的断言:DeepEval 的 assert_test(test_case, [metric]) 里「所有指标分数在 0–1 之间,threshold=0.5 最终决定测试是否通过」;promptfoo 有 --fail-on-error,也可以从 results.json 里读 stats.successes / stats.failures 算通过率再比阈值。
这里是本文最重要的一条工程规矩,是我的提炼而不是任何一份文档的原话:
采样式 oracle 在门禁里只有 HOLD 权,没有 PROMOTE 权。 它的失败应当拦下等人复核;它的通过不能单独放行,必须叠加确定性 oracle 全绿。
理由就是第二节那个 kappa = 0.13:裁判看不见结构性失败,结构检查看不见内容问题。让裁判独立签发 PROMOTE,等于让门禁只剩它看得见的那一半。反过来也成立:确定性 oracle 全绿而裁判亮红,说明出现了 assert 写不出来的问题,值得一个人看一眼。
4.4 Runner:Playwright 是主干,Midscene 是定位层,两者不是替代关系
这一格最容易选错,因为 Midscene 的宣传语是「the GUI Agent for E2E Testing」,听起来像是 Playwright 的下一代。看它的实际接法就清楚了:文档写的是「把 Midscene 加进你的 Playwright 或 Puppeteer 测试」——它挂在 Runner 之上,不是 Runner 本身。Stagehand 的自我定位更直白:「Playwright 是为测试造的,Stagehand 是为 agent 造的」,并且它的示例代码把 AI 的 observe 找到的选择器交给普通的 page.locator(...).click() 去执行,注释写着「用 locator 做确定性的 Playwright 风格动作」。
所以 Runner 这一格的分工是:
Playwright 做执行主干,因为门禁的 Runner 需要三样它原生就有的东西:进程级隔离(每个测试在独立 worker 里跑,失败的 worker 连浏览器一起丢掉,「保证失败的测试不会影响健康的测试」)、明确的 flaky 语义(默认不重试,重试后才过的单独标记)、以及可回放的 trace(trace: 'on-first-retry' 在第一次重试时录下每个动作的 DOM 快照、网络请求、控制台日志)。
Midscene 做两件 Playwright 做不好的事,都在执行位置、不在判决位置:
- 定位没有稳定选择器的元素:canvas 内容、跨域 iframe、原生 App——这些地方 DOM 拿不到,
getByRole无从下手。Midscene 1.0 砍掉 DOM 兜底走纯视觉,正是为了这些场景。用它的 Instant Actions(aiTap等)而不是全流程aiAction,让 AI 只负责「这颗按钮在哪」,不负责「接下来该做什么」。 - 在选择器脆弱的页面上降低维护成本:改版后一批
#login-btn失效,视觉定位不受影响。
但要认清 Midscene 带进门禁的不确定性,以及它的缓存机制能压掉多少。Midscene 缓存两种东西——规划步骤和元素定位的 XPath(后者仅 Web)——命中时不调模型;文档明确说「aiBoolean、aiQuery、aiAssert 这些查询类结果永远不会被缓存」,并且警告「缓存是加速手段,不是保证脚本长期稳定的工具」,缓存失效时「系统自动回退到 AI 模型重新分析」。翻译成门禁语言:定位步骤在缓存命中时是确定性的,未命中时是随机的;断言步骤永远是随机的。
由此我的建议(观点):
- 门禁里 Midscene 的定位调用全部开缓存(
cache: { id }),缓存文件进 Git,改版导致的缓存失效在 PR 里可见;打开DEBUG=midscene:cache:*把未命中记进台账,未命中率突然上升本身就是一个信号。 aiAssert归到 4.3 的「采样式 oracle」那一栏,只有 HOLD 权。凡是能用expect(page.getByText(...))写出来的断言,不用aiAssert。- Stagehand 的
observe → locator模式和上面同构:AI 找选择器,Playwright 执行;如果团队已经在 Playwright 上,两者选一个即可,差别主要在模型支持(Midscene 对国产 VLM 的适配更全)和平台覆盖(Midscene 有 Android / iOS / 桌面)。
4.5 决策器:合入闸靠 exit code 合成,发布闸靠 Argo Rollouts
合入闸的决策器可以很薄。每个 oracle 已经用 exit code 说了话——Playwright 失败非零、Conftest 失败 1、Pact can-i-deploy 不能部署 1、promptfoo --fail-on-error 非零——决策器只需要按声明的规则把它们合成一个判决。伪代码(根据 Automated Self-Testing 的 PROMOTE / HOLD / ROLLBACK 协议简化,具体阈值是示意):
# 伪代码:合入闸决策器主干。省略:超时处理、override 权限校验
def decide(results, contract):
hard = [r for r in results if r.oracle_kind == "deterministic"]
soft = [r for r in results if r.oracle_kind == "sampled"]
if any(r.exit_code != 0 for r in hard):
return ROLLBACK if contract.on_hard_fail == "rollback" else HOLD
for r in soft: # 采样式 oracle 只有 HOLD 权
lower = wilson_lower(r.passed, r.total)
if lower < contract.threshold[r.name]:
return HOLD # 拦下等人,不自动回滚
if any(r.status == "inconclusive" for r in results):
return HOLD # 判定器自身失败:合入闸 fail-closed 到 HOLD
return PROMOTE
注意第三个分支:判定器自己超时或崩了怎么办。Gate 决策地图篇的结论是看下游是否可逆——合入闸挡住的是开发进度,fail 到 HOLD(而不是默认放行)代价可承受;行动闸挡住的是转账,必须 fail-closed。
发布闸的决策器不该自写,Argo Rollouts 的 Analysis 已经把它做成了 CRD:AnalysisTemplate 里声明指标来源(Prometheus、Web、Job 等)和 successCondition: result[0] >= 0.95 这类条件;failureLimit 默认 0,即一次失败就算失败;背景分析失败时「Rollout 中止,金丝雀权重归零」并标记 Degraded;结果 Inconclusive 时「Rollout 在当前步骤暂停」等人处理。这三种结局恰好就是 PROMOTE / ROLLBACK / HOLD。它的 Job provider 可以跑任意容器,所以 4.3 里的 promptfoo 或 Inspect 回归也能挂进去当灰度期指标。
4.6 台账:三层证据,一条 trace
判决可以被推翻,台账不能没有。三层:
- 单次运行的回放:Playwright trace(
npx playwright show-trace trace.zip,文档说明「完全在浏览器里加载,不向外传输数据」)。Midscene 自带的可视化报告也属于这一层。 - 跨运行的趋势:Allure Report 是「框架无关的开源测试结果可视化工具」,功能列表里有「History and retries」「Test stability analysis」和「Quality Gate」——flaky 率随时间的变化就在这里看。
- LLM 调用的 trace:被测系统里每一次模型调用(包括门禁自己发起的裁判调用)应当以统一格式进 trace 系统。OpenTelemetry 已经把 GenAI 的 span / metric / event 语义约定拆成独立仓库 semantic-conventions-genai(Apache-2.0,覆盖 MCP 和主流供应商);仓库页面未标注稳定性等级、Schema URL 仍是 TODO,属于仍在演进的规范,选型时以当时的文档为准。落地后端可以是 Langfuse,它已经是 4.1 里资产层的底座,一套系统两用。
五、当被测系统含 LLM 时:门禁如何借用评测的 oracle 而不被它的方差拖垮
4.3 说采样式 oracle 只有 HOLD 权,但即便只是 HOLD,阈值怎么定也是问题。评测那边的通过率是采样估计,直接拿点估计比阈值会抖。上一篇的病理 C 讲了原理,这里给门禁里具体的数:
| 用例数 n | 通过数 | 通过率点估计 | Wilson 95% 下界 |
|---|---|---|---|
| 20 | 19 | 0.950 | 0.764 |
| 20 | 20 | 1.000 | 0.839 |
| 100 | 95 | 0.950 | 0.888 |
| 100 | 100 | 1.000 | 0.963 |
| 200 | 190 | 0.950 | 0.910 |
(用标准 Wilson 区间公式、z = 1.96 手算,脚本验算过。)
读法:如果门禁契约写「LLM 内容质量通过率 ≥ 0.90」,而 golden 集只有 20 条,那么即使 20 条全过,下界也只有 0.839,永远过不了这道门——这不是被测系统的问题,是 oracle 的分辩率不够。要让「19/20 过」有资格触发 PROMOTE 的那一半,golden 集至少要到 200 条量级(190/200 的下界才刚过 0.90)。所以门禁的决策器读的必须是下界而不是点估计(上面伪代码里的 wilson_lower),而阈值和 golden 集规模是要一起定的,不能各定各的。
反过来,这张表也给了一条排期依据:一个新业务线的 LLM 门禁,在 golden 集攒到几十条之前,采样式 oracle 只能进台账、不能进判决——先跑起来积累分布,不要急着上阈值。
六、施工顺序:三阶段,每阶段有可验收的产出
阶段一(一到两周):只有确定性 oracle 的门禁。 Playwright 覆盖关键路径,Testcontainers 固定依赖,契约用 Pact 或至少用 JSON Schema 锁住接口。决策器就是 CI 的 exit code。验收标准:任何一条关键路径断了,PR 合不进去。这一阶段不碰 AI——先让门禁有牙。
阶段二(两到四周):加 AI 定位层和台账。 选择器最脆弱的那几个页面换成 Midscene Instant Actions 加缓存,缓存文件进 Git;trace 开 on-first-retry;Allure 接上看趋势。验收标准:一次改版后,需要手改的用例数比阶段一下降,且缓存未命中在 PR 里可见。
阶段三(持续):加采样式 oracle 和发布闸。 golden 集在 Langfuse 里从生产 trace 反哺积累;到规模后 promptfoo / DeepEval 接进合入闸,只给 HOLD 权,阈值按第五节的下界表定;灰度发布交给 Argo Rollouts Analysis,把同一套回归挂成 Job 指标。验收标准:一次模型版本切换(供应商静默更新也算)能被门禁拦下,且拦下的原因在台账里能回放。
三个阶段的顺序不能倒。先上采样式 oracle 再补确定性 oracle,会造出上一篇的病理 B——门禁里全是裁判打的分,结构性失败一个也拦不住。
七、带得走的一张表
| 问题 | 评测系统的答案 | 交付门禁的答案 |
|---|---|---|
| 三元组(资产 / 目标 / Runner)能不能共用 | 能,平台层复用 | 能,平台层复用 |
| oracle 是什么 | 采样式:参考答案、rubric、裁判 | 确定性:断言、契约、策略;采样式仅辅助 |
| 被测对象能不能见过 oracle | 不能(污染) | 应当(照着它构建) |
| 资产的目标 | 分布上的代表性 | 变更面上的覆盖 |
| 重跑 | 必需,用 reducer 聚合 | flaky 即 bug,重试单独标记 |
| 输出 | 估计量(带误差条) | 判决(PROMOTE / HOLD / ROLLBACK) |
| 多出来的部件 | — | 决策器、台账 |
| AI 在里面的位置 | 目标本身,以及裁判 | 执行层的定位器,以及只有 HOLD 权的辅助断言 |
诚实的提醒
本文所有工具的功能描述和许可信息核实自 2026-09-03 当日的官方文档或仓库页,正文带链接。亲手跑过的:Playwright(多年)、Inspect AI(教程篇)、Midscene 的基本流程(拆解篇)。未亲手部署、仅核实文档的:Pact Broker 的 can-i-deploy、Argo Rollouts Analysis、Conftest、Testcontainers 的 Ryuk 行为、DeepEval、Allure 3。Automated Self-Testing 论文的 kappa = 0.13 是论文自报数字,未复现。第五节的 Wilson 下界是我用公式手算并脚本验算的,其余数字均为核实来源。
「采样式 oracle 只有 HOLD 权」是我的工程提炼,不是任何一份文档的规定;它的失效边界我能想到一个:如果你的确定性 oracle 覆盖面本身很薄(阶段一没做实),那么裁判反而是唯一在看的人,这时候剥夺它的 PROMOTE 权等于门禁形同虚设——解法是补阶段一,不是给裁判放权。
最低成本的亲手验证实验(一小时内):找出你现有 CI 里所有会让构建变红的检查,逐条问两个问题——(1)它的 oracle 是确定性规格还是某种打分?(2)它失败时是拦下等人,还是直接阻止合入?把答案填成一张两列表。如果表里有任何一行是「打分 + 直接阻止合入」,你的门禁里有一个采样式 oracle 在越权签发判决,第五节的下界表能告诉你它抖的幅度有多大。
参考来源
论文
- Barr, Harman, McMinn, Shahbaz, Yoo. The Oracle Problem in Software Testing: A Survey. IEEE TSE 41(5), 2015.(开放获取版)
- Maiorano. Automated Self-Testing as a Quality Gate: Evidence-Driven Release Management for LLM Applications. arXiv 2603.15676, 2026.
工程实践与文档
- Inspect AI · Options(epochs / reducer)
- Playwright Test Retries · Trace Viewer
- Midscene.js · Caching
- Stagehand
- Testcontainers Getting Started
- Pact 简介 · can-i-deploy
- Conftest · Options(exit codes)
- Argo Rollouts Analysis
- promptfoo CI/CD
- DeepEval
- Langfuse Datasets · Langfuse 仓库
- Allure Report
- OpenTelemetry GenAI Semantic Conventions
本站相关