多智能体系统必备:沙箱与权限模型的双层安全设计
2026/8/30 22:08:16 网站建设 项目流程

“沙箱不是权限模型”这句话,如果你只做单机工具开发,可能觉得无所谓;一旦进入多智能体系统,混淆这两个概念会在上线后频繁踩坑:Agent 把不该调的工具调了、把不该看的文件读了、把不该花的额度花了,而系统日志里看到的却是“运行环境一切正常”。

先把结论放在前面:沙箱解决的是“代码能不能访问系统资源”的隔离问题,权限模型解决的是“Agent 凭什么、在什么条件下、对谁、做什么操作”的授权问题。二者是两层东西,必须同时存在,谁也不能替代谁。

这篇文章会用系统架构的视角拆解这个问题:先澄清沙箱和权限模型的本质差异,再说明多智能体系统为什么特别依赖权限模型,然后给出一套可落地的分层设计方案、策略配置示例和排查清单。适合正在做 Agent 框架、MCP 工具集成、自动化工作流或者企业级 AI 平台的开发者。

1. 核心概念辨析:Sandbox 与 Permission Model 到底差在哪

先看两个概念的定义,不要混着用。

1.1 沙箱的定位:隔离执行环境

沙箱是一套运行时隔离机制。常见实现包括:

  • 容器(Docker / containerd):隔离文件系统、网络、进程空间。
  • 虚拟机(QEMU / Firecracker):更彻底的硬件级隔离。
  • seccomp / AppArmor / SELinux:限制系统调用和内核能力。
  • 语言级沙箱(WebAssembly / V8 isolate):限制代码在特定运行时内执行。
  • 云端代码解释器(如 ChatGPT 的 Code Interpreter):在一个临时环境里执行 Python,用完销毁。

沙箱的判定对象是“一段不可信代码”。它回答的问题是:这段代码能否读取/etc/passwd、能否绑定端口、能否访问内网、能否把文件写到宿主机。

1.2 权限模型的定位:授权决策

权限模型是一套授权机制。常见实现包括:

  • RBAC:用户 - 角色 - 权限的映射。
  • ABAC:基于属性的访问控制,如时间、位置、数据标签、风险等级。
  • Capability(能力令牌):持有令牌即拥有对应操作的权力。
  • 用户授权(User Consent):由用户在关键操作前显式确认。
  • TokenScope:OAuth 2.0 / API Key 的权限范围。

权限模型的判定对象是“一个主体对客体的一次操作”。它回答的问题是:这个 Agent 代表哪个用户、是否有权调用“删除订单”这个工具、操作预算上限是多少、操作是否需要人工审批。

1.3 两者对比

维度SandboxPermission Model
作用层运行时 / 系统调用层应用业务层
保护对象宿主机与进程环境数据、工具、外部系统、用户利益
判定问题代码能碰哪些系统资源主体能对客体做什么操作
典型实现Docker、seccomp、VM、WasmRBAC、ABAC、Scope、Consent
控制粒度文件、端口、进程、系统调用API、数据行、工具、预算、审批流
失效后果宿主机被入侵、系统被破坏数据泄露、越权操作、业务损失

从表格能直接看出,两者失效的后果完全不同。把沙箱当作权限模型,等于只解决了“系统会不会被打穿”,没解决“Agent 会不会越权办事”。

2. 为什么多智能体系统特别依赖权限模型

单 Agent 场景下,沙箱加一道用户确认往往够用。但多智能体系统的核心特征是:多个 Agent 自主协作、相互调用、共享上下文,并且可能代表不同用户或不同租户行动。这时候权限问题会从“边缘问题”变成“核心问题”。

2.1 沙箱挡不住 API 副作用

沙箱能挡住rm -rf /,但挡不住一个 Agent 调用“发送邮件”工具向用户联系人列表发垃圾邮件。因为发送邮件的副作用发生在外部系统,沙箱根本看不到。

代码层面,沙箱看到的是:

response = send_email(recipients, content)

这只是一个普通函数调用,系统调用层面没有任何异常。但如果这个 Agent 没有权限发送邮件,或者只能向指定白名单联系人发送,而沙箱对此一无所知,等于授权完全失守。

2.2 沙箱挡不住数据语义越权

容器可以限制 Agent 访问整个文件系统,但只要/data目录被挂载进沙箱,容器就管不了里面的文件了。更麻烦的是数据语义层面的越权:

  • 一个 Agent 可以读取/data/customer.db中所有客户记录,但权限模型要求它只能读取“属于当前操作者”的记录。
  • 两个 Agent 共享同一个沙箱,Agent A 可以把 Agent B 的中间结果读走。
  • 一个低权限 Agent 调用一个高权限 Agent 暴露的工具,形成越权链。

