跳转到内容

概念

现代智能体在能够对文件系统中的真实文件进行操作时效果最佳。Sandbox Agents 可以使用专门的工具和 shell 命令,对大型文档集进行搜索与操作、编辑文件、生成产物并运行命令。沙盒为模型提供了一个持久化工作区,智能体可以利用它代表您完成工作。Agents SDK 中的 Sandbox Agents 可帮助您运行与沙盒环境配对的智能体,让文件以合适的方式进入文件系统,并能够大规模编排沙盒以启动、停止和恢复任务。

您可以围绕智能体所需的数据来定义工作区。它可以从 GitHub 仓库、本地文件和目录、合成任务文件、远程文件系统(如 S3 或 Azure Blob Storage)以及您提供的其他沙盒输入开始。

带计算能力的沙盒智能体控制层

SandboxAgent 扩展自 Agent,因此它仍然是一个 Agent。它保留了常见的智能体接口,例如 instructionstoolshandoffsmcpServersmodelSettings、输出类型、护栏和 hooks,并且仍通过常规的 run()Runner API 运行。变化之处在于执行边界:

  • SandboxAgent 定义智能体本身:除了常规智能体配置外,还包括沙盒特有的默认值,如 defaultManifestbaseInstructionsrunAs,以及文件系统工具、shell 访问、技能、记忆或压缩等能力。
  • Manifest 声明全新沙盒工作区期望的初始内容和布局,包括文件、仓库、挂载和环境。
  • 沙盒会话是命令运行和文件发生变化的实时执行环境。
  • sandbox 运行选项决定本次运行如何获取该沙盒会话,例如直接注入一个会话、从序列化的沙盒会话状态重新连接,或通过沙盒客户端创建一个新的沙盒会话。
  • 已保存的沙盒状态和快照允许后续运行重新连接到先前的工作,或使用已保存的内容为新的沙盒会话提供初始数据。

Manifest 定义新沙盒工作区的初始内容。它并不描述每个实时沙盒中的当前文件,因为复用的会话、序列化的会话状态和快照都可能在运行时提供或更改工作区。

在本页中,“沙盒会话”指由沙盒客户端管理的实时执行环境。具体边界取决于客户端:Unix 本地会话在主机上的本地工作区中运行,而 Docker 和托管客户端提供更强的环境隔离。这与 会话 中描述的 SDK 对话式 Session 接口不同。

外层运行时仍负责审批、追踪、交接和恢复相关记录。沙盒会话负责命令、文件变更和环境隔离。这种分工是该模型的核心部分。

一次沙盒运行会将智能体定义与每次运行的沙盒配置结合起来。运行器会准备智能体,将其绑定到一个实时沙盒会话,并可以为后续运行保存状态。

SandboxAgent智能体加沙盒默认值
Runner准备 instructions 并绑定能力工具
沙盒会话命令运行和文件变化发生的工作区
已保存状态稍后恢复,或为新工作区提供初始数据

沙盒特有的默认值保留在 SandboxAgent 上。每次运行的沙盒会话选择保留在 sandbox 运行选项中。

可以将生命周期理解为三个阶段:

  1. 使用 SandboxAgentManifest 和能力定义智能体及工作区初始内容。
  2. 通过为 run()Runner 提供 sandbox 运行选项来执行一次运行,该选项可注入、恢复或创建沙盒会话。
  3. 之后可基于运行器管理的 RunState、显式的沙盒 sessionState 或已保存的工作区快照继续。

如果 shell 访问只是偶尔使用的一种工具,请先从工具指南中的托管 shell 开始。当工作区隔离、沙盒客户端选择或沙盒会话恢复行为本身就是设计的一部分时,再使用沙盒智能体。

沙盒智能体非常适合以工作区为中心的工作流,例如:

  • 编码与调试:为 GitHub 仓库中的问题报告编排自动修复,并运行有针对性的测试。
  • 文档处理与编辑:从用户的财务文档中提取信息,并创建填好的税表草稿。
  • 基于文件的审查或分析:在回答前检查入职材料、生成的报告或产物包。
  • 隔离的多智能体模式:为每个审查者或编码子智能体提供各自独立的工作区。
  • 多步骤工作区任务:在一次运行中修复 bug,稍后再添加回归测试,或从快照或沙盒会话状态恢复。

如果您不需要访问文件或活动的文件系统,请继续使用 Agent。如果 shell 访问只是偶尔需要的一项能力,可添加托管 shell;如果工作区边界本身是功能的一部分,则应使用沙盒智能体。

