You need to enable JavaScript to run this app.
文档中心
全站加速

全站加速

复制全文
下载 pdf
Agent SDK 参考
沙箱 Sandbox
复制全文
下载 pdf
沙箱 Sandbox

本文是 Agent SDK 中沙箱 Sandbox(沙箱)模块的参考。您可以在 IGA Pages 服务端创建或复用受控运行环境,运行代码和命令、读写文件、访问网页,并管理实例生命周期;也可以将沙箱传给 getTools(),让 Agent 调用这些能力(详见工具 Tools)。本文先给出一段可直接运行的最短示例,随后说明沙箱的获取、能力调用、实例管理与错误处理。

背景信息

Agent SDK 通过核心包 @iga-pages/agent 的 ./sandbox 子路径提供面向 IGA Pages 的沙箱能力,负责凭据换取、实例创建与生命周期管理。您在业务代码中通过 @iga-pages/agent/sandbox 引入对应入口,即可获得经 SDK 封装后的沙箱能力,而无需直接面对底层运行时细节。

沙箱仅用于 IGA Pages 服务端,要求 Node.js 20 或更高版本。实例中的文件、进程和浏览器状态不会永久保存,需要长期保留的数据应写入 Blob 等持久存储。

沙箱运行在 IGA Pages 服务端运行时中,使用当前应用的运行时身份访问对应项目中的资源;项目身份在运行时自动确定,您无需显式传入。

前提条件

在获取并使用沙箱实例之前,请确认您已完成以下准备:

  • 已安装 Agent SDK 核心包 @iga-pages/agent,并可通过子路径 @iga-pages/agent/sandbox 引入沙箱入口函数。安装步骤请参见安装与环境准备。
  • 已通过 CLI 完成登录与项目关联;沙箱会使用当前应用的运行时身份在运行时确定项目身份,您无需单独设置。配置步骤请参见安装与环境准备。

快速开始

在已关联项目的 IGA Pages 开发环境或线上服务端使用。安装 SDK:

npm install @iga-pages/agent

在已关联项目的 IGA Pages 开发环境或线上服务端中,创建沙箱并执行代码:

import { createSandbox } from "@iga-pages/agent/sandbox";

export async function runExample() {
  const sandbox = await createSandbox();
  try {
    const result = await sandbox.code.executeCode({
      language: "python",
      code: "print(1 + 1)",
    });
    if (!result.ok) throw new Error("代码执行请求失败");
    const execution = result.body.data;
    if (
      result.body.success === false || !execution ||
      execution.status !== "completed" ||
      (execution.exit_code !== undefined && execution.exit_code !== 0) ||
      (execution.traceback?.length ?? 0) > 0
    ) {
      throw new Error(result.body.message || "代码执行失败");
    }
    console.log(execution.stdout); // 输出 2。
    return execution.stdout;
  } finally {
    await sandbox.destroy();
  }
}

该示例在任务结束后释放实例,适合一次性任务。需要跨请求保留沙箱状态时,可按获取沙箱中的说明选择使用方式。

result.ok 表示请求是否成功;代码是否成功执行,还需检查执行状态和退出码等字段,详见请求与错误处理。

获取沙箱

SDK 提供两种沙箱管理方式,共有三个入口:

  • 按会话管理:使用 getConversationSandbox()。
  • 由应用自行管理:通过 createSandbox() 创建实例,并用 connectSandbox() 继续使用已保存的实例。
场景调用方式行为
多轮会话需要复用环境getConversationSandbox(conversationId)同步返回沙箱对象;首次使用时查找或创建会话实例。
为一个任务创建独立环境await createSandbox()每次创建新实例;等待返回后即可读取 sandboxId。
继续使用已保存的实例connectSandbox(sandboxId)同步返回沙箱对象;首次使用时检查并连接指定实例。

三个入口都从 @iga-pages/agent/sandbox 导入,无需传入客户端配置。conversationId 是应用的非空会话标识,最多 256 UTF-8 字节;sandboxId 是沙箱实例 ID,两者不能互换。应用应校验 ID 与当前用户或任务的归属。

按会话管理

使用 getConversationSandbox(conversationId) 获取指定会话的沙箱。不同会话使用各自的实例,同一会话会复用同一沙箱实例,适合需要在多轮交互中保留文件和执行环境的场景。

import { getConversationSandbox } from "@iga-pages/agent/sandbox";

// conversationId 为非空字符串,最多 256 UTF-8 字节。
const sandbox = getConversationSandbox(conversationId);

const result = await sandbox.code.executeCode({
  language: "python",
  code: "print('Hello, sandbox!')",
});