这些是行级、字段级、租户级的授权问题,沙箱作为一个粗粒度隔离层,没有任何办法回答。

2.3 多 Agent 之间需要边界,不只是“宿主与代码”的边界

沙箱的经典模型是“宿主信任边界”和“不可信代码”。多智能体系统的信任关系要复杂得多:

  • Agent 与 Agent 之间可能互相不可信。
  • Agent 代理的是不同用户,操作权限必须跟着身份走。
  • Agent 可以动态创建子任务,把权限传递给子 Agent。
  • Agent 可以调用工具链,工具本身也有权限范围。

这种场景下的正确模型是“最小权限 + 显式授权 + 可审计”,而不是“丢进沙箱就完事”。

2.4 背景参考:桌面应用的沙箱提示

近期 ChatGPT 桌面版在 Windows 上启动时会出现“Creating a sandbox needed to run on your computer”的提示,本质就是把不可信的应用逻辑装进受限环境,避免应用越权访问操作系统。这个做法本身是对的,但它只覆盖了“应用代码不能乱碰系统”这一层。真正到了用户授权 AI 调用本地文件、执行命令、访问浏览器的场景,系统依然需要独立的权限提示与应用层授权。换句话说,沙箱负责兜底,权限模型负责决策。

3. 典型问题推演:一个越权操作是怎么穿透沙箱的

下面用一个可达成的场景说明“沙箱正常 + 权限失守”的整个过程。这套推演不需要真实环境,逻辑上完整可复现。

3.1 场景设定

系统由三个 Agent 组成:

  • Agent A:负责读取私有仓库中的订单数据。
  • Agent B:负责调用 CRM 系统的写入接口。
  • Agent C:负责任务调度,可以调用 A 和 B 暴露的工具。

所有代码都运行在同一个 Docker 沙箱中,宿主机文件系统没有暴露给容器。

3.2 异常行为链路

  1. Agent C 被提示词注入,输出一段恶意工具调用指令。
  2. Agent C 调用 Agent B 暴露的update_crm_record()工具,参数被篡改。
  3. Agent B 执行更新前没有校验调用方的身份与授权范围。
  4. CRM 系统收到了合法格式的 API 请求,写入成功。

从系统层面看,Docker 日志干净,进程没有异常退出,网络流量是正常的 HTTPS 调用。但从业务层面看,一个没有权限的 Agent 修改了 CRM 数据。

3.3 排查时的关键问题

如果等到事故发生后去查,应该按下面顺序定位:

排查项检查内容判断标准
沙箱配置容器是否只读挂载、是否有网络白名单沙箱本身是否被绕过
工具调用链路B 是否记录调用方 Agent ID是否有完整调用来源
授权校验B 是否校验 C 的权限范围C 是否本来就不该有写权限
用户确认写入操作是否经过人工审批是否有人为确认环节
审计日志是否记录参数前后值能否跟踪写入来源

这条推演的核心结论是:问题不在沙箱,而在权限模型缺失,导致 Agent 之间的调用没有“身份 - 资源 - 动作 - 条件”的校验。

4. 多智能体系统权限模型的分层设计

正确的做法是把权限模型分成几个独立层次,每一层解决一类问题。下面给出一个适合大多数 Agent 系统的分层结构。

4.1 四层权限架构

  • L1 基础设施隔离层:容器、虚拟机、网络策略。负责不让代码破坏宿主环境。
  • L2 工具执行授权层:每个工具都有 scope、调用者要求、参数校验规则。负责控制“谁可以调用这个工具”。
  • L3 数据访问控制层:行级、字段级、租户级权限。负责控制“这个 Agent 可以看到哪些数据”。
  • L4 用户审批与预算层:关键操作显式确认、额度预算、风险阈值。负责控制“这个操作是否值得执行”。

L1 是沙箱,L2 到 L4 是真正的权限模型。四层缺一不可,但每一层的职责不能混淆。

4.2 核心设计原则

第一,身份必须可传递。Agent C 调用 Agent B 的工具时,B 必须知道这个请求的最终归属是哪个用户或租户。不能只在最外层记录身份,内部调用全部匿名。

第二,权限必须最小化。每个 Agent 启动时只拿到完成当前任务所需的最小权限集合,任务结束后回收。不要在系统里配置一个“全功能 Agent”。