本地开发时,先使用 UnixLocalSandboxClient。当您需要容器隔离或镜像一致性时,切换到 DockerSandboxClient。当您需要由提供方管理执行环境时,切换到托管提供方。

在大多数情况下,SandboxAgent 定义保持不变,只需在 sandbox 运行选项中更改沙盒客户端及其选项。有关本地、Docker、托管和远程挂载选项,请参阅沙盒客户端

主要 SDK 组件它回答的问题
智能体定义SandboxAgentManifest、capabilities将运行什么智能体,以及它应从什么样的全新会话工作区契约开始?
沙盒执行sandbox 运行选项、沙盒客户端和实时沙盒会话这次运行如何获得一个实时沙盒会话,工作又在哪里执行?
已保存的沙盒状态RunState 沙盒负载、sessionState 和快照该工作流如何重新连接到先前的沙盒工作,或从已保存内容为全新沙盒会话提供初始数据?

主要 SDK 组件与这些层的对应关系如下:

组件它负责什么请问自己这个问题
SandboxAgent智能体定义这个智能体应该做什么,哪些默认值应该随它一起携带?
Manifest全新会话工作区中的文件和文件夹运行开始时,文件系统中应该有哪些文件和文件夹?
Capability沙盒原生行为应为这个智能体附加哪些工具、指令片段或运行时行为?
sandbox 运行选项每次运行的沙盒客户端和沙盒会话来源这次运行应注入、恢复还是创建一个沙盒会话?
RunState由运行器管理的已保存沙盒状态我是否在恢复先前由运行器管理的工作流,并自动延续其沙盒状态?
sandbox.sessionState显式序列化的沙盒会话状态我是否想从已在 RunState 外部序列化好的沙盒状态恢复?
sandbox.snapshot用于全新沙盒会话的已保存工作区内容新的沙盒会话是否应从已保存的文件和产物开始?

一种实用的设计顺序是:

  1. 使用 Manifest 定义全新会话工作区契约。
  2. 使用 SandboxAgent 定义智能体。
  3. 添加内置或自定义能力。
  4. run(agent, input, { sandbox: ... })new Runner({ sandbox: ... }) 中决定每次运行应如何获取其沙盒会话。

在运行时,运行器会将上述定义转化为一个具体的、由沙盒支持的运行:

  1. 它从 sandbox 运行选项中解析沙盒会话。
  2. 它确定本次运行生效的工作区输入。
  3. 它让 capabilities 处理最终生成的 manifest。
  4. 它按固定顺序构建最终 instructions:SDK 默认的沙盒提示词,或在您显式覆盖时使用 baseInstructions,然后是 instructions,接着是 capability 的指令片段,再接着是任何远程挂载策略文本,最后是渲染后的文件系统树。
  5. 它将 capability 工具绑定到实时沙盒会话,并通过常规的 run()Runner API 运行准备好的智能体。

沙盒化不会改变一次 turn 的含义。turn 仍然是模型的一步,而不是单个 shell 命令或沙盒操作。沙盒侧操作与 turn 之间并不存在固定的 1:1 映射。实际规则是,只有当沙盒工作完成后,智能体运行时还需要模型给出新的响应时,才会消耗另一个 turn。

这些是在常规 Agent 字段之上的沙盒专属选项:

选项最佳用途
defaultManifest由运行器创建的全新沙盒会话的默认工作区。
instructions追加在 SDK 沙盒提示词之后的额外角色、工作流和成功标准。
baseInstructions用于替换 SDK 沙盒提示词的高级兜底选项。
capabilities应随该智能体一起携带的沙盒原生工具和行为。
runAs面向模型的沙盒工具(如 shell 命令、文件读取和补丁)所使用的用户身份。

沙盒客户端的选择、沙盒会话复用、manifest 覆盖和快照选择都应放在 sandbox 运行选项中,而不是放在智能体上。

defaultManifest 是当运行器为该智能体创建全新沙盒会话时所使用的默认 Manifest。可用它定义智能体通常应从哪些文件、仓库、辅助材料、输出目录和挂载开始。

这只是默认值。运行可以通过 sandbox.manifest 覆盖它,而复用或恢复的沙盒会话会保留其现有工作区状态。

定义 manifest
import { file, gitRepo, Manifest } from '@openai/agents/sandbox';
const manifest = new Manifest({
root: '/workspace',
entries: {
'task.md': file({
content: 'Fix the failing test and summarize the change.',
}),
repo: gitRepo({
repo: 'openai/openai-agents-js',
ref: 'main',
}),
},
environment: {
NODE_ENV: 'test',
},
});