getConversationSandbox() 会同步返回沙箱对象,首次调用业务方法、getInfo() 或 extendTimeout() 时才初始化。应用无需自行保存实例 ID,同一会话可跨请求、跨进程复用实例。

SDK 确认实例失效后,会尝试自动恢复,恢复成功后重试原操作一次。新实例不会恢复旧文件、进程和浏览器状态,需要长期保留的数据应提前写入 Blob 等持久存储。

需要下一轮继续使用时,不要在每次请求结束后调用 destroy();确认不再需要该会话的沙箱时,再主动释放。

自行管理生命周期

使用 createSandbox() 创建独立实例,由应用保存实例 ID;后续通过 connectSandbox(sandboxId) 连接同一个实例。适合需要自行决定实例如何分配、复用和释放的场景。

import {
  createSandbox,
  connectSandbox,
} from "@iga-pages/agent/sandbox";

// 创建独立实例,等待初始化完成。
const sandbox = await createSandbox();

// 保存 ID,供后续请求或其他进程使用。
const sandboxId = sandbox.sandboxId;

// 创建后可以直接使用。
const result = await sandbox.code.executeCode({
  language: "python",
  code: "print('Hello, sandbox!')",
});

// 后续通过保存的 ID 连接同一个实例。
const connected = connectSandbox(sandboxId);
const info = await connected.getInfo();

// 不再需要时释放实例。
await connected.destroy();

实例失效后,需要由应用调用 createSandbox() 创建新实例,并更新保存的实例 ID。主动销毁实例后,请勿继续使用原沙箱对象或通过原 ID 连接。

使用沙箱能力

获取沙箱后,通过以下模块执行操作。按会话管理和自行管理生命周期两种方式提供相同的能力。

调用后先检查 result.ok:请求失败时读取 result.error,请求成功时根据方法读取 result.body。请求成功不代表操作已成功完成,还需检查具体执行结果,详见请求与错误处理。

以下按模块列出全部公开方法及用途。具体参数、参数位置和返回类型,请查看对应方法签名:

能力入口用途
代码执行sandbox.code运行 Python 或 JavaScript 代码。
命令执行sandbox.shell执行 Shell 命令、查看输出和管理进程。
文件操作sandbox.file读写、查找文件。
网页操作sandbox.browserPage打开网页、操作页面和读取内容。

code:执行代码

通过 sandbox.code 执行 Python 或 JavaScript 代码。

方法用途
code.executeCode()执行 Python 或 JavaScript 代码。

例如,执行一段 Python 代码并读取标准输出:

const result = await sandbox.code.executeCode({
  language: "python",
  code: "print(1 + 1)",
});

if (!result.ok) {
  throw new Error("代码执行请求失败");
}
if (result.body.success === false || !result.body.data) {
  throw new Error(result.body.message || "未获取到执行结果");
}

console.log(result.body.data.stdout); // 输出:2

executeCode() 的执行数据位于 result.body.data,其中 stdout 为标准输出,stderr 为错误输出。

判断代码是否成功完成时,还需查看执行状态 status、退出码 exit_code 和异常堆栈 traceback,详见请求与错误处理。

shell:执行命令

通过 sandbox.shell 执行命令、查看输出和控制进程。

方法用途
shell.execCommand()执行 Shell 命令。
shell.view()查看 Shell 会话输出。
shell.waitForProcess()等待进程执行。
shell.killProcess()终止进程。
const result = await sandbox.shell.execCommand({
  command: "pwd && ls -la",
  exec_dir: "/tmp",
  async_mode: false,
});
if (!result.ok) throw new Error("命令请求失败");
const command = result.body.data;
if (result.body.success === false || !command ||
    command.status !== "completed" ||
    (command.exit_code !== undefined && command.exit_code !== 0)) {
  throw new Error(result.body.message || "命令未成功完成");
}
console.log(command.output);

命令输出通过 result.body.data.output 读取。判断命令是否成功完成,还需检查 body.success、执行状态和退出码。

异步执行的命令可用 waitForProcess() 等待完成,用 killProcess() 终止进程。

file:操作文件

通过 sandbox.file 读写、查找文件。

方法用途
file.readFile()读取文件内容。
file.writeFile()写入或追加文件内容。
file.replaceInFile()替换文件中的内容。
file.searchInFile()搜索指定文件中的内容。
file.findFiles()查找文件。
file.grepFiles()在多个文件中搜索内容。
file.listPath()列出指定路径下的文件和目录。

文件路径指向沙箱内的文件系统。同一实例中的代码、命令和文件操作可以访问这些文件。下面先写入文件,再读取正文:

const written = await sandbox.file.writeFile({
  file: "/tmp/notes.txt",
  content: "Hello Sandbox\n",
  append: false,
});
if (!written.ok) throw new Error("写文件请求失败");
if (written.body.success === false) {
  throw new Error(written.body.message || "文件写入失败");
}

const read = await sandbox.file.readFile({ file: "/tmp/notes.txt" });
if (!read.ok) throw new Error("读文件请求失败");
if (read.body.success === false) {
  throw new Error(read.body.message || "文件读取失败");
}
const data = read.body.data;
if (!data || !("content" in data)) throw new Error("响应中没有文件正文");
console.log(data.content);

读取文件正文前,先检查操作是否成功,再确认 body.data 中存在 content。写入成功后,body.data 包含文件路径和可选的写入字节数。

沙箱中的文件随实例存续。需要长期保留的输入和产物,请写入 Blob 等持久存储。

browserPage:网页操作

方法用途
browserPage.navigate()打开指定网页。
browserPage.back()后退。
browserPage.forward()前进。
browserPage.reload()重新加载页面。
browserPage.click()点击页面元素或指定位置。
browserPage.fill()填写输入框。
browserPage.typeText()模拟键盘输入文本。
browserPage.pressKey()按下指定按键。
browserPage.hotKey()执行组合键操作。
browserPage.hover()将鼠标悬停在元素或指定位置。
browserPage.selectOption()选择下拉框选项。
browserPage.check()勾选复选框。
browserPage.uncheck()取消勾选复选框。
browserPage.uploadFile()向网页的文件上传控件提交文件。
browserPage.scroll()滚动页面。
browserPage.scrollTo()滚动到指定位置。
browserPage.scrollToElement()滚动到指定元素。
browserPage.screenshot()获取页面截图。
browserPage.getHtml()读取页面 HTML。
browserPage.getText()读取页面文本。
browserPage.wait()等待指定页面条件满足。

sandbox.browserPage 操作当前页面。导航、读取内容和截图等有先后依赖的操作,应依次执行,避免并发导航改变操作目标。下面先打开网页,再获取截图:

const navigation = await sandbox.browserPage.navigate({
  url: "https://example.com",
  wait_until: "load",
});
if (!navigation.ok) throw new Error("导航请求失败");
if (navigation.body.success === false) {
  throw new Error(navigation.body.message || "页面导航失败");
}

const screenshot = await sandbox.browserPage.screenshot({ full_page: true });
if (!screenshot.ok) throw new Error("截图请求失败");
const image = await screenshot.body.arrayBuffer();

截图使用当前页面,请先通过 navigate() 打开目标网页。截图成功后,body 为二进制内容,可通过 arrayBuffer()、blob() 或 stream() 读取,再用于显示、保存或交给模型处理。

读取 HTML 使用 getHtml(),HTML 字符串位于 result.body.data。

管理实例

获取到的沙箱实例除上述业务能力模块外,还暴露以下生命周期方法与属性:

方法用途返回值
getInfo(options?)查询当前实例信息;必要时触发初始化Promise<SandboxInstanceInfo>
extendTimeout(timeoutInMinutes, options?)请求续期,时长单位为分钟Promise<SandboxInstanceInfo>
destroy(options?)销毁实例,释放其资源Promise<void>

此外,实例还提供 conversationId(会话 ID,仅绑定会话的实例有)与 sandboxId(实例 ID)两个属性。

const info = await sandbox.getInfo();
console.log(info.sandboxId, info.expireAt);

const updated = await sandbox.extendTimeout(30); // 单位为分钟
console.log(updated.expireAt);

// 不再需要该实例时释放。
await sandbox.destroy();

getInfo() 和 extendTimeout() 返回以下实例信息 SandboxInstanceInfo:

字段类型说明
sandboxIdstring实例 ID。
status可选字符串枚举Starting(启动中)、Ready(可用)、Failed(失败)、Terminating(终止中)。
createdAtstring | undefined创建时间。
expireAtstring | undefined预计到期时间。

实例多久过期

通过 getInfo() 返回的 expireAt 查看实例的预计到期时间。

按会话管理和自行管理生命周期两种方式都支持自动续期。SDK 在使用实例时检查已知到期时间,剩余不超过 5 分钟时尝试续期 30 分钟。常规自动续期失败不会阻断当前业务调用。

自动续期由调用触发,不会在后台持续保活。闲置或长时间执行中的实例仍可能到期。需要确认续期结果时,显式调用 extendTimeout(),并检查返回的 expireAt。

实例续期与代码、命令的执行超时以及单次请求超时相互独立,不能互相替代。

实例失效或销毁后怎么办

