护栏与安全默认
智能体行为的分层防御:输入筛查、权限门控、沙箱隔离,以及不可逆开关的「默认安全」设计。
纵深防御,而非一道万能过滤器
任何单一护栏都会被绕过。可靠的系统叠加多层独立检查,使任一层的失效都不致命:
| 层 | 拦截什么 | 实现方式 |
|---|---|---|
| 输入筛查 | 明显的注入尝试 | 轻量分类器或模式清单 |
| 权限门控 | 越权行为 | 按智能体配置白名单,在代码中强制 |
| 沙箱隔离 | 合法动作造成的损害 | 限制文件系统、网络出口、超时 |
| 人工确认 | 不可逆后果 | 危险操作前显式提示 |
| 审计日志 | 事后还原 | 决策与动作的只追加记录 |
核心原则:权限在你的代码里强制,而不是向模型请求。 不能指望智能体自觉拒绝——客客气气地请求,不构成访问控制。
提示词注入无法靠提示词解决
智能体读到的任何文本都可能含有指令:检索来的文档、工具返回值、用户上传的文件、网页。不存在哪个提示词能可靠地让模型忽略后续指令。
有效缓解手段,按价值大致排序:
- 明确区隔不可信内容。 把检索/工具返回的内容标记为数据,与指令区分开。
- 约束能力,而非理解。 即便智能体被完全注入,它也只能做工具允许的事。只读智能体删不掉东西。
- 状态变更需确认,尤其是触发源来自不可信内容时。
- 不可逆操作保留人工审批环节。
注意第 2 层才是真正兜底的那一层。其余手段都是抬高门槛,只有能力限制能设定天花板。
不可逆动作必须默认安全
真正的损失都发生在这里。删除、发布、发送、支付、部署——做完就收不回来。
具体规则:
- 默认空跑(dry-run)。 真正执行必须显式传标志位。
- 先展示 diff/预览。 让人看到将要发生什么。
- 限制影响半径。 先在单条记录上验证,再放开批量。
- 绝不让一个含糊的请求隐含不可逆动作。
UI 代码里有个特别锋利的坑:布尔标志位在 undefined 时被判定为「继续执行」。若发布动作由 mode === 'push' 把关,标志位没设对就会偷偷上线。要判定肯定的取值,绝不要依赖「取反不存在」。
沙箱要点
即便可信的智能体也应受限运行:
- 文件系统:限定在工作目录内,禁止向外写入
- 网络:域名白名单;屏蔽元数据端点(
169.254.169.254) - 执行:超时、内存上限,非必要不开 shell
- 凭据:最小权限、短时效,绝不粘贴进上下文
把每个工具的返回值都当作下一步的不可信输入。
审计是为了学习,不是为了追责
要记录到足以还原一次决策:输入、选了什么动作、理由、结果。只追加。目的是回答「上周二到底发生了什么」,以及发现模式——某个工具 40% 的调用在失败,某个确认步骤所有人都在闭眼点。
最后那类发现才是最有行动价值的:一个人类总是点同意的护栏只是装饰,应该重新设计。