第三,关键操作必须显式授权。发送外部消息、删除数据、支付、修改权限这类操作,应当要求用户在界面中确认,而不是让 Agent 静默执行。

第四,所有授权决策必须可审计。每次授权的时间、决策依据、用户确认结果、参数快照都要进入审计日志。

第五,权限要有生命周期。长时间运行的多 Agent 系统中,会话结束、任务完成或风险升高时,要及时吊销权限。不能一个 token 从创建用到过期。

5. 落地示例:Agent 权限策略与中间件

下面给出一个通用的权限策略配置和调用校验示例。它不绑定特定框架,可以直接改造成 LangChain、AutoGen、CrewAI 或自研 Agent 系统中的中间件。

5.1 权限策略定义

策略文件采用 JSON 格式,便于动态下发:

{ "agent_id": "agent-b-crm-write", "principal": "user:zhang@example.com", "allowed_tools": [ "crm.query_order" ], "tool_scopes": { "crm.query_order": { "allowed_actions": ["read"], "allowed_tenants": ["tenant-001"], "max_records": 100 } }, "require_human_approval": [ "crm.update_order", "crm.delete_order" ], "budget": { "max_calls_per_hour": 200, "max_cost_per_task": 5.0 }, "effective_until": "2025-12-31T23:59:59Z" }

这里的字段含义:

  • principal:最终归属用户。
  • allowed_tools:该 Agent 可以调用的工具清单。
  • tool_scopes:每个工具的细粒度动作、租户范围和数量上限。
  • require_human_approval:命中这些工具时必须进入人工审批。
  • budget:调用频率和成本额度。
  • effective_until:权限有效期。

5.2 权限校验中间件

在 Agent 调用工具之前,由统一中间件做一次校验:

import time from typing import Any, Dict class PermissionDecision: def __init__(self, allowed: bool, reason: str = ""): self.allowed = allowed self.reason = reason def check_tool_call( policy: Dict[str, Any], agent_id: str, tool_name: str, action: str, resource_owner: str, now: float ) -> PermissionDecision: if agent_id != policy.get("agent_id"): return PermissionDecision(False, "unknown agent") if tool_name not in policy.get("allowed_tools", []): return PermissionDecision(False, "tool not allowed") if now > policy.get("effective_until", 0): return PermissionDecision(False, "policy expired") scopes = policy.get("tool_scopes", {}).get(tool_name, {}) if action not in scopes.get("allowed_actions", []): return PermissionDecision(False, "action not allowed") if resource_owner not in scopes.get("allowed_tenants", []): return PermissionDecision(False, "tenant not allowed") return PermissionDecision(True, "ok")

这个示例省略了预算扣减、审批回调、审计日志,但核心逻辑已经完整:每次工具调用都携带agent_idtool_nameactionresource_owner和当前时间,由中间件统一决策。

5.3 人工审批回调

对于require_human_approval中的工具,中间件不能直接放行,而是要进入待审批队列:

def call_with_approval(tool_name, payload, approver_callback): if tool_name not in POLICY.get("require_human_approval", []): return execute_tool(tool_name, payload) approval_id = create_approval_request(tool_name, payload) result = approver_callback(approval_id) # 返回是否批准 if not result.approved: return {"error": "rejected by human", "approval_id": approval_id} return execute_tool(tool_name, payload)

审批环节要展示给用户的不是原始 JSON,而是“Agent X 要以用户 Y 的身份调用工具 Z,参数摘要如下”,让用户能快速判断是否授权。

6. 工程化落地:策略下发、审计与撤权

有了策略和中间件还不够,工程上还要解决三个问题。

6.1 策略动态下发

权限策略不应该硬编码在 Agent 代码里。推荐的做法是集中式策略服务,Agent 启动时拉取,或者由调度系统在创建任务时一起下发。这样可以快速修改某个 Agent 的权限,而不需要重新部署整个系统。

策略更新时要考虑一致性问题:如果一个任务运行到一半,权限被收回,已经执行的步骤如何处理?更稳妥的做法是“新任务新策略,旧任务旧策略”,正在运行的任务不做中途收回,除非检测到高风险行为。

6.2 审计日志

每条重要的权限决策都要记录。日志建议包含:

  • 请求 ID、Agent ID、用户 ID、租户 ID。
  • 工具名、动作、资源 ID。
  • 决策结果、拒绝原因。
  • 策略版本号。
  • 审批人、审批时间。
  • 请求参数摘要和返回值摘要。

日志要 append-only,不能被 Agent 进程写入或修改。这样才能作为事后追责和安全分析的依据。

6.3 动态撤权