使用 instructions 来放置应跨不同提示词保留的简短规则。在 SandboxAgent 中,这些 instructions 会附加在 SDK 的沙盒基础提示词之后,因此您可以保留内置的沙盒指导,同时添加自己的角色、工作流和成功标准。

只有在您想替换 SDK 沙盒基础提示词时,才使用 baseInstructions。大多数智能体都不应设置它。

放在…中用途示例
instructions智能体的稳定角色、工作流规则和成功标准。“检查入职文档,然后交接。”、“将最终文件写入 output/。“
baseInstructions完整替换 SDK 沙盒基础提示词。自定义底层沙盒包装提示词。
用户提示词本次运行的一次性请求。“总结这个工作区。“
manifest 中的工作区文件更长的任务说明、仓库本地 instructions 或有限的参考材料。repo/task.md、文档包、示例材料。

避免将用户的一次性任务复制到 instructions 中,避免嵌入本应放在 manifest 中的长参考资料,避免重复描述内置 capability 已经注入的工具文档,也避免混入模型在运行时并不需要的本地安装说明。

Capabilities 会将沙盒原生行为附加到 SandboxAgent 上。它们可以在运行开始前塑造工作区、追加沙盒专属 instructions、暴露绑定到实时沙盒会话的工具,并为该智能体调整模型行为或输入处理方式。

内置 capabilities 包括:

Capability在何时添加说明
shell()智能体需要 shell 访问时。添加 exec_command,以及当沙盒客户端支持 PTY 交互时添加 write_stdin
filesystem()智能体需要编辑文件或查看本地图像时。添加 apply_patchview_image;补丁路径相对于工作区根目录。
skills()您希望在沙盒中进行技能发现和实例化时。对于沙盒本地 SKILL.md 技能,优先使用此方式,而不是手动挂载 .agents.agents/skills
memory()后续运行应读取或生成记忆产物时。需要 shell();实时更新还需要 filesystem()
compaction()长时间运行的流程在压缩项后需要裁剪上下文时。会调整模型采样和输入处理。

默认情况下,SandboxAgent.capabilities 使用 Capabilities.default(),其中包括 filesystem()shell()compaction()。如果您传入 capabilities: [...],该列表会替换默认值,因此请将您仍希望保留的默认 capability 一并包含进去。

Manifest 描述全新沙盒会话的工作区。它可以设置工作区 root,声明文件和目录,复制本地文件,克隆 Git 仓库,附加远程存储挂载,设置环境变量,定义用户或组,并授予对工作区外特定绝对路径的访问权限。

Manifest 中的环境值默认会被持久化。对于 API 密钥、访问令牌或其他不应随沙盒状态一起保存的短期凭证,请使用如 { value: "...", ephemeral: true } 这样的临时条目。

Manifest 条目的路径是相对于工作区的。它们不能是绝对路径,也不能通过 .. 跳出工作区,这使工作区契约可以在本地、Docker 和托管客户端之间保持可移植性。

对于智能体在开始工作前所需的材料,请使用 manifest 条目:

Manifest 条目用途
file()dir()小型合成输入、辅助文件或输出目录。
localFile()localDir()应在沙盒中实例化的主机文件或目录。
gitRepo()应拉取到工作区中的仓库。
挂载,如 s3Mount()gcsMount()r2Mount()azureBlobMount()s3FilesMount()应显示在沙盒中的外部存储。

挂载条目描述要暴露哪些存储;挂载策略描述沙盒后端如何附加这些存储。有关挂载选项和提供方支持,请参阅沙盒客户端

Permissions 控制 manifest 条目的文件系统权限。它针对的是沙盒实例化出的文件,而不是模型权限、审批策略或 API 凭证。

用户是可以在沙盒中执行工作的身份。当您希望某个身份存在于沙盒中时,可将用户添加到 manifest 中;然后在模型侧的沙盒工具(如 shell 命令、文件读取和补丁)应以该用户身份运行时,设置 SandboxAgent.runAs

如果您还需要文件级共享规则,可将用户与 manifest 中的组以及条目的 group 元数据结合使用。runAs 用户控制谁来执行沙盒原生操作;Permissions 控制在沙盒实例化工作区后,该用户可以读取、写入或执行哪些文件。

SnapshotSpec 告诉全新沙盒会话应从哪里恢复已保存的工作区内容,并持久化回哪里。它是沙盒工作区的快照策略,而 sessionState 则是用于恢复特定沙盒后端的序列化连接状态。

