多智能体系统必备:沙箱与权限模型的双层安全设计

发布时间:2026/8/30 22:09:04
多智能体系统必备:沙箱与权限模型的双层安全设计 “沙箱不是权限模型”这句话如果你只做单机工具开发可能觉得无所谓一旦进入多智能体系统混淆这两个概念会在上线后频繁踩坑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由用户在关键操作前显式确认。TokenScopeOAuth 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 异常行为链路Agent C 被提示词注入输出一段恶意工具调用指令。Agent C 调用 Agent B 暴露的update_crm_record()工具参数被篡改。Agent B 执行更新前没有校验调用方的身份与授权范围。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:zhangexample.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_id、tool_name、action、resource_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 排查时的判断顺序事故发生后按“先沙箱、后权限、再数据”的顺序排查沙箱是否被绕过查网络连接、挂载点、进程树。权限校验是否生效查工具调用日志里的授权决策记录。数据是否越权查数据库访问日志中的租户过滤条件。用户是否批准查询审批记录和操作前后的复核记录。8. 最佳实践与合规边界多智能体系统的权限设计除了技术正确性还要考虑业务合规和安全边界。8.1 技术最佳实践第一从最小权限开始逐步扩大。不要一上来就给 Agent 配置全量工具权限。绝大多数任务只需要一到两个工具的只读权限。第二把沙箱参数和权限策略分开维护。容器配置、网络策略、挂载点归基础设施团队工具权限、数据范围、审批规则归业务平台团队。两边升级节奏不同混在一起会互相阻塞。第三对高风险工具做二次确认。发送消息、删除、写库、支付、导出数据这些操作默认进入人工审批队列审批超时自动拒绝。第四把权限检查做成可测试的独立模块。单元测试覆盖“未授权调用被拒绝”“租户不匹配被拒绝”“策略过期被拒绝”“审批未通过不执行”等核心用例并在每次变更后回归。8.2 合规与安全边界涉及用户数据、企业数据、外部系统账号的操作必须遵守以下边界用户数据访问须获得明确授权授权范围应限定在任务所需的最小数据集。涉及个人信息、联系人、账单等敏感数据应遵循个人信息保护相关法规。Agent 调用外部系统时不能使用超出原始授权范围的 token也不得长期保存凭据。涉及人类用户的肖像、声音、身份信息的生成或处理须取得明确授权并标注用途。禁止把权限模型设计成“收集一切数据以备用”数据最小化原则同样适用于 AI 系统。这些不是可选项。多智能体系统一旦接入真实业务和真实用户数据合规问题就是上线阻塞项。9. 总结回到标题A sandbox is not a permission model for multi-agent systems。沙箱是“执行环境的安全兜底”权限模型是“业务操作的授权决策”。多智能体系统的每一次工具调用、每一次数据访问、每一次外部系统交互都需要明确的身份、动作、资源和条件校验。建议下一步这样做先盘点现有系统中的工具调用入口找出绕过统一授权的路径。为每个 Agent 建立最小权限策略关键操作加入工审批。把权限校验收敛到统一中间件补全审计日志。用异常链路推演验证权限模型是否真的生效。最容易踩的坑是框架自带的沙箱让开发者产生“安全已经足够”的错觉等上线后出现越权操作才回头补权限。如果在架构设计阶段就把沙箱和权限模型拆开对待多智能体系统的安全地基会扎实很多。建议收藏备用等真正开始做 Agent 权限治理时再翻出来对照检查。