这一期想聊一个被大量团队低估的问题:AI 安全不等于系统安全。作为长期运营大模型 API 中转站的 4sapi,我见过太多把「模型很乖」当成「系统很安全」的接入方案,最后在真实事故里交学费。
痛点:Agent 能执行命令,谁保证它不越界
Agent 的价值在于能执行命令:读写文件、调用工具、访问外部系统、发起网络请求。可只要多问一句——谁保证它不越界?——大多数方案就答不上来。
模型的每个输出本质上都只是「建议」。真正把动作落地的,是宿主环境里的一段普通程序。当一段建议被直接翻译成系统调用,Agent 就同时具备了「会被诱导」和「能执行」两个特性。一条精心构造的 Prompt Injection 可以让平时表现完全正常的 Agent 去删除文件、外发数据或修改配置,而模型自己对这一切毫无察觉。
近期的一系列 Agent 沙箱逃逸事件反复证明同一件事:降低有害模型行为与可靠地包含软件,是两个不同的目标。前者做的是「让模型不做坏事」,后者做的是「让软件跑不出边界」。把前者的成果当成后者的保障,就是事故的起点。
原理速览:AI 安全与系统安全是两套体系
前沿实验室在「概率性 AI 安全技术」上投入巨大:对齐训练、红队评测、越狱防护、输出过滤。这些技术有价值,但共同特征是概率性——任何防护都存在绕过空间,评测集永远无法覆盖全部恶意输入,模型的「善良」也无法被证明。
系统安全面对的是另一个问题:一个程序能不能跑出它被允许的边界。这个问题从操作系统时代起就有成熟答案——权限、隔离、沙箱、审计。系统安全的特征是确定性:策略是写死的代码,不依赖任何模型的心情。
问题恰恰出在混用上。不少团队把概率性技术用在了需要确定性保障的场景:用「模型不会生成危险动作」的假设,替代「进程没有权限执行危险动作」的事实。于是沙箱逃逸事件一再发生,而每次复盘都能看到同一个根因——把两类安全当成了同一件事。
一张表看懂两类安全的差别
| 维度 | AI 安全 | 系统安全 |
|---|---|---|
| 核心目标 | 让模型不做坏事 | 让软件跑不出边界 |
| 典型手段 | 对齐训练、红队评测、输出过滤 | 权限、隔离、沙箱、审计 |
| 控制性质 | 概率性,无法证明完备 | 确定性,策略即事实 |
| 失效方式 | 越狱、Prompt Injection、对抗样本 | 逃逸、提权、滥用授权 |
| 判断主体 | 模型自身,可被诱导 | 策略引擎,不可被诱导 |
| 验收方式 | 评测集上的指标分数 | 边界约束是否被强制执行 |
| 出事后果 | 一次越狱对话 | 一次真实的数据泄露或破坏 |
这张表值得贴在每个 Agent 项目的墙上。模型的评测分数再高,也替代不了一条防火墙规则或一个只读挂载。
沙箱逃逸为什么总在发生
把近期的逃逸事件放到一起看,成因高度重复:
- 把概率当确定性:默认「模型不会生成危险动作」,于是不做权限隔离。
- 权限给得过大:Agent 进程直接拥有用户级全部权限,读写边界等于账号边界。
- 动作直通系统:模型输出的工具调用被直接映射成系统调用,中间没有任何校验层。
- 缺少审批与审计:高危动作无人确认,出事后无日志可查,复盘只能靠猜。
这四个成因里,第一个最致命。概率性安全的失效率再低,乘以每天百万级的 Agent 动作调用量,也一定会变成高频出现的真实事件。
确定性控制四层:权限 / 隔离 / 审批 / 审计
治理方案并不神秘,就是把系统安全的老办法按 Agent 的特性重新排布:
- 第一层 权限(最小权限):每个 Agent 只拿完成任务所需的最小凭证,按「角色 × 资源 × 操作」建立权限矩阵。读、写、发请求分别授权,绝不共用一把万能钥匙。
- 第二层 隔离(Sandbox):Agent 进程放进容器或虚拟机,文件系统只读挂载,网络走白名单,CPU、内存、磁盘配额写死。逃逸成本越高,攻击面越小。
- 第三层 审批(Approval):删除、转账、外发、写数据库这类高危动作,必须经过人工或独立策略引擎批准后才能执行。审批是最贵的一环,也是最后一道闸。
- 第四层 审计(Audit):每个动作的入参、决策、执行结果、token 消耗全量留痕,形成可追溯的完整链路。审计不是为了追责,是为了让下一次改进有据可依。
四层缺一不可。只做隔离不做审批,高危动作依然畅通;只做审批不做审计,出了问题无从复盘。
治理链:从模型动作到审计日志
治理链的完整形态可以画成一条单向管道:
模型提出动作(自然语言 / 工具调用)
│
▼
策略引擎解析并分类意图
│
▼
权限检查(角色 × 资源 × 操作 最小权限矩阵)
│
▼
是否高危? ──是──► 人工或二次校验审批 ──不通过──► 拒绝并记录
│否
▼
沙箱执行(只读文件系统 / 网络白名单 / 资源限额)
│
▼
审计日志(入参、决策、执行结果、token 消耗)
注意这条链路里,模型只出现在第一格。模型可以「提议」,但「能不能执行」永远由后面的确定性代码回答。即便模型被 Prompt Injection 完全攻破,动作仍然过不了权限、审批、沙箱任何一关——这才是「确定性」的意义。
三种高危的接入姿势
第一,把输出过滤当成执行护栏。过滤层拦截的是「看起来危险」的文本,可攻击者只需要把危险指令拆散、编码、藏进工具参数里,过滤就形同虚设。第二,把人工 review 当成事后补救。让运营在出事后逐条翻日志,不如在事前把高危动作的审批做成强制流程。第三,把模型版本当成安全补丁。换一个更「乖」的模型并不等于堵住了漏洞,因为漏洞的根不在模型肚子里,而在宿主环境的执行边界上。
这三种姿势的共同点,都是把概率性手段放在确定性控制的位置上。评估一个 Agent 项目安不安全,真正要问的问题是:假如模型被完全攻破,系统还能不能守住?如果答案依赖「模型应该不会」,那这道防线就是纸糊的。
接入教程:带权限校验的 Agent 调用
落地示例用 openai 库,通过中转网关统一接入,再把权限校验插在模型调用与真实执行之间:
import os
from openai import OpenAI
# 经中转网关统一接入,base_url 使用中转入口
client = OpenAI(
api_key=os.environ["DSH_API_KEY"],
base_url="https://4sapi.com/v1",
)
READONLY_TOOLS = {"read_file", "list_dir", "web_search"}
HIGH_RISK_TOOLS = {"delete_file", "send_email", "write_db", "run_shell"}
def decide(action: str) -> str:
"""确定性决策:allow / approval / deny,与模型输出完全解耦。"""
if action in READONLY_TOOLS:
return "allow"
if action in HIGH_RISK_TOOLS:
return "approval"
return "deny"
def run_in_sandbox(action: str, args: str) -> dict:
"""在受限环境中执行动作,失败也不会触及宿主系统。"""
... # 容器或虚拟机内的实现
def ask_human(action: str, args: str) -> dict:
"""高危动作进入人工审批队列,返回审批结果。"""
... # 对接工单或审批系统
def audit_log(action: str, args: str, decision: str, result: dict) -> None:
"""把入参、决策、结果写入审计存储。"""
... # 写日志系统或对象存储
def run_agent(initial_prompt: str) -> None:
messages = [{"role": "user", "content": initial_prompt}]
for _ in range(10): # 步数上限,防止失控循环烧 token
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=TOOL_SCHEMAS, # 工具定义,此处省略
)
message = response.choices[0].message
messages.append(message)
if not message.tool_calls:
break # 模型不再调用工具,回合结束
for call in message.tool_calls:
action = call.function.name
args = call.function.arguments
decision = decide(action) # 策略引擎先于执行,不经过模型
if decision == "allow":
result = run_in_sandbox(action, args)
elif decision == "approval":
result = ask_human(action, args)
else:
result = {"ok": False, "reason": "denied"}
audit_log(action, args, decision, result) # 全量留痕
messages.append(
{
"role": "tool",
"tool_call_id": call.id,
"content": repr(result),
}
)
这段代码的关键不是 openai 调用本身,而是三行确定性逻辑:decide() 决定动作等级,run_in_sandbox() 保证执行环境受限,audit_log() 保证一切可追溯。模型只能请求动作,永远不能自己授权。
再看一遍上面的调用循环:decide() 返回的三个等级正好对应四层控制里的权限与审批。allow 的动作走沙箱执行,approval 的动作等人工放行,deny 的动作连沙箱都不进。audit_log() 把每一步写进审计存储,事后复盘只需要按时间线回放。这套结构不需要任何花哨的框架,几十行确定性代码就能搭起来,却能把逃逸事件的破坏半径从「整个系统」缩小到「一次调用」。
中转侧治理:配额、负载与计费
权限治理在 Agent 侧,网关侧也有对应工作。中转站这类入口天然适合做三件事:
- 独立 Key 与配额:每个 Agent 一个独立 API Key,按项目设置速率上限与日配额。某个 Agent 失控时直接掐断,不影响其他业务。
- 负载均衡:多模型、多区域节点之间按延迟与可用性路由请求,避免单点故障拖垮 Agent 任务。
- 计费可视化:按 Agent、按项目汇总 token 消耗,把成本归属到具体业务线,超预算的调用第一时间被发现。
这三件事与权限治理是互补关系:网关管「流量能不能发出去」,Agent 侧管「动作能不能执行」,两侧都不依赖模型自己的判断。
成本与风险提示
- 概率性安全的隐性成本:对齐与评测投入巨大,但它降低的是风险而非消除风险。预算上要按持续投入规划,不能当成一次性工程。
- 确定性控制的显性成本:沙箱增加资源开销,审批引入延迟。把审批做成异步队列、高危动作批量处理,延迟就能控制在可接受范围。
- 审计存储成本:全量日志增长很快,按「入参 + 决策 + 结果摘要」三级结构存储,保留周期与合规要求对齐。
- token 成本:Agent 循环是 token 消耗大户。步数上限、上下文裁剪、缓存命中都能显著降本;配合网关配额,预算就被锁死。
- 合规红线:一切治理都建立在合法接入的基础上。中转与代理只做合规的 API 访问、架构设计与负载均衡,不提供任何绕开监管的动作。
另外要提醒一点:确定性控制是常年成本,不是一次性投入。沙箱资源、审批人力、审计存储、演练开销,都要按季度滚动进预算。很多项目上线时控制做得漂亮,半年后因为预算收紧悄悄撤掉了隔离层——这才是最危险的退化。控制体系应该像防火墙一样永远在线,而不是像活动一样办完即止。
上线前检查清单
- 每个 Agent 独立 API Key,权限矩阵最小化
- Sandbox:只读文件系统、网络白名单、资源限额
- 高危动作(删除、外发、转账)必须经过审批
- 决策逻辑是确定性代码,与模型输出完全解耦
- 全量审计:入参、决策、结果、token 消耗可追溯
- 步数上限与上下文长度上限已配置
- 网关侧配额、速率限制、计费告警已生效
- 用 Prompt Injection 场景做过逃逸演练
- 权限与审批策略经过至少一次独立评审
九项全部勾上,Agent 才算具备上生产的资格。少任何一项,都是在用概率赌确定性。
总结
AI 安全负责让模型不做坏事,系统安全负责让软件跑不出边界;前者是概率性的,后者必须是确定性的。沙箱逃逸事件反复提醒:Agent 接入生产时,权限、隔离、审批、审计四层确定性控制必须放在模型之前,模型自己的判断永远只是参考。4sapi 在中转侧做好配额、负载均衡与计费治理,Agent 侧的确定性安全,需要每个接入方自己守住。欢迎在评论区发表想法/聊聊。