在需要本地持久化快照时使用本地快照;当您的应用提供远程快照客户端时使用远程快照。已挂载路径和临时路径不会作为持久工作区内容被复制到快照中。

有两种生命周期模式:SDK 持有开发者持有

SDK 持有运行器持有实时沙盒。
  1. 传入 sandbox.client

  2. 运行器创建或恢复一个沙盒会话。

  3. 智能体运行,并且基于快照的工作区状态可以持久化。

  4. 运行器关闭由其持有的资源。
开发者持有您的应用持有实时沙盒。
  1. 创建一个 session

  2. sandbox.session 传入运行。

  3. 智能体使用现有工作区。
  4. 自行检查、复用并关闭该会话。

当沙盒只需要存活一次运行时,使用 SDK 持有的生命周期。传入 client、可选的 manifest、可选的 snapshot 以及客户端 options;运行器会创建或恢复沙盒、运行智能体、持久化基于快照的工作区状态,并让客户端清理由运行器持有的资源。

让运行器管理沙盒会话
import { run } from '@openai/agents';
import { SandboxAgent } from '@openai/agents/sandbox';
import { UnixLocalSandboxClient } from '@openai/agents/sandbox/local';
const agent = new SandboxAgent({
name: 'Workspace reviewer',
model: 'gpt-5.5',
instructions: 'Inspect the sandbox workspace before answering.',
});
const result = await run(agent, 'Inspect the workspace.', {
sandbox: {
client: new UnixLocalSandboxClient(),
},
});
console.log(result.finalOutput);

当您希望提前创建一个沙盒、在多次运行中复用同一个实时沙盒、在运行后检查文件、对您自己创建的沙盒进行流式传输,或精确决定何时清理时,使用开发者持有的生命周期。传入 session 会告诉运行器使用该实时沙盒,但不会替您关闭它。

自行管理沙盒会话
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.5',
instructions: 'Inspect the sandbox workspace before answering.',
});
const client = new UnixLocalSandboxClient();
const session = await client.create({ manifest });
try {
await run(agent, 'First task.', { sandbox: { session } });
await run(agent, 'Follow-up task.', { sandbox: { session } });
} finally {
await session.close?.();
}

sandbox 运行选项包含每次运行的配置,用于决定沙盒会话从哪里来,以及如何初始化全新会话。

这些选项决定运行器应复用、恢复还是创建沙盒会话:

选项适用时机说明
client您希望运行器为您创建、恢复并清理沙盒会话时。除非您提供了一个实时沙盒 session,否则这是必需的。
session您已经自行创建了一个实时沙盒会话。生命周期由调用方持有;运行器会复用该实时沙盒会话。
sessionState您有序列化的沙盒会话状态,但没有实时沙盒会话对象。需要 client;运行器会从该显式状态恢复,并将其作为持有型会话。

这些选项仅在运行器创建全新沙盒会话时才有意义:

选项适用时机说明
manifest您想要一次性的全新会话工作区覆盖。省略时会回退到 agent.defaultManifest
snapshot全新沙盒会话应从快照提供初始数据。适用于类似恢复的流程或远程快照客户端。
options沙盒客户端在创建时需要额外选项。常用于 Docker 镜像、提供方超时及类似的客户端特定设置。

concurrencyLimits 控制沙盒实例化工作可并行执行的程度。当大型 manifest 或本地目录复制需要更严格的资源控制时,可使用 manifestEntrieslocalDirFiles

实例化控制被有意设计为每次运行配置。请将它们放在 sandbox 运行选项附近,这样同一个 SandboxAgent 就可以在复制大型本地目录时使用保守限制,而在处理小型 manifest 时使用更宽松的限制。

当 manifest 有许多独立条目(如文件、目录、仓库和挂载)时,使用 concurrencyLimits.manifestEntries。当 localDir() 条目包含许多文件且需要限制本地复制压力时,使用 concurrencyLimits.localDirFiles

这个编码风格的示例是一个很好的默认起点:

