沙盒客户端
本页帮助您选择沙盒任务的运行环境。在大多数情况下,SandboxAgent 定义保持不变,只需在 sandbox 运行选项中更改沙盒客户端及其专属选项。
| 目标 | 首选方案 | 原因 |
|---|---|---|
| 在 macOS 或 Linux 上进行可信的本地开发 | UnixLocalSandboxClient | 使用受管理的工作区运行宿主机进程;不提供额外的操作系统级隔离。 |
| 基本容器隔离 | DockerSandboxClient | 使用指定镜像在 Docker 内运行任务。 |
| 托管执行 | 托管沙盒客户端 | 使用提供商管理的环境;隔离程度取决于提供商和配置。 |
对于大多数用户,建议从以下两个沙盒客户端中选择一个:
| 客户端 | 安装要求 | 适用场景 |
|---|---|---|
UnixLocalSandboxClient | 无 | 在 macOS 或 Linux 上进行可信的本地开发,或在外部隔离的环境中执行任务。 |
DockerSandboxClient | 本地可用的 Docker CLI | 需要容器隔离,或希望使用指定镜像保持本地环境的一致性。 |
UnixLocalSandboxClient 在 macOS 和 Linux 上将 shell 命令作为宿主机进程运行,包括使用 PTY 的命令。该客户端不提供额外的操作系统级文件系统或网络隔离。命令以所选宿主机用户的权限运行,并受外部强制实施的隔离措施约束。工作区目录、命令工作目录和 HOME 环境变量不会将命令限制在工作区内。
每个新的 Unix 本地会话都会获得独立的临时工作区。Manifest.root 是一个逻辑路径,workspaceBaseDir 用于选择临时工作区的父目录。即使为这些设置使用相同的值,新创建的会话也不会共享工作区。复用仍在运行的会话会共享该会话的工作区。独立的 Unix 本地会话和工作区并不构成操作系统级隔离边界。
Unix 本地路径授权限制受支持的宿主机源路径访问和 SDK 文件 API 的操作。readOnly 授权会阻止 SDK 文件 API 向获授权的路径写入;该授权不会限制任意 shell 命令。即使没有路径授权,命令也可以访问进程权限和外部隔离措施所允许的宿主机路径。请参阅清单路径授权。
对于不可信的命令,包括受不可信输入影响的命令,请选择经过适当配置的 DockerSandboxClient 或托管后端,或提供外部隔离措施。请根据应用所需的文件系统、网络和进程隔离级别选择后端及其配置。
要从 Unix 本地客户端切换到 Docker,请保持智能体定义不变,仅更改客户端:
import { run } from '@openai/agents';import { SandboxAgent } from '@openai/agents/sandbox';import { DockerSandboxClient } from '@openai/agents/sandbox/local';
const agent = new SandboxAgent({ name: 'Workspace reviewer', model: 'gpt-5.6-sol', instructions: 'Inspect the sandbox workspace before answering.',});
const result = await run(agent, 'Inspect the workspace.', { sandbox: { client: new DockerSandboxClient({ image: 'node:22-bookworm-slim' }), },});
console.log(result.finalOutput);同一个智能体通常可以使用任一本地客户端运行:
import { DockerSandboxClient, UnixLocalSandboxClient,} from '@openai/agents/sandbox/local';
const client = process.env.USE_DOCKER ? new DockerSandboxClient({ image: 'node:22-bookworm-slim' }) : new UnixLocalSandboxClient();DockerSandboxClient 使用 Docker 的默认网络配置,除非您在客户端构造函数或每次运行的 sandbox.options 中设置 networkMode: 'none'。'none' 模式会在启动容器时禁用网络。该模式不能与 exposedPorts 一起使用;SDK 会在创建或恢复容器之前拒绝此配置。目前不支持显式设置其他 networkMode 值。
在 DockerSandboxClient 构造函数或每次运行的 sandbox.options 中设置 labels: Record<string, string>,可为创建的容器应用用户自定义标签。每次运行的 labels 记录会替换构造函数中的记录,而不是与其合并。SDK 会拒绝非字符串值,并保留 openai-agents-sandbox、openai-agents-sandbox.session-identity 和 openai-agents-sandbox.mount-authority-fingerprint,用于自身的归属检查。
SDK 会将用户自定义标签复制到序列化的 Docker 会话状态中。当您显式恢复该状态时,调用方提供的标签必须与持久化的标签记录完全一致;如需更改标签,请启动新的沙盒会话。复用仍在运行的容器时,也会验证每个已配置标签是否仍具有所需的值。在 SDK 之外添加的无关标签不会阻止复用。
会话生命周期有两种管理方式。
| 方式 | 传入内容 | 会话关闭方 | 适用场景 |
|---|---|---|---|
| SDK 管理 | sandbox: { client } | 运行器 | 沙盒只需在一次运行期间存在。 |
| 开发者管理 | sandbox: { session } | 您的代码 | 需要在运行后检查文件、复用同一个仍在运行的会话,或协调多次运行。 |
正常完成或失败时,运行器会关闭由 SDK 管理的会话。当运行因等待审批而中断,或尚未完成的流式运行被取消时,运行器会改为将所管理的沙盒状态保存在 RunState 中,以便继续同一次运行。
自行创建会话时,也需要自行关闭:
import { run } from '@openai/agents';import { Manifest, SandboxAgent } from '@openai/agents/sandbox';import { UnixLocalSandboxClient } from '@openai/agents/sandbox/local';
const manifest = new Manifest();const agent = new SandboxAgent({ name: 'Workspace reviewer', model: 'gpt-5.6-sol', instructions: 'Inspect the sandbox workspace before answering.',});
const client = new UnixLocalSandboxClient();const session = await client.create({ manifest });
try { await run(agent, 'First pass.', { sandbox: { session } }); await run(agent, 'Follow-up pass.', { sandbox: { session } });} finally { await session.close?.();}沙盒状态与对话状态相互独立:
- SDK 对话状态保存在
result.history、SDKSession、conversationId或previousResponseId中。 - 沙盒状态保存在仍在运行的沙盒会话、序列化的
sessionState、RunState沙盒载荷或快照中。
如果希望通过沙盒客户端重新连接到同一个后端会话,请使用 sessionState。如果希望基于已保存的工作区内容初始化新会话,请使用快照。
import { Manifest } from '@openai/agents/sandbox';import { UnixLocalSandboxClient } from '@openai/agents/sandbox/local';
const manifest = new Manifest();const client = new UnixLocalSandboxClient({ snapshot: { type: 'local', baseDir: '/tmp/my-sandbox-snapshots' },});
const session = await client.create({ manifest });const state = await client.serializeSessionState?.(session.state);await session.close?.();
if (state) { const restored = await client.resume?.( await client.deserializeSessionState!(state), ); await restored?.close?.();}在暂停或恢复更大范围的工作流时,RunState 也可以保留由运行器管理的沙盒状态。当沙盒生命周期在序列化运行之外管理时,请显式使用 sessionState。
对于 Docker,恢复内存中的同一个 RunState 时,只有在 SDK 验证容器身份并重新验证当前清单、环境和路径授权后,才能复用仍在运行的容器。如果无法复用或复用被拒绝,Docker 会回退到可恢复的快照。经过序列化并通过 RunState.fromString(...) 重建的 RunState 不包含可信的运行中容器授权信息,因此 Docker 也会从快照恢复,而不是连接到序列化状态中的容器 ID。如果未配置可恢复的快照,恢复会失败,而不会连接到未经验证的容器。
对于未显式指定 baseDir 的本地快照,可以设置 OPENAI_AGENTS_SANDBOX_SNAPSHOT_DIR 来覆盖存储目录。否则,SDK 在 macOS 上使用 ~/Library/Application Support/openai-agents-js/sandbox-snapshots,在 Windows 上使用 %LOCALAPPDATA%\openai-agents-js\sandbox-snapshots,在其他平台上使用 $XDG_STATE_HOME/openai-agents-js/sandbox-snapshots;当这些位置不可用时,会回退到主目录或临时目录。
清单条目会在智能体运行之前准备就绪。您可以为每次运行或每次客户端创建调用调整物化并发度:
import { run } from '@openai/agents';import { SandboxAgent } from '@openai/agents/sandbox';import { UnixLocalSandboxClient } from '@openai/agents/sandbox/local';
const agent = new SandboxAgent({ name: 'Repository inspector', model: 'gpt-5.6-sol', instructions: 'Inspect the repository before answering.',});
await run(agent, 'Inspect the repo.', { sandbox: { client: new UnixLocalSandboxClient(), concurrencyLimits: { manifestEntries: 4, localDirFiles: 16, }, },});manifestEntries 限制顶层条目的并行处理数量。localDirFiles 限制 localDir() 条目内的文件复制并发度。
文件系统存在性检查
Section titled “文件系统存在性检查”当会话实现 pathExists() 时,false 表示后端已确认路径不存在。权限错误、I/O 故障和提供商探测失败会导致调用以提供商错误拒绝,而不会被视为路径不存在。这样可以防止编辑器、清单和记忆流程覆盖或替换可能存在但无法访问的路径。
挂载与远程存储
Section titled “挂载与远程存储”挂载条目描述要暴露哪些存储;挂载策略描述沙盒后端如何连接这些存储。请从 @openai/agents/sandbox 导入内置挂载条目和通用策略。
常用挂载选项:
mountPath:存储在沙盒中呈现的位置。相对路径基于清单根目录解析;绝对路径按原样使用。readOnly:如果不希望沙盒向挂载的存储写回数据,请设置此选项。mountStrategy:使用同时匹配挂载条目和沙盒后端的策略。
挂载被视为临时工作区条目。快照和持久化流程会分离或跳过挂载路径,而不会将挂载的远程存储复制到保存的工作区中。
通用本地/容器策略:
| 策略或模式 | 适用场景 | 说明 |
|---|---|---|
inContainerMountStrategy(...) | 沙盒镜像可以运行 rclone、mount-s3 或 blobfuse2 等挂载命令。 | 作为通用策略提供;是否支持取决于后端。 |
dockerVolumeMountStrategy(...) | 需要 Docker 在容器启动之前连接由卷驱动支持的挂载。 | 仅适用于 Docker。 |
localBindMountStrategy() | 需要本地后端将绝对本地路径绑定到工作区中。 | 在允许的情况下,由本地工作区物化机制支持。 |
后端支持范围刻意做了明确划分:
| 后端 | 挂载说明 |
|---|---|
UnixLocalSandboxClient | 通过本地工作区模型支持本地绑定式挂载。 |
DockerSandboxClient | 在 Docker 可以连接存储的情况下,支持本地绑定挂载和 Docker 卷式策略。 |
| 托管提供商 | 提供商专属策略随各提供商实现一同提供。请查阅该提供商的文档,了解支持的挂载和所需配置。 |
不要假定一个挂载条目适用于所有后端。如果客户端无法落实清单元数据、身份或挂载行为,应尽早失败,而不是静默忽略清单中的相应部分。
支持的托管平台
Section titled “支持的托管平台”当您需要托管环境时,通常可以沿用同一个 SandboxAgent 定义,只需在 sandbox 运行选项中更改沙盒客户端。
托管提供商实现可通过 @openai/agents-extensions 的提供商子路径获取。请查阅提供商文档,了解具体的环境变量、可运行的代码示例、端口行为、PTY 支持、快照行为和清理行为。
安装 @openai/agents-extensions 并满足其包级对等依赖要求。各提供商还可能要求安装提供商 SDK 包或进行后端配置:
| 客户端 | 导入路径 | 提供商要求 |
|---|---|---|
BlaxelSandboxClient | @openai/agents-extensions/sandbox/blaxel | npm 对等依赖:@blaxel/core |
CloudflareSandboxClient | @openai/agents-extensions/sandbox/cloudflare | Cloudflare Sandbox 桥接 Worker URL 和 Worker 身份验证 |
DaytonaSandboxClient | @openai/agents-extensions/sandbox/daytona | npm 对等依赖:@daytonaio/sdk |
E2BSandboxClient | @openai/agents-extensions/sandbox/e2b | npm 对等依赖:e2b 或 @e2b/code-interpreter |
ModalSandboxClient | @openai/agents-extensions/sandbox/modal | npm 对等依赖:modal |
VercelSandboxClient | @openai/agents-extensions/sandbox/vercel | npm 对等依赖:@vercel/sandbox |
使用 ModalSandboxClient 创建沙盒时,可通过 cpu 和 memoryMiB 请求预留 CPU 和内存,通过 cpuLimit 和 memoryLimitMiB 设置上限。您可以在客户端构造函数或每次运行的 sandbox.options 中设置这些选项;每次运行的值会覆盖构造函数默认值。所有值都必须是有限正数。设置 cpuLimit 时必须同时设置 cpu,且前者不能低于后者;设置 memoryLimitMiB 时必须同时设置 memoryMiB,且前者不能低于后者。
CloudflareSandboxClient 不会导入 Cloudflare npm SDK,而是通过 HTTP 与已部署的 Cloudflare Sandbox 桥接 Worker 通信。
VercelSandboxClient 按照每次创建的选项、构造函数选项、环境变量 VERCEL_PROJECT_ID、VERCEL_TEAM_ID 和 VERCEL_TOKEN 的优先级,解析各个 PAT 凭据字段。只有解析得到的 projectId、teamId 和 token 均非空时,才会转发凭据。否则,它会省略这三个字段,让 @vercel/sandbox 自行解析身份验证方式,包括平台 OIDC 或本地提供商凭据。会话序列化和恢复时,会保留完整的已解析凭据。序列化凭据会被视为完整的三元组,不会与当前选项或环境变量混用;不完整的序列化凭据会被丢弃,然后回退到解析当前配置。由于令牌仍保留在序列化的会话状态中,请安全地存储该状态。
托管沙盒客户端提供各自的提供商专属挂载策略。请选择最适合您的存储提供商的后端和挂载策略:
默认情况下,带有凭据且在沙盒内运行辅助程序的挂载会被拒绝,因为模型控制的代码可以访问该辅助程序的进程凭据。这包括通过受支持的挂载字段、环境中的 AWS 或 GCP 环境变量、RCLONE_CONFIG_* 值,以及工作负载身份或托管身份发现机制提供的凭据。不使用凭据的 rclone 和 mountpoint 辅助程序会禁用环境或元数据身份验证,并在后端支持的情况下使用匿名访问。建议优先使用外部或提供商原生策略,例如 Docker 卷、Modal 云存储桶或 Cloudflare 存储桶挂载。
如果必须使用沙盒内辅助程序,请在应用创建的清单上,逐一确认每个可信的实际挂载路径。对于通过类型化挂载字段直接提供的挂载范围凭据,请使用 manifest.withInContainerMountCredentialExposureAcknowledged('mounted/path') 返回的清单。对于环境中的凭据、工作负载身份或托管身份,以及外部凭据或配置文件,则必须使用 manifest.withInContainerMountBroadCredentialExposureAcknowledged('mounted/path') 返回的清单。同时使用这两类授权的挂载需要两种确认。这些针对确切路径的确认仅在运行时有效,绝不接受来自清单初始化对象或序列化清单数据的确认。它们允许所选辅助程序接收凭据,但不会将这些凭据的可访问范围限制在挂载路径内,因此同一沙盒中其他由模型控制的代码仍可能获取这些凭据。请使用作用域限于沙盒、短期有效且遵循最小权限原则的凭据。
挂载引用的凭据文件不得直接或通过符号链接解析到可序列化的清单条目。动态清单变更按会话串行执行;如果特权挂载转换或替换过程中的卸载在提供商操作可能已生效后失败,SDK 会使该会话失效并将其终止,而不是复用或持久化不确定的状态。
序列化沙盒状态会省略挂载凭据,包括沙盒内挂载辅助程序选用的环境凭据。任何持久化的挂载拓扑在恢复前都需要当前可信的清单。对于可恢复的外部或提供商原生挂载,只有当前挂载拓扑与持久化挂载拓扑在去除凭据后相匹配,SDK 才会恢复凭据。只有在未脱敏的活跃授权信息仍与当前可信清单匹配时,显式传入的 sessionState 才能重新连接已有的提供商原生挂载;如果授权信息已脱敏、轮换或移除,则需要新的沙盒。无法拆分出不含凭据的拓扑的不透明配置不可恢复。当 Runner 恢复使用过沙盒内挂载辅助程序的序列化 RunState 条目时,会丢弃已存储的会话,并根据当前可信配置创建新的沙盒。调用方显式提供的 sessionState 和直接通过提供商恢复的方式则会拒绝容器内挂载状态;请显式启动新的沙盒。
| 后端 | 挂载说明 |
|---|---|
| Docker | 支持通过 inContainerMountStrategy() 和 dockerVolumeMountStrategy() 等本地策略使用 s3Mount()、gcsMount()、r2Mount()、azureBlobMount()、boxMount() 和 s3FilesMount()。 |
ModalSandboxClient | 支持在 S3、R2 和使用 HMAC 身份验证的 GCS 挂载条目上,通过 ModalCloudBucketMountStrategy 挂载云存储桶。 |
CloudflareSandboxClient | 支持在 S3、R2 和使用 HMAC 身份验证的 GCS 挂载条目上,通过 CloudflareBucketMountStrategy 进行 Cloudflare 存储桶挂载。 |
BlaxelSandboxClient | 支持在 S3、R2 和 GCS 挂载条目上,通过 BlaxelCloudBucketMountStrategy 挂载云存储桶。带有凭据的云挂载需要由 SDK 管理的沙盒;复用不归 SDK 管理的命名沙盒时,可以使用不带凭据的云挂载,或通过 BlaxelDriveMount 和 BlaxelDriveMountStrategy 使用持久化 Blaxel Drives。 |
DaytonaSandboxClient | 支持在 S3、GCS、R2、Azure Blob 和 Box 挂载条目上,通过 DaytonaCloudBucketMountStrategy 进行基于 rclone 的挂载。 |
E2BSandboxClient | 支持在 S3、GCS、R2、Azure Blob 和 Box 挂载条目上,通过 E2BCloudBucketMountStrategy 进行基于 rclone 的挂载。 |
VercelSandboxClient | 支持通过 VercelCloudBucketMountStrategy 在创建时进行 S3 挂载。对于新代码,请使用 withInContainerMountCredentialExposureAcknowledged() 为每个确切的挂载路径确认内联凭据暴露风险。已弃用的 allowS3CredentialExposure: true 选项仍可接受,以兼容已发布的内联 S3 凭据配置,但它不会授权使用环境凭据或其他广泛权限。请复用仍在运行的已挂载会话,因为序列化的挂载状态无法直接恢复。 |
对于 E2B 基于 rclone 的挂载,SDK 会在已有 rclone 二进制文件可用时使用它。否则,SDK 仅在验证 SHA-256 校验和后,才会安装 SDK 指定版本的 Linux 归档包;不支持的架构和校验和验证失败都会中止挂载。
下表总结了各后端可以直接挂载的远程存储条目:
| 后端 | AWS S3 | Cloudflare R2 | GCS | Azure Blob Storage | Box | S3 Files |
|---|---|---|---|---|---|---|
| Docker | 是 | 是 | 是 | 是 | 是 | 是 |
ModalSandboxClient | 是 | 是 | 是 | 否 | 否 | 否 |
CloudflareSandboxClient | 是 | 是 | 是 | 否 | 否 | 否 |
BlaxelSandboxClient | 是 | 是 | 是 | 否 | 否 | 否 |
DaytonaSandboxClient | 是 | 是 | 是 | 是 | 是 | 否 |
E2BSandboxClient | 是 | 是 | 是 | 是 | 是 | 否 |
VercelSandboxClient | 是 | 否 | 否 | 否 | 否 | 否 |
“是”表示后端可以执行该类型的存储挂载,并不意味着可以绕过上述凭据边界。Docker 的 dockerVolumeMountStrategy()、Modal 云存储桶挂载和 Cloudflare 存储桶挂载会将挂载凭据保留在模型控制的沙盒之外。Docker 的 inContainerMountStrategy() 以及 Daytona 和 E2B 的 rclone 策略在接收凭据时,都需要针对确切路径进行确认。Box 挂载需要身份验证,因此请根据 Box 授权信息是通过类型化挂载字段,还是通过外部凭据或配置文件提供,选择相应的确认方式。Docker S3 Files 挂载使用广泛的工作负载身份权限,因此需要 withInContainerMountBroadCredentialExposureAcknowledged()。
在后端支持的情况下,沙盒客户端可以通过 resolveExposedPort(port) 暴露端点。
| 客户端 | 行为 |
|---|---|
UnixLocalSandboxClient | 将已配置的端口解析到 127.0.0.1。 |
DockerSandboxClient | 发布已配置的容器端口,并解析其宿主机端点。 |
当您需要后端强制执行允许列表时,请在客户端选项中声明端口:
import { DockerSandboxClient } from '@openai/agents/sandbox/local';
const client = new DockerSandboxClient({ image: 'node:22-bookworm-slim', exposedPorts: [3000],});功能支持矩阵
Section titled “功能支持矩阵”| 功能 | Unix 本地 | Docker |
|---|---|---|
exec_command | 支持 | 支持 |
PTY write_stdin | 支持 | 支持 |
apply_patch | 支持 | 通过工作区文件 API 支持 |
view_image | 支持 | 通过工作区文件 API 支持 |
命令的 runAs | 宿主机能够解析并切换到该用户时支持 | 受容器/用户配置限制 |
| 本地快照 | 支持 | 支持 |
| 本地/Docker 挂载 | 支持本地绑定式挂载 | 支持绑定挂载和 Docker 卷式挂载 |
本地 PTY 支持在 SDK 进程中使用一个小型 Python 3 桥接程序。该桥接程序仅用于 tty: true 会话,因为 Node.js 不提供内置的 PTY API,而 SDK 需要标准 POSIX PTY 行为来实现交互式标准输入、信号处理和退出状态报告。请在运行 SDK 代码的环境中安装 python3,或将 OPENAI_AGENTS_PYTHON 设置为 Python 3 可执行文件的路径。这与 Docker 沙盒镜像中可能安装的 Python 版本无关。
托管提供商的支持情况因提供商而异。请查阅提供商专属文档,了解具体的选项、环境变量、端口行为、PTY 支持、快照行为和清理行为。