让 Agent 提交预约前,先拆开提议与审批权限
LabQuorum 将实验室预约拆为两个 Agent:一个检查设备、培训资格和空闲时间并创建待审批请求,另一个由负责人操作以审核和请求提交。前者的工具配置中完全没有提交能力,以明确权限边界应对聊天审批歧义。
AI 深度解读
把 AI 接进预约群,难点并不是让它找到空闲时间,而是让所有人分清:它刚才提出了方案,还是已经替你占用了资源。LabQuorum 在实验室仪器预约里划了一条明确边界:Agent 可以提议,真正生效必须由人确认。
这次黑客松项目值得看的,是权限怎么落到工具上,以及一次真实学生试用如何暴露了自动化测试没发现的问题。它也提醒做 AI 应用的程序员:账本正确、演示跑通,与整个流程可以放心上线,是几件不同的事。
预约权限为什么要从工具列表里拿掉
作者团队在桥接 Mattermost 的 Switch 房间里放了两个 Agent,共用通过 MCP server 访问的 SQLite 账本,但工具权限不同。
@labops 面向房间里的所有人,可以查询仪器、培训资格和空闲时间,也可以创建待处理申请。它的工具配置里根本没有提交工具。即使有人诱导它直接预约,它也缺少执行入口。
@pi-desk 只接受其所有者,也就是课题负责人 PI 的消息。它可以读取申请、检查规则、拒绝申请或请求提交。提交前,PI 必须回答 Switch 原生审批卡,卡片列出仪器、申请人、本地时间与 UTC 时间、修订版本和内容哈希。
后两项让确认对象更具体:人批准的是某个版本的申请内容,而不是聊天里一句可能已经过时的「同意」。提议、拒绝和提交还会进入哈希链审计日志,供后续校验。
能否执行关键操作,应该由工具权限决定。
这里也有平台能力的贡献。学生向 @pi-desk 请求批准时,消息会被 Switch 提前拒绝,Agent 根本收不到。作者明确承认,这条边界是平台提供的,并非他们自己实现。
一个合格回复,要把冲突和待定状态说清楚
作者给出的场景很具体:申请在 14:00 到 17:00 之间使用 INS-01,时长 60 分钟。但演示数据里的 Dr. Lena Okafor 已经预约了 14:00 到 15:30。
合格回复不能只说「时间冲突」。它需要指出冲突区间及预约人,考虑清洁间隔,提出同样长的最近空档 15:45 到 16:45,再给出申请人和 request ID,明确申请仍在等待处理。
线上部署确实产生了这样的结果:提出替代时间,申请保持 pending,提交事件为零,提议侧没有审批卡。
作者还在独立测试账本上验证了审批路径:PI 回答一次原生卡片,写入恰好一条匹配预约和一条提交审计事件;拒绝审批卡后,申请仍然 pending;学生点击所有者专属卡片上的 Approve,也不能使它生效。两次提示注入探测产生了匹配卡片,但没有发生提交。
这些结果支持审批机制的部分设计,验证范围仍要分清:独立测试账本上的成功,不能直接替代线上完整流程的验证。
为什么真实学生一上手,就发现了三个问题
一个没有编写 Agent 的学生进入房间,向 @rao-labops 申请下一个开放日 14:00 到 17:00 之间的 60 分钟。首次回复用了 7 分 47 秒。
慢的直接原因是只读查询也触发审批。lab_state 和 check_availability 都弹出了卡片,学生还能回答。频繁确认会训练用户顺手点击,削弱真正提交时那次确认的辨识度。
第二个问题是申请人写死成了演示用户 Maya。Agent 正确拒绝用别人的名字替学生申请,却因此无法完成正常申请。拒绝冒名没有解决身份接入问题。
第三个问题更隐蔽:学生回复卡片的 A7 1、A9 1,被 Agent 当成了有关培训资格的事实。交互控制信息混进了业务对话。
团队采用先写测试再修复的方式,当晚合并了修改:从 Switch 发送者 handle 获取身份;读取不再弹审批卡,只保留属于 PI 的 commit_booking 确认;卡片回答不再作为普通对话事实处理。
复查还找到了越权漏洞:cancel_my_proposal 只接收 booking ID,没有检查所有者,学生也能取消别人的已提交预约。团队复现后,让它和 check_availability 都要求并强制校验发送者 handle。冲突回复也增加了明确区间和确定性的摘要,减少表述漂移。
同一学生在同一线上房间重试后,系统以学生自己的身份提出 15:45 到 16:45 的待处理申请,明确表示尚未预约。回复耗时降到 80 秒,审批卡为零;学生随后请求 @pi-desk 批准,Switch 在四秒内拒绝。
速度改善发生在一组修复之后,原文没有拆分各项贡献,也没有给出重复测量,因此不能把这个结果当成稳定性能指标。
我的判断
这篇最有价值的地方,是把身份、授权、审批和审计分别落到具体机制里。相比只在提示词里要求模型遵守规则,移除危险工具能提供更明确的约束;相比所有动作都确认一次,把确认集中在产生约束力的提交上,也更符合用户的注意力习惯。
但 LabQuorum 目前只交付提议功能,具有约束力的提交仍然关闭。原因很具体:没有经过验证的 Console session ID,因而没有在线验证每个进程只提交一次的限制;五次注入探测中,有三次没有捕获到申请或卡片,只能算未证明;线上追踪也没显示实际运行的模型及 reasoning effort。
测试账本证明过一次批准能正确落账,还不足以证明整个部署流程可以开放提交。
常见的替代方案,是让聊天助手生成申请,再进入传统审批页面确认。原文没有提供与这种做法的对照数据,无法证明双 Agent 更省事或更可靠。它展示的是一种有参考价值的权限分工,以及一次有效的试用纠错过程。
还有两个前提不能忽略:所有者限制依赖 Switch;演示中的人员和实验室记录全部是合成数据。原文也没有说清内容哈希如何参与最终提交校验,因此不能仅凭卡片展示了哈希,就认定申请变更风险已经解决。
能拿来做什么
- 做聊天式操作入口时,先区分查询、申请和生效操作,再按角色分配工具。可以直接借鉴
@labops不持有提交工具的做法。 - 在前端和服务端之间明确区分普通消息与审批回执。发送者身份应来自可信平台上下文,后端仍需校验资源所有权,不能相信工具参数里自报的申请人。
- 找一位没有参与开发的人,用自己的账号走完整流程。重点观察回复耗时、确认次数、身份归属,以及「待处理」是否被误解成「已完成」。
- 想研究账本与审计,可以从作者提供的本地命令开始。项目使用 Python 3.12、uv、SQLite 和官方 MCP Python SDK:
uv sync --locked
uv run lq init
uv run lq seed --demo --anchor-date 2026-11-07
uv run lq audit verify
要留意 --demo --anchor-date 2026-11-07:这里初始化的是指定日期的合成演示记录。本地审计校验可以帮助理解账本,但不能替代线上权限和审批验证。