沙盒编码任务
import { run } from '@openai/agents';
import {
Capabilities,
Manifest,
SandboxAgent,
localDir,
skills,
} from '@openai/agents/sandbox';
import {
UnixLocalSandboxClient,
localDirLazySkillSource,
} from '@openai/agents/sandbox/local';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
const exampleDir = dirname(fileURLToPath(import.meta.url));
const hostRepoDir = join(exampleDir, 'repo');
const hostSkillsDir = join(exampleDir, 'skills');
const manifest = new Manifest({
entries: {
repo: localDir({ src: hostRepoDir }),
},
});
const agent = new SandboxAgent({
name: 'Sandbox engineer',
model: 'gpt-5.5',
instructions:
'Read `repo/task.md` before editing files. Load the `$invoice-total-fixer` skill before changing code. Stay grounded in the repository, preserve existing behavior, and mention the exact verification command you ran. If you edit files with apply_patch, paths are relative to the sandbox workspace root.',
defaultManifest: manifest,
capabilities: [
...Capabilities.default(),
skills({
lazyFrom: localDirLazySkillSource(hostSkillsDir),
}),
],
});
const result = await run(
agent,
'Open `repo/task.md`, fix the issue, run the targeted test, and summarize the change.',
{
sandbox: {
client: new UnixLocalSandboxClient(),
},
},
);
console.log(result.finalOutput);

请从上面的完整示例开始。在很多情况下,可以保持同一个 SandboxAgent 不变,仅更改沙盒客户端、沙盒会话来源或工作区来源。

保持智能体定义不变,只更改运行配置。当您需要容器隔离或镜像一致性时使用 Docker;当您需要由提供方管理执行环境时使用托管提供方。有关示例和提供方选项,请参阅沙盒客户端

保持智能体定义不变,仅通过 sandbox: { client, manifest } 替换全新会话 manifest。当同一个智能体角色需要针对不同仓库、材料包或任务包运行,而无需重建智能体时,这种方式很适合。

当您需要显式生命周期控制、运行后检查或复制输出时,可注入一个实时沙盒会话。为该次运行使用 sandbox: { session },并在您的应用代码中关闭该会话。

如果您已经在 RunState 外部序列化了沙盒状态,可通过 sandbox: { client, sessionState } 让运行器从该状态重新连接。当沙盒状态存储在您自己的存储或任务系统中,并且您希望 Runner 直接从中恢复时,可使用此方式。

使用 sandbox: { client, snapshot } 让新沙盒从已保存的文件和产物中提供初始数据。当一次全新运行应从已保存的工作区内容开始,而不只是从 agent.defaultManifest 开始时,可使用此方式。

通过 skills({ from: gitRepo(...) }) 将本地技能来源替换为基于仓库的来源。当技能包有自己的发布节奏,或应在多个沙盒之间共享时,可使用此方式。

工具智能体既可以拥有自己的沙盒边界,也可以复用父运行中的实时沙盒。复用对于快速的只读探索型智能体很有用:它可以检查父级正在使用的精确工作区,而无需付出创建、填充或快照另一个沙盒的成本。

当工具智能体确实需要隔离时,请通过 sandboxAgent.asTool(...) 为它提供自己的 runConfig。如果工具智能体应自由修改、运行不受信任的命令,或使用不同的后端或镜像,请使用独立沙盒。

在保留沙盒工作区的同时,仍可在同一个智能体上使用普通工具。沙盒 capabilities 可以与 toolsmcpServers、handoffs、模型设置和输出配置共存。

当未来的沙盒智能体运行应从先前运行中学习时,请使用 memory() capability。记忆不同于 SDK 对话式 Session 记忆:它会将经验提炼成沙盒工作区中的文件,之后的运行可以读取这些文件。

有关设置、读取/生成行为、多轮对话和布局隔离,请参阅智能体记忆

当单智能体模式已经清晰后,下一个设计问题就是在更大的系统中,沙盒边界应该放在哪里。

沙盒智能体仍然可以与 SDK 的其余部分组合:

  • 交接:将文档密集型工作从非沙盒接入智能体交接给沙盒审查智能体。
  • Agents as tools:将多个沙盒智能体作为工具暴露,通常是在每次 asTool(...) 调用中传入一个沙盒运行配置,以便每个工具都有自己的沙盒边界。
  • MCP 集成 和普通函数工具:沙盒 capabilities 可以与 mcpServers 和普通工具共存。
  • 运行智能体:沙盒运行仍然使用常规的 run()Runner API。

对于交接,仍然只有一个顶层运行和一个顶层 turn 循环。活跃智能体会变化,但运行不会变成嵌套结构。

而使用 asTool(...) 时,关系就不同了。外层编排器会在一个外层 turn 中决定调用该工具,而该工具调用会为沙盒智能体启动一个嵌套运行。这个嵌套运行有自己的 turn 循环、maxTurns、审批,并且通常也有自己的沙盒运行配置。从外层编排器的视角看,所有这些工作仍然都隐藏在一次工具调用之后,因此嵌套的 turns 不会增加外层运行的 turn 计数。