沙盒客户端
使用此页面选择沙盒任务的运行位置。在大多数情况下,SandboxAgent 定义保持不变,只需更改 sandbox 运行选项中的沙盒客户端和客户端专属选项。
| 目标 | 入门选择 | 原因 |
|---|---|---|
| 在 macOS 或 Linux 上实现最快的本地迭代 | UnixLocalSandboxClient | 无额外服务依赖,并提供简单的本地文件系统工作流。 |
| 基本容器隔离 | DockerSandboxClient | 使用指定镜像在 Docker 内运行任务。 |
| 托管执行或生产环境风格的隔离 | 托管沙盒客户端 | 将工作区边界移至提供商管理的环境。 |
对于大多数用户,建议从以下两个沙盒客户端之一开始:
| 客户端 | 安装要求 | 适用场景 |
|---|---|---|
UnixLocalSandboxClient | 无 | 在 macOS 或 Linux 上实现最快的本地迭代。适合作为本地开发的默认选项。 |
DockerSandboxClient | 本地可用的 Docker CLI | 需要容器隔离,或需要指定镜像以保持本地环境一致性。 |
Unix-local 是针对本地文件系统开始开发的最简单方式。当您需要更强的环境隔离或与生产环境类似的一致性时,可迁移到 Docker 或托管提供商。
若要从 Unix-local 切换到 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();除非您在客户端构造函数或每次运行的 sandbox.options 中设置 networkMode: 'none',否则 DockerSandboxClient 将使用 Docker 的默认网络。'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,只有在 SDK 验证实时容器的身份,并重新验证当前清单、环境和路径授权之后,恢复同一个内存中的 RunState 才能复用该容器。如果无法复用实时容器或复用请求被拒绝,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 |
RunloopSandboxClient | @openai/agents-extensions/sandbox/runloop | npm 对等依赖:@runloop/api-client |
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 按以下优先级解析每个 PAT 凭据字段:每次创建选项、构造函数选项,然后是 VERCEL_PROJECT_ID、VERCEL_TEAM_ID 和 VERCEL_TOKEN。仅当最终得到的 projectId、teamId 和 token 均非空时,它才会转发凭据。否则,它会省略全部三个字段,并让 @vercel/sandbox 解析身份验证,包括平台 OIDC 或本地提供商凭据。会话序列化和恢复时,会保留完整解析出的凭据。序列化的凭据被视为不可拆分的完整三元组,不会与当前选项或环境变量混合;如果序列化的凭据不完整,则会将其丢弃,然后回退到解析当前配置。由于令牌仍会保留在序列化的会话状态中,请安全存储该状态。
托管沙盒客户端提供提供商专属的挂载策略。请选择最适合您的存储提供商的后端和挂载策略:
默认情况下,系统会拒绝在沙盒内运行辅助程序且携带凭据的挂载,因为模型控制的代码可以访问该辅助程序的进程凭据。这包括通过受支持的挂载字段提供的凭据、环境中已有的 AWS 或 GCP 环境变量、RCLONE_CONFIG_* 值,以及工作负载身份或托管身份发现机制。不带凭据的 rclone 和挂载点辅助程序会禁用环境身份验证或元数据身份验证,并在后端支持时使用匿名访问。应优先采用外部或提供商原生策略,例如 Docker 卷、Modal 云存储桶或 Cloudflare 存储桶挂载。
如果必须使用沙盒内辅助程序,请在应用程序创建的清单中确认每个可信的有效挂载路径。对于通过类型化挂载字段直接提供的挂载级凭据,请使用由 manifest.withInContainerMountCredentialExposureAcknowledged('mounted/path') 返回的清单。对于环境凭据、工作负载身份或托管身份,以及外部凭据或配置文件,请使用由 manifest.withInContainerMountBroadCredentialExposureAcknowledged('mounted/path') 返回的清单。同时使用这两类权限的挂载需要两种确认。这些精确路径确认仅在运行时有效,绝不会从清单初始化对象或序列化清单数据中接受。它们允许选定的辅助程序接收凭据,但不会将凭据限制在挂载路径中,因此同一沙盒内由模型控制的其他代码仍可能获取这些凭据。请使用沙盒范围内、短期且最小权限的凭据。
挂载引用的凭据文件不能直接或通过符号链接解析到可序列化的清单条目。动态清单变更按会话序列化;如果在提供商端的操作可能已经开始后,具有特权的挂载转换或替换卸载失败,SDK 将使该会话失效并终止它,而不会复用或持久化含糊不清的状态。
序列化的沙盒状态会省略挂载凭据,包括沙盒内挂载辅助程序选择的环境凭据。恢复任何已持久化的挂载拓扑之前,都需要当前可信清单。对于可恢复的外部或提供商原生挂载,只有在当前挂载拓扑与已持久化挂载拓扑去除凭据后相匹配时,SDK 才会恢复凭据。仅当未脱敏的实时权限仍与当前可信清单匹配时,显式 sessionState 才能重新连接现有的提供商原生挂载;如果权限已脱敏、轮换或移除,则需要新沙盒。无法将无凭据拓扑分离出来的不透明配置不可恢复。当运行器恢复使用过沙盒内挂载辅助程序的序列化 RunState 条目时,它会丢弃已存储的会话,并根据当前可信配置创建新沙盒。调用方提供的显式 sessionState 和直接提供商恢复操作会改为拒绝容器内挂载状态;请显式启动新沙盒。对于容器内挂载,系统会拒绝通过不透明 secretRefs 提供的 Runloop 凭据文件变量;请通过 managedSecrets 提供当前可信路径,以便 SDK 在挂载前验证其有效路径。
| 后端 | 挂载说明 |
|---|---|
| Docker | 支持将 s3Mount()、gcsMount()、r2Mount()、azureBlobMount()、boxMount() 和 s3FilesMount() 与 inContainerMountStrategy()、dockerVolumeMountStrategy() 等本地策略结合使用。 |
ModalSandboxClient | 支持通过 ModalCloudBucketMountStrategy 挂载 S3、R2 和使用 HMAC 身份验证的 GCS 挂载条目。 |
CloudflareSandboxClient | 支持通过 CloudflareBucketMountStrategy 挂载 S3、R2 和使用 HMAC 身份验证的 GCS 挂载条目。 |
BlaxelSandboxClient | 支持通过 BlaxelCloudBucketMountStrategy 挂载 S3、R2 和 GCS 挂载条目。携带凭据的云挂载要求使用 SDK 所有的沙盒;复用的不受 SDK 所有的命名沙盒可以使用无凭据云挂载,或通过 BlaxelDriveMount 和 BlaxelDriveMountStrategy 使用持久化 Blaxel Drive。 |
DaytonaSandboxClient | 支持通过 DaytonaCloudBucketMountStrategy 挂载由 rclone 支持的 S3、GCS、R2、Azure Blob 和 Box 挂载条目。 |
E2BSandboxClient | 支持通过 E2BCloudBucketMountStrategy 挂载由 rclone 支持的 S3、GCS、R2、Azure Blob 和 Box 挂载条目。 |
RunloopSandboxClient | 支持通过 RunloopCloudBucketMountStrategy 挂载由 rclone 支持的 S3、GCS、R2、Azure Blob 和 Box 挂载条目。 |
VercelSandboxClient | 支持在创建时通过 VercelCloudBucketMountStrategy 挂载 S3。对于新代码,请针对每个精确挂载路径使用 withInContainerMountCredentialExposureAcknowledged() 确认内联凭据。为兼容已发布的内联 S3 凭据配置,已弃用的 allowS3CredentialExposure: true 选项仍可使用,但它不授权环境凭据或其他广泛权限。请复用已挂载的实时会话,因为序列化的挂载状态无法直接恢复。 |
对于由 E2B 和 Runloop 的 rclone 支持的挂载,如果存在 rclone 二进制文件,SDK 会直接使用它。否则,SDK 仅在验证 SHA-256 校验和后,才会安装由 SDK 锁定版本的 Linux 归档文件;不受支持的架构和校验和失败都会中止挂载。
下表汇总了每个后端可以直接挂载的远程存储条目:
| 后端 | AWS S3 | Cloudflare R2 | GCS | Azure Blob Storage | Box | S3 Files |
|---|---|---|---|---|---|---|
| Docker | 是 | 是 | 是 | 是 | 是 | 是 |
ModalSandboxClient | 是 | 是 | 是 | 否 | 否 | 否 |
CloudflareSandboxClient | 是 | 是 | 是 | 否 | 否 | 否 |
BlaxelSandboxClient | 是 | 是 | 是 | 否 | 否 | 否 |
DaytonaSandboxClient | 是 | 是 | 是 | 是 | 是 | 否 |
E2BSandboxClient | 是 | 是 | 是 | 是 | 是 | 否 |
RunloopSandboxClient | 是 | 是 | 是 | 是 | 是 | 否 |
VercelSandboxClient | 是 | 否 | 否 | 否 | 否 | 否 |
“是”表示后端可以执行相应类型的存储挂载;它不会绕过上述凭据边界。Docker 的 dockerVolumeMountStrategy()、Modal 云存储桶挂载和 Cloudflare 存储桶挂载会将挂载凭据保留在模型控制的沙盒之外。每当 Docker 的 inContainerMountStrategy() 以及 Daytona、E2B 和 Runloop 的 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-local | 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 支持、快照行为和清理行为。