使用 getConversationSandbox() 时,SDK 确认实例失效后会尝试自动恢复,恢复成功后重试原操作一次;恢复或重试仍可能失败,应用需要处理返回结果或异常。

使用 createSandbox()、connectSandbox() 时,SDK 不会自动创建替代实例。应用需要调用 createSandbox() 创建新实例,并更新保存的实例 ID。

注意

connectSandbox() 在懒加载时做前置检查:实例不存在或状态为 Failed/Terminating 时抛出 SandboxError(message 说明实例已不存在);实例已过期则自动续期后接回。

释放实例

不再需要实例时,调用 destroy():

await sandbox.destroy();

销毁成功后,请停止使用原沙箱对象或通过原 ID 连接。需要继续使用沙箱时,通过获取沙箱中的入口重新获取。

按会话复用沙箱时,如果下一轮交互还需要使用当前实例,请勿在每次请求结束后销毁。

与工具的关系

沙箱是内置工具运行的基础。SDK 的内置工具集通过 getTools(sandbox) 基于一个沙箱实例来构建,工具在执行时依托该沙箱所提供的运行环境完成动作。因此,在构建工具之前,您需要先准备好一个可用的沙箱实例,再将其作为参数传入 getTools。

关于内置工具的具体清单与用法,请参见工具 Tools。

请求与错误处理

读取调用结果

实例管理方法与代码、文件等操作方法的返回方式不同:

方法成功时失败时
createSandbox()返回沙箱对象抛出异常。
getInfo()、extendTimeout()返回实例信息抛出异常。
destroy()无返回数据抛出异常。
代码、命令、文件和浏览器等业务方法返回 ok: true,结果位于 body可能返回 ok: false,也可能在初始化等阶段抛出异常。

调用业务方法时,先检查 result.ok:

const result = await sandbox.file.readFile({
  file: "/tmp/notes.txt",
});

if (!result.ok) {
  console.error(result.error);
  throw new Error("读取请求失败");
}

// 请求成功后,再检查并读取 result.body。

对于 JSON 响应,还需要判断操作是否成功完成:

检查项说明
result.ok请求是否成功。
result.body.success为 false 时表示操作失败,说明通常位于 message。
result.body.data具体结果,按方法检查执行状态、退出码或文件正文等字段。

截图返回二进制内容,直接读取 body,无需检查 JSON 的 success、data 字段。

捕获异常

除检查返回结果外,还应使用 try...catch 处理初始化和实例管理等阶段的异常:

import {
  getConversationSandbox,
  SandboxError,
  isAbortError,
} from "@iga-pages/agent/sandbox";

export async function inspect(conversationId: string) {
  try {
    const sandbox = getConversationSandbox(conversationId);
    return await sandbox.getInfo();
  } catch (error) {
    if (isAbortError(error)) {
      return undefined;
    }

    if (error instanceof SandboxError) {
      console.error(error.toJSON());
    }

    throw error;
  }
}

SandboxError 提供以下信息:

字段或方法说明
code由 HTTP 状态名派生的错误码(如 404 → NotFound);无可用状态时回落为 SandboxError,便于程序分支判断。
status可选,对应的 HTTP 状态码。
message可读的错误说明。
toJSON()返回 { code, status?, message } 结构化错误信息,适合记录。

SandboxError 以 code 标识出错类型。各模块的错误对象字段结构并不相同(Store 为 StoreError、Blob 为 BlobError),处理时应先用 instanceof 按错误类型分支,再读取该类型自有的字段,不要假设某个字段在所有模块上都存在。

被取消信号中止属于正常控制流,用 isAbortError 单独识别。

代码、文件等业务方法返回的失败仍需检查 result.ok,不能只依赖 catch。

Unauthorized、Forbidden 一类属配置或权限问题,应检查项目登录与授权而非重试。

取消操作

将取消信号放入本次调用的请求选项:

const result = await sandbox.shell.execCommand(
  { command: "pwd" },
  { abortSignal: request.signal },
);

实例管理方法同样支持取消:

const info = await sandbox.getInfo({
  abortSignal: request.signal,
});

取消调用不会销毁实例,也不保证终止已经启动的代码或进程。需要停止 Shell 进程时,使用 killProcess()。

请求选项的位置取决于方法签名:

// 有操作参数:请求选项放在第二个参数。
await sandbox.browserPage.getHtml(
  {},
  { abortSignal: request.signal },
);

// 实例管理方法无操作参数:请求选项放在第一个参数。
await sandbox.getInfo({
  abortSignal: request.signal,
});

获取沙箱的入口函数不接收取消信号。请在具体操作时传入。

最近更新时间:2026.10.08 11:53:16
这个页面对您有帮助吗?
有用
有用
无用
无用