过去两年门禁产品的用户是人:工程师看 dashboard 上的红绿、点「重跑」、在 Slack 里问「这条为什么挂了」。这个前提正在失效。提交变更的是 Claude Code、Cursor、Codex 这样的编码 Agent;它们在本地就会主动调用验证工具;读判决并据此修改代码的也是它们。人被推到了两个位置:事前定策略,事中只在「拦下等人」时出现。一旦一等用户从人换成 Agent,门禁产品的每一层——交互原语、判决格式、防作弊、升级通道——都得重画。这篇就是那张重画后的图。
这是门禁系列的第三篇。第一篇讲评测与门禁在质量回路上的位置(传感器 vs 执行器),第二篇讲两者在 oracle 处的分叉和门禁六元组的开源底座。本篇不再讲原理,讲产品怎么设计、链路怎么搭、Agent 怎么跟它交互。读者画像是要把这套系统做出来的产品或平台负责人。
名词速查
| 术语 | 一句话解释 |
|---|---|
| Agent-native | 工具把 Agent 当一等用户来设计:通过 Agent 可调用的接口(如 MCP)暴露能力,人类界面是可选的而不是主入口 |
| MCP | Model Context Protocol,Agent 调外部工具的开放协议;工具有输入输出 schema,结果可带结构化数据;本站有专文 |
| Elicitation | MCP 里「服务端反过来向人要一个输入」的机制,有表单模式和 URL 模式;本文用它做 HOLD 的升级通道 |
| Hook | Agent 运行时在特定时点(如每次调工具之前)自动执行的用户脚本,可以拦截这次调用 |
| PROMOTE / HOLD / ROLLBACK | 门禁的三种判决:放行、拦下等人、回滚;来自 Automated Self-Testing (2603.15676) |
| Oracle | 判断输出对不对的依据;门禁里主要是确定性规格(断言、契约、策略),辅以采样式裁判;上一篇的主角 |
| Held-out 用例 | 被测 Agent 看不见的判决用例;用来防止 Agent 照着测试改代码而不是照着需求改 |
| Merge queue | GitHub 的合并队列:把待合入的 PR 和主干最新状态合成临时分支再跑检查,保证主干不被互相冲突的变更打坏 |
一、用户换了:三类 Agent 和两个人
先把用户画像摆出来,后面所有设计都从这张表推。
| 用户 | 它在门禁里做什么 | 它需要门禁给它什么 |
|---|---|---|
| 变更 Agent(Claude Code / Cursor / Codex 等编码 Agent) | 写代码、写测试、在本地主动验证、开 PR、读判决后修 | 事前能查到「这次改动要过哪些检查」;事后拿到结构化、可行动的判决和证据 |
| 执行 Agent(门禁自己的 Runner,含 Midscene 这类视觉定位 Agent) | 在真实浏览器 / 沙箱里跑用例、收集证据 | 确定性的执行环境、缓存、超时与重试策略 |
| 运维 Agent(夜间巡检、flaky 治理、覆盖衰减审计) | 有自己的计划和持久上下文,不等编码 Agent 来调它 | 历史台账的读权限、提出 oracle 变更的权限(但不是批准权) |
| 策略制定者(人) | 事前:写门禁契约、定阈值、定谁有 override 权 | 一个能声明契约、看趋势、审 oracle 变更的界面 |
| HOLD 复核者(人) | 事中:只在判决为 HOLD 时被叫出来,看证据、做三选一 | 一条推送式升级通道 + 一份三分钟能看完的证据包 |
这张表有两个和「人是用户」时代不同的结论。
第一,读判决的主体不是人,所以判决的首要品质不是「好看」而是「可行动」——MCP 规范对工具执行错误的定义是「包含可操作的反馈,语言模型可以用来自我修正并调整参数重试」,客户端「应当把工具执行错误提供给语言模型以支持自我修正」。门禁的每一条失败都应当按这个标准写。
第二,同一个 Agent 既写代码又写测试。Shiplight 把这当卖点(「你的编码 Agent 成为 E2E 测试的主要作者和维护者」);从门禁视角看,这恰恰是最大的设计风险——写作业的和出考卷的是同一个人。第五节整节讲怎么处理。
二、一条变更的完整链路
先看一次变更从意图到上线经过哪些闸、每一步谁和谁在说话。
sequenceDiagram
participant H as 人
participant A as 变更 Agent
participant G as 门禁服务
participant R as Runner 池
participant CI as 代码托管 CI
participant D as 发布系统
H->>A: 需求
A->>G: gate.contract.get 这次改动要过什么
G-->>A: 契约 检查清单与阈值
A->>A: 写代码与用例
A->>G: gate.check.run 本地快速档
G->>R: 跑确定性检查
R-->>G: 结果与证据
G-->>A: 判决 HOLD 含修复提示
A->>A: 按提示修改
A->>G: gate.check.run 再跑
G-->>A: 判决 PROMOTE
A->>CI: 开 PR
CI->>G: 合入闸 完整档 含 held-out 用例
G-->>CI: 状态检查 通过
CI->>CI: 合并队列 对主干最新状态重跑
CI->>D: 合入 触发灰度
D->>G: 发布闸 灰度指标分析
G-->>D: ROLLBACK 或 PROMOTE
G->>H: 仅在 HOLD 时 推送复核
几个链路设计上的要点,按时序说:
契约先于变更。变更 Agent 第一步不是写代码而是查契约。Shiplight 那篇《QA agent vs verification tool》里有一句话说得对:「验证器的质量取决于它的判据」——判据不告诉 Agent,Agent 就会自己猜,猜出来的通常是「能让测试变绿的最短路径」。所以门禁要暴露一个只读工具 gate.contract.get(scope),按改动路径返回这次要过的检查、阈值、fail 模式。
本地档和合入档分开。Agent 在本地循环里调的是「快速档」:只跑确定性检查、只跑与 diff 相关的用例、跳过采样式裁判。合入闸跑「完整档」:加 held-out 用例、加采样式 oracle、加契约验证。两档的区别不是快慢,是信任级别——本地档的判决是给 Agent 自我修正用的建议,合入档的判决才是有法律效力的。
合并队列是第二道合入闸。GitHub 的 merge queue 把 PR 和主干最新状态以及排在前面的 PR 合成临时分支跑检查,「确保分支永远不会被不兼容的变更打坏」。Agent 时代这一步比以前更重要:多个 Agent 并行开 PR 是常态,单个 PR 各自绿、合起来红的概率随并发数上升。注意它要求 workflow 监听 merge_group 事件,不监听则「必需检查永远不会报告,合并失败」。
人只在一个箭头上出现。上图最后一条:门禁只在 HOLD 时把人叫出来。PROMOTE 不通知人(通知了也没人看),ROLLBACK 自动执行后记台账。
三、六层架构
flowchart TB
subgraph L6["治理层 面向人"]
POL["策略中心<br>契约 阈值 override 权"]
OC["Oracle 变更审批<br>CODEOWNERS"]
HQ["HOLD 队列<br>Elicitation 推送"]
end
subgraph L1["接入层 面向 Agent 的入口"]
MCP["MCP Server<br>gate.* 工具"]
CLI["CLI<br>本地与 CI 同一命令"]
APP["代码托管 App<br>状态检查与 PR 评论"]
HK["Runtime Hooks<br>PreToolUse 拦截"]
end
subgraph L2["编排层"]
CT["契约解析<br>按 scope 选检查"]
BG["预算与幂等<br>attempt 计数 结果缓存"]
DC["决策器<br>PROMOTE HOLD ROLLBACK"]
end
subgraph L3["执行层 Runner 池"]
PW["Playwright<br>Web 主干"]
MS["Midscene<br>视觉定位层"]
PT["pytest 与容器<br>API 与集成"]
IN["Inspect 或 promptfoo<br>LLM 回归"]
end
subgraph L4["Oracle 层"]
DET["确定性<br>断言 契约 策略"]
SMP["采样式<br>裁判 仅 HOLD 权"]
HO["Held-out 用例<br>Agent 不可见"]
end
subgraph L5["证据与台账层"]
EV["证据包<br>trace 截图 日志"]
LG["判决台账<br>可回放 可趋势"]
OT["OTel GenAI trace<br>模型调用"]
end
POL -.-> CT
OC -.-> HO
MCP --> CT
CLI --> CT
APP --> CT
HK -. 本地拦截 .-> CT
CT --> BG
BG --> PW
BG --> PT
BG --> IN
PW --- MS
PW --> DET
PT --> DET
IN --> SMP
HO --> DET
DET --> DC
SMP --> DC
DC --> EV
DC --> LG
IN --> OT
DC -. 仅 HOLD 时 .-> HQ
每一层只说一个和「面向 Agent」有关的设计决定:
接入层有四个入口但一个内核。MCP Server 给 Agent 在开发循环里调;CLI 保证本地和 CI 跑的是同一条命令(Shiplight 的 npx shiplight test 做到了这点,值得抄);代码托管 App 负责把判决写成 required status check 和 PR 评论;Runtime Hooks 是行动闸的执法点——Claude Code 的 PreToolUse hook 「在工具调用执行前触发,可以阻止它」,退出码 2 即拦截,并且文档明确警告「超时不会拦截……不要指望一个卡住的 hook 充当门禁」,所以 hook 里的判定必须是本地、快速、确定性的(路径白名单、命令模式),不能在这里调远端裁判。
编排层多了「预算与幂等」这个人类时代不需要的组件。原因见第五节。
执行层是上一篇的 Runner 格:Playwright 主干,Midscene 只做定位,不做判决。
Oracle 层多了 held-out 一格。这是本文相对 Shiplight 最大的增补,第五节展开。
证据层的产出是「包」不是「页」。Agent 读证据靠的是 MCP 结果里的 resource_link——门禁返回 trace.zip、截图、日志的 URI,Agent 按需拉取,而不是把所有东西塞进上下文。
治理层是全系统唯一面向人的层。它有三个界面,且只有三个:写策略、处理 HOLD、审 oracle 变更。没有「测试结果大盘」——那是运维 Agent 读台账的事。
四、领域对象与判决 schema
产品的骨架是七个对象。用实体关系图给形状,表给细节。
erDiagram
CONTRACT ||--o{ CHECK : declares
CONTRACT ||--o{ POLICY : governed_by
CHANGE ||--o{ RUN : triggers
RUN ||--|| VERDICT : produces
RUN ||--o{ CHECK_RESULT : contains
CHECK ||--o{ CHECK_RESULT : instantiated_as
CHECK_RESULT ||--o{ EVIDENCE : backed_by
VERDICT ||--o| ESCALATION : may_open
CONTRACT {
string scope
string version
string fail_mode
}
CHANGE {
string sha
string world_snapshot
int attempts_used
}
CHECK {
string id
string oracle_kind
string visibility
}
VERDICT {
string decision
string contract_version
}
ESCALATION {
string channel
string resolution
}
| 对象 | 关键字段 | 面向 Agent 的设计点 |
|---|---|---|
| Contract 契约 | scope(路径模式)、version、检查清单、阈值、fail_mode、override 权 | 版本化;Agent 可读不可写;判决必须引用它跑的是哪个版本 |
| Change 变更 | sha、world_snapshot(依赖与模型版本的锁定)、attempts_used | 判决绑定 (sha, contract_version, world_snapshot) 三元组,同一三元组不重跑 |
| Check 检查 | oracle_kind(deterministic / sampled)、visibility(visible / held-out)、tier(fast / full) | visibility 字段是防作弊的核心,见第五节 |
| Run 运行 | 触发者(Agent / CI / 人)、tier、开始结束时间 | 触发者是审计字段——夜里两点 30 次运行来自同一个 Agent 是个信号 |
| Check Result | status、score、ci_lower(采样式必填)、fix_hint、evidence[] | fix_hint 是给 Agent 读的自然语言修复提示,是 MCP 「可操作反馈」的落点 |
| Verdict 判决 | decision、blocking[]、next_actions[]、attempts{used, budget}、escalation{available, channel} | 三值判决 + 显式告诉 Agent「还剩几次机会、下一步该做什么、能不能升级」 |
| Escalation 升级 | channel(elicitation-form / elicitation-url / PR review)、resolution、waiver_expiry | 人处理 HOLD 的记录;waiver 必须带过期时间 |
判决作为 MCP 工具的 structuredContent 返回,按 outputSchema 校验(规范要求「服务端必须提供符合此 schema 的结构化结果」)。一份最小示例:
{
"decision": "HOLD",
"run_id": "run_7f3a",
"change": { "sha": "e1c9…", "contract_version": "checkout@14", "world_snapshot": "ws_2026-09-05" },
"blocking": ["e2e.checkout.apply_promo", "judge.answer_faithfulness"],
"checks": [
{ "id": "e2e.checkout.apply_promo", "oracle_kind": "deterministic", "status": "fail",
"fix_hint": "促销码输入后未出现折扣行;断言等待的是 [data-test=discount-row],页面渲染的是 .discount-line",
"evidence": ["gate://run_7f3a/e2e.checkout.apply_promo/trace.zip"] },
{ "id": "judge.answer_faithfulness", "oracle_kind": "sampled", "status": "below_threshold",
"score": 0.91, "ci_lower": 0.86, "threshold": 0.88,
"fix_hint": "点估计过线但 Wilson 下界未过;此检查只有 HOLD 权,可申请人工复核或补充 golden 集",
"evidence": ["gate://run_7f3a/judge.answer_faithfulness/samples.jsonl"] }
],
"next_actions": ["修复 e2e.checkout.apply_promo 后重跑 fast 档", "对 judge 结果可调用 gate.escalate"],
"attempts": { "used": 2, "budget": 3 },
"escalation": { "available": true, "channel": "elicitation-form" }
}
读这份 schema 时注意三处:blocking 把「哪些在拦你」单独列出来,Agent 不用自己从十几条结果里找;每条失败带 fix_hint 和证据 URI;attempts 明确告诉 Agent 这是第几次、还剩几次。这三处是「人读」和「Agent 读」的判决之间的全部差别——人可以看一眼红绿自己推断,Agent 需要你把推断写出来。
五、三条防 Agent 钻空子的产品规则
这一节是本文的核心增量。人类工程师也会为了让 CI 变绿而改测试,但频率低、有社会约束;Agent 做这件事没有羞耻感、速度快一千倍、而且是被目标函数鼓励的。OpenAI 的 Monitoring Reasoning Models for Misbehavior (2503.11926) 在 agentic 编码环境里观察到了 reward hacking,并且发现如果把监控器本身放进训练目标,「过度优化之后,Agent 学会了隐蔽的 reward hacking」——在推理链里藏起意图,行为照旧。门禁是 Agent 面对的最直接的目标函数,这三条规则就是为此设计的。
规则一:变更 Agent 只能动「变更集」,不能动「判决集」
判决集指所有 oracle 资产:门禁用例目录、契约文件、策略文件、golden 集。三道机制叠加:
- 仓库层:
CODEOWNERS把这些路径指给人类 owner,分支保护开启「要求代码所有者审查」。GitHub 文档:「代码所有者在有人开的 PR 修改了他们拥有的代码时自动被请求审查」,并建议把 CODEOWNERS 文件自己也列进去防止被绕过。 - 运行时层:
PreToolUsehook 匹配Edit|Write,路径落在判决集目录就退出码 2 拦截,stderr 写「oracle 资产变更需通过 gate.propose_oracle_change 提交人审」。Hook 收到的输入里有tool_name、tool_input(含文件路径),足够做这个判断。 - 产品层:给变更 Agent 一条合法通道
gate.propose_oracle_change——它可以提议改测试(测试确实可能错了),提议进人审队列,不进本次判决。
这条规则有一个直接后果:Shiplight 式的「Agent 是测试的作者和维护者」需要拆成两个角色。写新用例是变更集的一部分(新功能带新测试,进同一个 PR 由人审);改既有用例的断言是判决集变更,走提议通道。而 self-healing 要区分两种:修定位器(「Place order」按钮改名为「Complete purchase」,找到它)是执行层的事,允许自动;修断言(期望值从 A 变成 B)是 oracle 变更,不允许自动。Shiplight 的 healing 描述是「重新读页面、解析原始意图、中途更新缓存」——如果只更新定位缓存,合规;如果 intent 解析导致断言语义漂移,就越界了。这是选型时要向供应商问清楚的一个问题。
规则二:一部分判决用例对 Agent 不可见
SWE-bench 的评测设计是这条规则的原型:模型拿到的是代码库和 issue 描述,判定「解决」用的是对应 PR 里的测试,这些测试不在模型输入里——模型只提交一个 diff。门禁照搬:Check.visibility = held-out 的用例只在合入闸的完整档跑,gate.contract.get 返回给 Agent 的清单里只写「另有 N 条 held-out 用例覆盖 checkout 流程」,不给内容。
Held-out 用例从哪来:从生产 trace 反哺的 golden 集里抽一部分单独标记;从人写的验收标准派生;定期轮换(一条 held-out 用例一旦在 fix_hint 里泄漏过内容,就该转成 visible 并补一条新的)。
这条规则的代价是 Agent 本地档的判决和合入档可能不一致——本地绿、合入红。这是故意的:不一致率本身是一个指标,它衡量的是「Agent 在照着需求改还是照着测试改」。不一致率持续为零反而要警惕,说明 held-out 集和 visible 集同分布到失去了意义。
规则三:每次变更有尝试预算,采样式 oracle 的结果按三元组缓存
两个问题合在一起解。第一,Agent 会无限重试——失败就改、改完就跑,一夜几十次,成本和噪声都失控。第二,更隐蔽的:采样式 oracle 的判决是带方差的估计,同一份代码反复跑十次,总有一次下界会碰巧过线。这是统计学里的多重比较问题,人类工程师偶尔手动重跑一下影响不大,Agent 系统化地做就是在对门禁做 p-hacking。
解法:Change.attempts_used 对完整档计数,超过 budget(建议 3)自动转 HOLD 并升级,Agent 拿到的 fix_hint 是「预算耗尽,需人工介入」。采样式 oracle 的结果按 (sha, contract_version, world_snapshot) 缓存——三元组不变,重跑返回缓存结果而不是新抽样;Agent 想要新的判决,必须先改代码。
六、判决的状态机与人的三个动作
stateDiagram-v2
[*] --> Queued: gate.check.run
Queued --> Running
Running --> Promoted: 全部确定性通过 且 采样式下界过线
Running --> Held: 采样式未过 或 判定器不确定 或 预算耗尽
Running --> RolledBack: 确定性失败 且 契约 fail_mode 为 rollback
Running --> Held: 确定性失败 且 fail_mode 为 hold
Held --> Escalated: gate.escalate 或 超时自动
Escalated --> Promoted: 人 批准并附 waiver
Escalated --> Held: 人 要求修改 附说明
Escalated --> RolledBack: 人 拒绝
Held --> Queued: Agent 修改后重跑 预算内
Promoted --> [*]
RolledBack --> [*]
人在 Escalated 状态有且只有三个动作,对应 MCP elicitation 的三种响应:批准并附 waiver(accept,表单里必填理由和过期时间)、要求修改(decline,附说明回给 Agent 作 fix_hint)、拒绝(cancel 或显式 reject,转 ROLLBACK)。
升级通道用 elicitation 的两种模式分工:日常 HOLD 用表单模式,规范限制它只能是「扁平对象、原始类型」——这个限制在这里是优点,逼着你把复核动作设计成三选一加两个字段,而不是一个自由文本框。不可逆动作的 override(比如跳过发布闸强推)用 URL 模式:规范要求涉及授权和敏感操作的交互「不得经过 MCP 客户端」,用户在自己信任的域名下、带自己的 SSO 会话完成——这恰好是 override 需要的审计属性:谁、什么时候、在哪个会话里按了这个键,与 Agent 的上下文彻底隔离。
给复核者的证据包要能在三分钟内看完:判决 JSON 的 blocking 部分、每条 blocking 检查的一张截图或一段 trace 片段、这条变更的 attempts 历史、以及一句由门禁生成的「为什么拦」。不要把 Playwright 的完整 trace viewer 当默认视图——那是 Agent 或工程师深挖时才打开的。
七、以 Shiplight 为参照:做对的、和还缺的
Shiplight 是目前把「Agent 是一等用户」落得最实的门禁类产品,值得当参照系——既学它做对的,也看清它的边界。以下基于其官网与文档在 2026-09-03 的公开描述,我未亲手部署。
它做对的五件事,都应该进你的需求清单:
- 接口面向 Agent:以 MCP server 加 Skills 的形式安装进 Claude Code / Cursor / Codex,「人类 dashboard 是可选的,不是主入口」。
- 意图式用例:YAML 里写
intent: Apply the promo code "SAVE10"而不是选择器,可读如规格。 - Git-native:用例在仓库里、走 PR 审;它自己的话是「测试放在供应商私有数据库里没法在 code review 里审,并且制造锁定」。
- 真实浏览器 + 证据进 PR:失败「带日志、截图、trace 发到 PR」。
- 本地与 CI 同一命令,且可退出:YAML 转译为标准 Playwright,「没有锁定」。
它没有覆盖的六处,也是本文相对它的增量:
| 缺口 | Shiplight 的现状 | 本文的补法 |
|---|---|---|
| Oracle 种类 | 只有 E2E UI 一种 | 六层里的 Oracle 层:断言、契约、策略、LLM 回归、采样式裁判 |
| 判决形态 | pass / fail 二值 | PROMOTE / HOLD / ROLLBACK 三值 + blocking / next_actions / attempts |
| Oracle 保护 | 同一个 Agent 写代码、写测试、heal 测试 | 规则一:变更集 / 判决集分离,CODEOWNERS + hook + 提议通道 |
| Held-out | 无 | 规则二:visibility 字段,合入档跑 Agent 看不见的用例 |
| 预算与幂等 | 无 | 规则三:attempts 预算,采样式结果按三元组缓存 |
| 发布闸与熔断 | 止于 CI | Argo Rollouts Analysis 接发布闸;灰度指标复用同一契约 |
其中「self-healing」需要单独说一句公道话:它是 Shiplight 最有价值的功能之一,也是最需要边界的。定位器自愈属于执行层,应该有;断言自愈属于 oracle 变更,不应该有。产品上把这两者拆成两个开关、两条审计日志,是「比它做得更好」的最具体的一步。
八、施工顺序:先让 Agent 能查契约,再让它能被拦
第一阶段(两到三周):只读接入 + 确定性判决。 起 MCP server,只暴露 gate.contract.get、gate.check.run(fast 档)、gate.verdict.get、gate.evidence.get 四个工具;Runner 只接 Playwright 和 pytest;判决 schema 按第四节,但 decision 暂时只有 PROMOTE / HOLD。验收:一个编码 Agent 能在不看任何 dashboard 的情况下,从查契约到拿到绿判决走完一轮。
第二阶段(三到四周):合入闸 + 三条规则。 接代码托管 App 写 required status check;开 merge queue 并让 workflow 监听 merge_group;CODEOWNERS 圈住判决集;PreToolUse hook 拦 oracle 路径写入;上 held-out 用例和 attempts 预算。验收:故意让一个 Agent 去改测试断言,它应当被 hook 拦下并被引导到 gate.propose_oracle_change。
第三阶段(持续):采样式 oracle、升级通道、发布闸。 promptfoo / Inspect 回归接进完整档、只给 HOLD 权,阈值按 Wilson 下界表定;elicitation 表单模式接 HOLD 队列,URL 模式接 override;Argo Rollouts Analysis 接发布闸。验收:一次供应商静默更新模型权重,被完整档拦成 HOLD,复核者在三分钟内从证据包看懂原因并做出三选一。
九、带得走的一张表:人是用户 vs Agent 是用户
| 设计维度 | 人是一等用户 | Agent 是一等用户 |
|---|---|---|
| 主入口 | Dashboard | MCP 工具 + CLI;dashboard 只剩策略中心和 HOLD 队列 |
| 判决格式 | 红绿 + 日志链接 | 结构化 JSON:三值 decision、blocking、fix_hint、evidence URI、attempts |
| 判据可见性 | 默认全可见 | 契约可查,但一部分用例 held-out |
| 谁能改 oracle | 任何有写权限的人 | 变更 Agent 只能提议;人批准;hook 兜底 |
| 重试 | 手动点、无限制 | 预算制;采样式结果按三元组缓存 |
| 人出现的时刻 | 全程盯着 | 事前定策略、事中仅 HOLD |
| 升级通道 | Slack / 口头 | Elicitation 表单(日常 HOLD)与 URL(不可逆 override) |
| 自愈 | 无 | 定位器自愈允许,断言自愈禁止,两条日志 |
诚实的提醒
本文的协议与产品事实核实自 2026-09-03 当日的官方文档:MCP 规范(tools、elicitation 页面,版本 2026-07-28)、Claude Code hooks 文档、GitHub 关于受保护分支 / merge queue / CODEOWNERS 的文档、Shiplight 官网与文档。引用的两篇论文(2603.15676、2503.11926)是论文自报结论,未复现;SWE-bench 的「测试不在模型输入里」来自其论文摘要与评测指南的描述。我未亲手部署 Shiplight,也未在生产中跑过本文的完整六层架构——第二、三阶段的验收标准是设计目标,不是实测结果。
「三条防钻空子规则」是我的产品提炼,不是任何一份文档的规定。它们的共同失效边界是:如果你的确定性 oracle 覆盖面本身很薄,held-out 和预算只是在保护一个没什么可保护的东西——先把上一篇的阶段一做实。
最低成本的亲手验证实验(半天):在你现有的 Agent 编码环境里加一条 PreToolUse hook,匹配 Edit|Write,路径命中测试目录就退出码 2 并在 stderr 写一句提示。然后给 Agent 一个会让现有测试失败的任务,观察它的行为:它是修代码,还是试图改测试并被拦下,还是绕道(比如用 Bash 写文件)?记录一周内被拦的次数和绕道的方式。这份记录就是你的第一份「Agent 与门禁的对抗账本」,也是决定要不要上 held-out 和预算制的依据。
参考来源
论文
- Maiorano. Automated Self-Testing as a Quality Gate. arXiv 2603.15676, 2026.
- Baker et al. Monitoring Reasoning Models for Misbehavior and the Risks of Promoting Obfuscation. arXiv 2503.11926, 2025.
- Jimenez et al. SWE-bench: Can Language Models Resolve Real-World GitHub Issues?. ICLR 2024.
- Shi et al. Progent: Securing AI Agents with Privilege Control. arXiv 2504.11703, 2026 修订版.
协议与平台文档
- MCP 规范 · Tools · Elicitation
- Claude Code Hooks
- GitHub · 受保护分支与必需状态检查 · Merge queue · CODEOWNERS
- SWE-bench 评测指南
产品参照
本站相关