AWS 开源智能体沙箱 Strands Box,用 Dogwood 策略约束工具调用
Strands Box: Open-Source Agent Sandbox from AWS
AWS 发布开源本地智能体沙箱 Strands Box,以开发者预览形式推出,把操作系统隔离与 Dogwood 语义策略结合,让开发者定义智能体能访问什么、在什么条件下行动。
我几乎每天都与 AWS 客户谈论智能体。我听到很多人对智能体已经带来的成果感到兴奋,包括在软件开发、运营、业务流程以及直接服务客户方面。我也听到他们对更多控制、更强安全性以及更深入理解智能体工作方式的强烈渴望。在客户的指引下,我们正在 AWS 深度投资于智能体安全、隔离和策略。
去年夏天,我们发布了 AgentCore,这是我们用于构建和优化智能体的平台。AgentCore Runtime 是 AgentCore 的核心:一个用于运行智能体的安全沙箱,其中每个智能体的每个会话都拥有自己专用的 MicroVM(基于 Firecracker,以及 AWS 二十年来在虚拟化安全方面的投资)。去年晚些时候,我们发布了 AgentCore Policy,允许对云托管智能体如何使用其工具进行细粒度控制,利用了最初在 AWS 开发的 Cedar 策略语言。今年,我们发布了 Dogwood,这是我们开源的策略语言,旨在为定义智能体能做什么带来更强大的能力和控制。上周,我们开源了 Dogwood Local Engine,为 Dogwood 提供了一个持久、快速的本地运行时。
今天,我们很高兴宣布我们在智能体安全投资中的另一部分:Strands Box,一个面向 AI 智能体的开源本地沙箱。我们以开发者预览版形式发布 Box,将操作系统隔离与用 Dogwood 编写的语义策略相结合。这些控制措施共同让开发者能够定义智能体可以访问什么,以及在什么条件下可以行动。
无论你的智能体是直接使用工具、通过 MCP 使用工具,还是生成 shell 或 Python 代码,Strands Box 都能工作。与 Dogwood 和 Strands 一样,Strands Box 可与任何模型配合使用,无论是在本地还是在任何云上。它甚至不绑定于 Strands Harness SDK。你可以将 Box 与任何智能体框架或 harness 一起使用(当然,如果你能看看 Strands harness,我们会很高兴)。
我们在 Box 中特别兴奋的是语义策略:能够在每个工具级别设置策略,并使其被确定性地强制执行。例如,通过 Box 的策略,你可以强制执行诸如“允许此智能体执行 git push,但仅当测试通过时”,或“允许此智能体使用支付 API,但每天总计不超过 100 美元”之类的规则。如果你一直关注我们在 AgentCore Policy 和我们的策略语言 Dogwood 上的工作,这些类型的策略听起来可能很熟悉。这并非巧合:这是相同的底层技术。我们相信这是智能体策略的正确抽象层次,这一信念贯穿于我们在 Strands Box 中做出的所有设计决策。
让我们先看看为什么语义策略很重要。为此,我们需要问为什么我们要构建智能体。我们构建智能体,是因为它们能够实现开放式或模糊的目标,找到动态路径来解决问题,而无需预设解决方案。如果我们有清晰、明确的流程可遵循,我们就不会构建智能体。我们会节省时间和 token,转而构建工作流。
这正是约束智能体的核心矛盾:我们既想利用智能体在动态解决问题方面的优势、它们探索和尝试的能力以及灵活性,同时又想为智能体所能做的事情设定清晰的边界,并以确定且安全的方式强制执行这些边界。如果边界太紧,智能体就会变得能力不足、用处不大。如果边界太松,智能体就可能在其环境中做出意料之外且不受欢迎的事情。要为每个智能体找到合适的平衡点,我们需要一种强大、富有表现力且精确的策略设定方式。Dogwood 恰好完美契合。
让我们深入探究 Strands Box 在底层是如何工作的,然后再来看看这些决策是如何从策略中产生的。