常见触发条件包括:用户主动撤销、任务完成、预算耗尽、检测到异常行为、策略过期。撤权要实现成“实时生效”,即策略服务推送更新后,所有在线 Agent 下一次调用工具时必须重新加载策略。

如果系统用了超时时间较长的 API Key,需要配合短期 token 机制。每次工具调用使用短期 token,权限变更后 token 立即失效,而不是等长时间过期。

7. 常见误区与排查方法

这部分是从真实工程经验中提炼的常见问题,直接做成排查表。

问题现象可能原因排查方式解决方案
Agent 调用了不该调的工具权限校验在框架层被跳过,Agent 直连工具检查工具调用入口是否统一经过中间件把所有工具调用收敛到统一网关
沙箱正常但数据被越权读取权限只做到“目录级”,没有行级租户过滤检查数据库查询是否带租户条件在数据访问层强制注入租户 ID
一个 Agent 篡改另一个 Agent 的数据Agent 之间共享了同一份上下文或凭据检查凭据存储和上下文传递链路每个 Agent 独立凭据,最小权限
审批弹窗形同虚设审批只展示工具名,不展示具体参数检查审批界面信息密度展示参数摘要、数据对象、影响范围
权限收回后仍能继续调用长期 token 未失效,或策略缓存未更新检查 token 有效期和缓存刷新机制改用短期 token,增加策略刷新监听
审计日志查不到关键操作部分工具绕过中间件直连外部 API对比调用网关日志与外部系统日志强制所有外部调用经过网关

7.1 排查时的判断顺序

事故发生后,按“先沙箱、后权限、再数据”的顺序排查:

  1. 沙箱是否被绕过?查网络连接、挂载点、进程树。
  2. 权限校验是否生效?查工具调用日志里的授权决策记录。
  3. 数据是否越权?查数据库访问日志中的租户过滤条件。
  4. 用户是否批准?查询审批记录和操作前后的复核记录。

8. 最佳实践与合规边界

多智能体系统的权限设计,除了技术正确性,还要考虑业务合规和安全边界。

8.1 技术最佳实践

第一,从最小权限开始,逐步扩大。不要一上来就给 Agent 配置全量工具权限。绝大多数任务只需要一到两个工具的只读权限。

第二,把沙箱参数和权限策略分开维护。容器配置、网络策略、挂载点归基础设施团队;工具权限、数据范围、审批规则归业务平台团队。两边升级节奏不同,混在一起会互相阻塞。

第三,对高风险工具做二次确认。发送消息、删除、写库、支付、导出数据这些操作,默认进入人工审批队列,审批超时自动拒绝。

第四,把权限检查做成可测试的独立模块。单元测试覆盖“未授权调用被拒绝”“租户不匹配被拒绝”“策略过期被拒绝”“审批未通过不执行”等核心用例,并在每次变更后回归。

8.2 合规与安全边界

涉及用户数据、企业数据、外部系统账号的操作,必须遵守以下边界:

  • 用户数据访问须获得明确授权,授权范围应限定在任务所需的最小数据集。
  • 涉及个人信息、联系人、账单等敏感数据,应遵循个人信息保护相关法规。
  • Agent 调用外部系统时,不能使用超出原始授权范围的 token,也不得长期保存凭据。
  • 涉及人类用户的肖像、声音、身份信息的生成或处理,须取得明确授权并标注用途。
  • 禁止把权限模型设计成“收集一切数据以备用”,数据最小化原则同样适用于 AI 系统。

这些不是可选项。多智能体系统一旦接入真实业务和真实用户数据,合规问题就是上线阻塞项。

9. 总结

回到标题:A sandbox is not a permission model for multi-agent systems。

沙箱是“执行环境的安全兜底”,权限模型是“业务操作的授权决策”。多智能体系统的每一次工具调用、每一次数据访问、每一次外部系统交互,都需要明确的身份、动作、资源和条件校验。

建议下一步这样做:

  1. 先盘点现有系统中的工具调用入口,找出绕过统一授权的路径。
  2. 为每个 Agent 建立最小权限策略,关键操作加入工审批。
  3. 把权限校验收敛到统一中间件,补全审计日志。
  4. 用异常链路推演验证权限模型是否真的生效。

最容易踩的坑是:框架自带的沙箱让开发者产生“安全已经足够”的错觉,等上线后出现越权操作才回头补权限。如果在架构设计阶段就把沙箱和权限模型拆开对待,多智能体系统的安全地基会扎实很多。建议收藏备用,等真正开始做 Agent 权限治理时再翻出来对照检查。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询