跳转到内容

沙盒客户端

使用本页选择沙盒工作应在何处运行。大多数情况下,SandboxAgent 定义保持不变,只需更改 sandbox 运行选项中的沙盒客户端和客户端特定选项。

目标首选方案原因
在 macOS 或 Linux 上进行最快的本地迭代UnixLocalSandboxClient无额外服务依赖,并提供简单的本地文件系统工作流。
基本容器隔离DockerSandboxClient使用指定镜像在 Docker 中运行工作。
托管执行或生产级隔离托管沙盒客户端将工作区边界移至由提供商管理的环境。

对于大多数用户,建议从以下两个沙盒客户端之一开始:

客户端安装要求适用场景
UnixLocalSandboxClient在 macOS 或 Linux 上进行最快的本地迭代。适合作为本地开发的默认选项。
DockerSandboxClient本地可使用 Docker CLI需要容器隔离,或希望通过指定镜像保持本地环境一致性。

Unix 本地客户端是针对本地文件系统开始开发的最简单方式。如果需要更强的环境隔离或生产级环境一致性,请迁移到 Docker 或托管提供商。

若要从 Unix 本地客户端切换到 Docker,请保持智能体定义不变,仅更改客户端:

使用 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();

会话有两种生命周期管理方式。

方式传入内容负责关闭会话的一方适用场景
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、SDK SessionconversationIdpreviousResponseId 中。
  • 沙盒状态存放在活动沙盒会话、序列化的 sessionStateRunState 沙盒载荷或快照中。

如果希望通过沙盒客户端重新连接到同一个后端会话,请使用 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() 条目中的文件复制并发数。

当会话实现 pathExists() 时,false 表示后端已确认该路径不存在。权限错误、I/O 故障和提供商探测失败会以提供商错误拒绝请求,而不会被视为路径不存在。这样可避免编辑器、清单和记忆流程覆盖或替换可能存在但无法访问的路径。

挂载条目描述要公开哪些存储,挂载策略描述沙盒后端如何连接这些存储。从 @openai/agents/sandbox 导入内置挂载条目和通用策略。

常用挂载选项:

  • mountPath:存储在沙盒中的显示位置。相对路径基于清单根目录解析;绝对路径按原样使用。
  • readOnly:当沙盒不应向挂载的存储写回数据时设置此项。
  • mountStrategy:使用同时匹配挂载条目和沙盒后端的策略。

挂载会被视为临时工作区条目。快照和持久化流程会分离或跳过挂载路径,而不会将已挂载的远程存储复制到保存的工作区中。

通用本地/容器策略:

策略或模式适用场景说明
inContainerMountStrategy(...)沙盒镜像可以运行 rclonemount-s3blobfuse2 等挂载命令。作为通用策略提供;是否支持取决于后端。
dockerVolumeMountStrategy(...)Docker 应在容器启动前连接由卷驱动程序支持的挂载。仅限 Docker。
localBindMountStrategy()本地后端应将绝对本地路径绑定到工作区中。在允许的情况下,受本地工作区物化机制支持。

后端支持范围会明确界定:

后端挂载说明
UnixLocalSandboxClient通过本地工作区模型支持本地绑定式挂载。
DockerSandboxClient在 Docker 能够连接存储的情况下,支持本地绑定挂载和 Docker 卷式策略。
托管提供商提供商特定策略随各提供商实现一起提供。请查阅相应提供商的文档,了解支持的挂载和必要设置。

不要假定一个挂载条目能在所有后端上工作。如果客户端无法强制执行清单元数据、身份或挂载行为,应尽早失败,而不是默默忽略清单的相应部分。

当需要托管环境时,通常可以沿用相同的 SandboxAgent 定义,只需更改 sandbox 运行选项中的沙盒客户端。

托管提供商实现可从 @openai/agents-extensions 的提供商子路径中获得。请查阅提供商文档,了解确切的环境变量、可运行示例、端口行为、PTY 支持、快照行为和清理行为。

安装 @openai/agents-extensions 并满足其包级对等依赖。每个提供商可能还需要相应的提供商 SDK 包或后端设置:

客户端导入路径提供商要求
BlaxelSandboxClient@openai/agents-extensions/sandbox/blaxelnpm 对等依赖:@blaxel/core
CloudflareSandboxClient@openai/agents-extensions/sandbox/cloudflareCloudflare Sandbox 桥接 Worker URL 和 Worker 身份验证
DaytonaSandboxClient@openai/agents-extensions/sandbox/daytonanpm 对等依赖:@daytonaio/sdk
E2BSandboxClient@openai/agents-extensions/sandbox/e2bnpm 对等依赖:e2b@e2b/code-interpreter
ModalSandboxClient@openai/agents-extensions/sandbox/modalnpm 对等依赖:modal
RunloopSandboxClient@openai/agents-extensions/sandbox/runloopnpm 对等依赖:@runloop/api-client
VercelSandboxClient@openai/agents-extensions/sandbox/vercelnpm 对等依赖:@vercel/sandbox

CloudflareSandboxClient 不会导入 Cloudflare npm SDK,而是通过 HTTP 与已部署的 Cloudflare Sandbox 桥接 Worker 通信。

VercelSandboxClient 按以下优先级解析每个 PAT 凭据字段:每次创建时的选项、构造函数选项,然后是 VERCEL_PROJECT_IDVERCEL_TEAM_IDVERCEL_TOKEN。仅当最终得到的 projectIdteamIdtoken 均非空时,它才会转发凭据。否则,它会省略所有三个字段,并让 @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 所有的沙盒;复用的非自有命名沙盒可以使用无凭据云挂载,或通过 BlaxelDriveMountBlaxelDriveMountStrategy 使用持久化 Blaxel Drive。
DaytonaSandboxClient支持通过 DaytonaCloudBucketMountStrategy 对 S3、GCS、R2、Azure Blob 和 Box 挂载条目进行基于 rclone 的挂载。
E2BSandboxClient支持通过 E2BCloudBucketMountStrategy 对 S3、GCS、R2、Azure Blob 和 Box 挂载条目进行基于 rclone 的挂载。
RunloopSandboxClient支持通过 RunloopCloudBucketMountStrategy 对 S3、GCS、R2、Azure Blob 和 Box 挂载条目进行基于 rclone 的挂载。
VercelSandboxClient支持通过 VercelCloudBucketMountStrategy 在创建时挂载 S3。对于新代码,请针对每个精确挂载路径使用 withInContainerMountCredentialExposureAcknowledged() 确认内联凭据。已弃用的 allowS3CredentialExposure: true 选项仍可用于兼容已发布的内联 S3 凭据配置,但它不授权环境凭据或其他广泛权限。请复用活动的已挂载会话,因为序列化的挂载状态无法直接恢复。

对于 E2B 和 Runloop 基于 rclone 的挂载,SDK 会在可用时使用现有的 rclone 二进制文件。否则,只有在验证 SHA-256 校验和后,它才会安装由 SDK 固定版本的 Linux 归档文件;不受支持的架构和校验和验证失败会中止挂载。

下表概述了每个后端可以直接挂载的远程存储条目:

后端AWS S3Cloudflare R2GCSAzure Blob StorageBoxS3 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],
});
功能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 支持、快照行为和清理行为。