从本质上讲,Strands Box 是一个由内核强制执行的沙箱,使用与许多其他沙箱方案相同的操作系统提供的机制。我们使用这些机制的方式与大多数其他方案不同:我们不是在操作系统沙箱层应用策略,而是用它把所有与系统和工具的交互都汇聚到专门的策略层。换句话说,沙箱机制确保策略层是离开这个盒子的唯一出口。这使我们能够把策略层放在用户空间,并实现系统感知、协议感知和语言感知的策略。
我们扩展了 Strands Shell,让你能够针对智能体在 Dogwood 中可以运行的 shell 脚本表达策略,并扩展了 Pydantic 的 Monty,为 Python 脚本实现同样的能力。这同样适用于 MCP 工具、文件系统访问和网络访问。例如,下面这条策略强制要求:自上次 git add 以来,git push 之前必须有一次成功的 npm test,且必须在最近 15 分钟内:
forbid (principal, action == Box::Action::"shell:spawn", resource)
when { context.input.program == "git" && context.input has arg1 && context.input.arg1 == "push" }
unless temporal {
(!Box::Action::"shell:spawn"::response{ input.program: "git", input.arg1: "add" }
since within 15m
Box::Action::"shell:spawn"::response{ input.program: "npm", input.arg1: "test", input.arg_count: 1, input.cwd: "~/my-project", output.status: 0 })
};
这不是一条完整的策略(例如,git switch 可能会打破“只有经过测试的代码才会被提交”这一承诺),但它展示了可以实现什么。Dogwood 允许编写完整的策略,把你想做的所有操作都列入允许清单,并阻止所有你不想做的操作。下面是另一个例子,将智能体限制为每小时最多调用 AWS MCP 服务器 60 次。
forbid (principal, action == Box::Action::"mcp:call", resource)
when { context.input.server == "aws" && context.input.method == "tools/call" }
when temporal {
exists (n: Long). (
(count for (t: Timepoint). where (
formerly within 1h (
Box::Action::"mcp:call"::request{ input.server: "aws", input.method: "tools/call" } && tp(t)
)
)) == n
&& n >= 60
)
};
这类做法对于付费 API、需要在多个智能体之间共享固定配额的 API,或者仅仅是为了防止意外账单,都很有用。
你读到这些示例时的第一反应可能是它们难以理解、难以编写。这是我们未来几个月重点投入的领域。我们希望让你能够轻松编写、维护和理解所需的策略。不过,今天的好消息是,前沿编程智能体已经非常擅长读写 Dogwood,无需特殊技能或插件。
构建沙箱的方式有很多种
对不受信任以及部分受信任的工作负载进行沙箱隔离,是计算领域的一个经典问题。自 20 世纪 60 年代大型机加入内存保护,随后 20 世纪 70 年代和 80 年代微处理器 CPU 跟进以来,系统构建者一直在发明隔离工作负载的新方法。对于一个有 60 年先例的问题来说,方案自然不少。让我们深入探讨其中几种,看看它们对我们能表达的策略意味着什么。
首先,我们从硬件支持的虚拟化开始。这里最明显的方法是从 MicroVM 入手,比如 Firecracker,就像我们在 AWS Lambda 和 AgentCore Runtime 中所做的那样。MicroVM 具有出色的安全态势、小巧的可信计算基以及卓越的性能。这种安全态势的一个关键部分来自限制不受信任的客户机与受信任的主机之间的交互,仅实现一小组协议。这些协议允许主机(通常是主机 VMM 进程)与客户机内核协作,假装实现硬盘或网卡等硬件。这种方法在性能和最小化 TCB 方面非常出色,但在策略方面却不尽如人意。
例如,一旦深入到网卡层面,你在网络上看到的基本上都是 TLS 密文(可能偶尔还有 DNS 请求,取决于 DNS 的配置方式)。TLS 社区花了很长时间,恰恰让我们想做的事情——拆解请求并查看其内部——变得非常困难。硬盘的情况稍微容易一些,通常是明文,但在这个层面上,你看到的大多是“在偏移 X 处读取 N 个字节”或“在偏移 Y 处写入这些字节”。你可以仔细逆向工程这些请求来弄清客户机操作系统在做什么,但这会非常繁琐、高度依赖状态,而且很可能很脆弱。设备模拟是实现丰富策略的尴尬之地,但却是实现最可信的粗粒度策略(例如所有网络请求都必须发往此网关,阻止其他所有请求)的绝佳之地。
其次,让我们上升到系统调用层面,容器安全机制通常就位于这一层。这一层有更多的灵活性(尤其是借助 SECCOMP_RET_USER_NOTIF 以及 macOS 27 新的 Endpoint Security 之类的东西),并且能获得关于进程正在做什么的更多语义信息。在文件系统层面,你会看到诸如打开此文件或写入此文件之类的操作;在网络层面,你会看到诸如监听此端口或连接到此主机之类的操作。在这一层编写丰富的策略更容易,无需跟踪大量状态。这几乎是实现诸如“代理可以读取此路径中的文件,但不能写入它们”这类策略的完美之地。不过,在网络方面,你可能仍然只能看到密文,并且能表达的内容有限。这一层的另一个挑战是系统调用接口庞大且不断增长,造成了持续的兼容性挑战。允许列表最安全,但需要随着应用程序使用新的内核特性而不断增长,以避免兼容性问题。拒绝列表安全性较低,并且需要随着内核添加可能允许沙箱逃逸的接口而增长。另一个问题是,过滤系统调用是一种笨拙的机制,使得某些功能难以实现,虽然可以修改系统调用本身,但这并不可靠(至少在 Linux 上如此,它会导致潜在的 TOCTOU 问题)。
一些沙箱,尤其是 gVisor,通过假装成内核、模拟系统调用而不是试图过滤它们,已经解决了其中一部分问题。这种方法已被证明非常有效,但仍未达到足够高的语义层次,无法实现我们想要的那么丰富的策略。在这个层次上,我们可以打开 execve 及其同类,在 git 调用上实施策略,但在 MCP 调用上实施语义策略会困难得多。
因此,对于 Strands Box,我们选择了双管齐下的方法。使用内核级隔离机制进行隔离,并通过只提供一条离开沙箱的路径——即通过策略层——来拦截与外部世界的交互。这使我们能够看到 MCP 请求、shell 程序、Python 程序、文件系统和网络访问,并对它们应用策略。
天下没有免费的午餐
虽然我们相信我们的方法是应对从客户那里听到的现实世界智能体隔离挑战的正确方法,但这一领域的所有选项都伴随着权衡。特别是,Strands Box 需要信任更多代码(安全人士会称之为可信计算基),包括解释器和协议拦截器等复杂代码。我们用 Rust 构建了这些代码,并在测试、模糊测试和验证方面进行了投入,以提高安全性。但现实是,更多代码意味着更多出现 bug 的机会,而在这个领域,bug 可能意味着策略被绕过。
我们将继续深入投入,以简化、测试和验证 Box 的安全模型。但对于云中的多租户部署,我们建议将其与专用的每会话 MicroVM 搭配使用。最简单的方法是使用 AgentCore Runtime,只需在 AgentCore 智能体中运行 Box。但你也可以在 EC2、Lambda 或 Fargate 上构建相同的架构。这种方法允许你在 Box 上本地设置最细粒度的策略,使用 AgentCore Policy 实施工具调用策略,并在智能体的不同会话之间建立强大的 MicroVM 边界。
更大的图景
Strands Box 是 AWS 在智能体安全、策略和隔离方面长期投资旅程中的最新一步。我们正在继续深入投资这一领域,包括在 AWS 云内的 Bedrock 和 AgentCore 等服务中,以及在开源领域通过 Dogwood、Strands 和其他即将推出的产品。凭借二十年来在虚拟化与工作负载隔离方面的持续投资和专业知识,以及十多年来在自动推理和计算数学基础方面的深入投入,我们对能够带来的专业知识以及未来的路线图感到非常兴奋。
我们在此最引以为豪的创新是将本地语义策略引入智能体,包括通过生成代码来调用工具的智能体。我们相信这是智能体治理的一项关键能力,因此我们将其开源,邀请大家在我们投入的基础上继续构建。
来源:Hacker News · strandsagents.com