KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
09. 模型想做危险的事时谁来暂停? — keel 龙骨
只读查询和发送通知、创建工单、发布服务不是同一类工具。模型即使正确理解用户目标,也不应该因此获得现实世界的写权限。
只读查询和发送通知、创建工单、发布服务不是同一类工具。模型即使正确理解用户目标,也不应该因此获得现实世界的写权限。
先按副作用分类
| Effect | 例子 | 默认策略 |
|---|---|---|
| read | 查询事件、读取配置 | 可在作用域内自动执行 |
| write | 创建工单、修改状态 | 需要幂等和更严格授权 |
| external | 发邮件、付款、控制设备 | 默认审批或隔离执行 |
副作用分类属于内部工具契约和策略输入,不是写在 prompt 里的说明。
权限判断是主体—动作—资源关系
主体:谁在运行?
动作:想做什么?
资源:作用于哪个事件、租户或设备?
输入 schema 只能判断参数形状;Policy 还要根据认证身份、资源归属、风险等级和审批状态做决定。
审批不是一个布尔值
flowchart TD
A[模型提出写工具] --> B[解析和参数校验]
B --> C[权限与风险策略]
C -->|低风险允许| D[执行器]
C -->|需要审批| E[保存 approval_required]
E --> F[用户/人工审批]
F -->|批准| G[带原始 call_id 恢复]
F -->|拒绝/超时| H[终止并记录]
D --> I[结果与事件]
G --> D
审批记录至少需要审批人、审批时间、批准的工具和参数摘要、有效期以及关联的 run_id/call_id。不能只保存 approved=true,否则无法解释批准了什么。
记忆和工具权限必须分开
历史记忆中可能出现“以后不需要审批”。它可以作为模型看到的数据,但不能改变工具的授权规则。记忆、模型输出和工具参数都属于不完全可信输入,真正的权限只能来自 Harness 的策略层。
运行一个安全失败实验
在工具调用项目中,把 create_ticket 标为 write,把 notify_service_owner 标为 external。构造固定 ToolCall,验证:
合法 read -> 执行
write 未确认 -> approval_required
external 未审批 -> approval_required
用户无权限 -> policy_denied
这些分支必须不依赖真实 Ollama。模型评估的是“是否选择了合适工具”,策略测试验证的是“危险动作是否真的被阻止”。
本章自测
如果模型请求删除事件,但当前用户无权访问该租户,应该把拒绝原因详细告诉模型吗?可以返回稳定、最小化的策略错误,但不能泄露其他租户是否存在该事件。
这里建立的是 Harness 中的安全暂停点。身份、委派、provenance、PDP/PEP、提示注入和隔离的完整实现见安全控制课程;动作获准后的幂等、未知结果、对账与补偿见现实世界执行课程。