概览
Makers Agent 内置的沙箱工具底层是腾讯云的隔离实例,专门承载 Agent 执行过程中的"副作用"——跑命令、读写文件、操控浏览器、运行代码,让 LLM 真正具备"动手"能力,而不是只能输出文本。
两层 API
平台把同一个沙箱实例分别包装成两层 API 暴露在
context 上:一层给 LLM 当工具调用,一层给开发者直接使用。视角 | 字段 | 给谁用 | 粒度 |
LLM 视角 | context.tools.* | 传给 LLM 的工具清单(按 framework 包装为原生对象) | 已扁平化为原子工具,便于按需放开调用范围 |
开发者视角 | context.sandbox.* | 开发者代码中直接调用的沙箱原子 API | 按模块组织: commands / files / browser /runCode 顶层方法 |
两层 API 底层共用同一个沙箱实例——
context.tools 中需要沙箱能力的内置工具,其内部实现就是直接调用 context.sandbox.*,不存在两套独立逻辑。实例生命周期
维度 | 说明 |
实例归属 | 一对话一实例,按 conversation_id 维度托管 |
创建时机 | 懒加载——首次访问沙箱工具时由适配层调用 |
跨请求复用 | 如果沙箱实例未被销毁,同 conversation_id 的沙箱工具请求落到同一实例 |
生命周期上限 | 由 edgeone.json 的 sandbox.timeout 控制,到时间点自动回收 |
隔离 | 不同对话的沙箱实例物理隔离 |
实例控制
方法挂载在
context.sandbox 顶层,用于管理沙箱实例本身的生命周期与对外暴露。方法 | 用途 |
getHost(port) | 获取沙箱实例的外部访问地址 |
envdAccessToken | 获取数据面访问 token |
getInfo() | 获取当前沙箱信息( instanceId、expiresAt 等) |
extendTimeout(seconds) | 延长当前沙箱实例寿命;返回 { instanceId, expiresAt, message? } |
kill() | 销毁沙箱实例 |
getHost(port) / get_host(port)
获取沙箱实例某个端口的外部可访问地址,用于把沙箱内启动的 server 暴露给浏览器或外部调用方。
参数
Parameter | Type | Required | Description |
port | number / int | Yes | 沙箱内监听的端口号 |
返回值
形如
https://<port>-<instance>.sandbox.example.com 的外部地址。TS 示例:
// 沙箱里跑个 vite dev server,再把它的访问地址返给前端await context.sandbox.commands.run('nohup npx vite --port 5173 &', { timeout: 10 })const previewUrl = context.sandbox.getHost(5173)return Response.json({ previewUrl })
Python 示例:
await ctx.sandbox.commands.run('nohup python -m http.server 8000 &', timeout=10)preview_url = ctx.sandbox.get_host(8000)return {'preview_url': preview_url}
envdAccessToken / envd_access_token
获取沙箱实例数据面的访问 token
返回值
envd token
TS 示例:
const token = context.sandbox.envdAccessToken
Python 示例:
token = ctx.sandbox.envd_access_token
getInfo() / get_info()
获取当前会话缓存的沙箱元信息,沙箱实例 ID、过期时间等。
返回值
SandboxInfointerface SandboxInfo {instanceId: stringsandboxToken: stringsandboxDomain?: stringenvdVersion?: stringexpiresAt: string // ISO 时间字符串,由后端 acquire/update 返回}
@dataclassclass SandboxInfo:instance_id: strsandbox_token: strexpires_at: strsandbox_domain: Optional[str] = Noneenvd_version: Optional[str] = None
TS 示例:
const info = context.sandbox.getInfo()console.log(info.instanceId, info.expiresAt)const remainingMs = new Date(info.expiresAt).getTime() - Date.now()if (remainingMs < 60_000) {await context.sandbox.extendTimeout(600)}
Python 实例:
info = ctx.sandbox.get_info()print(info.instance_id, info.expires_at)
extendTimeout(seconds) / extend_timeout(seconds)
为当前沙箱实例发起续期请求,真实生效的时长以后端返回为准。如果你要求的秒数超出后端允许的剩余可续期窗口,后端会截断并告诉你实际只续到什么时候,SDK 会用返回的
expiresAt / expires_at 同步更新本地缓存。参数
Parameter | Type | Required | Description |
seconds | number / int | Yes | 续期秒数,必须是正整数 |
返回值
UpdateResponse
interface UpdateResponse {instanceId: stringexpiresAt: string // 后端确认后的真实新过期时间message?: string // 仅当被后端截断续期时返回,例如 "extended to max lifetime"}
Python:
dict,字段为 instance_id / expires_at / message?(snake_case)。TS 示例
await context.sandbox.commands.run('echo init', { timeout: 300 })const renewed = await context.sandbox.extendTimeout(600)console.log('new expiresAt:', renewed.expiresAt)
Python 示例
await ctx.sandbox.commands.run('echo init', timeout=300)renewed = await ctx.sandbox.extend_timeout(600)print('new expires_at:', renewed['expires_at'])
kill()
主动销毁当前沙箱实例。
context.sandbox.kill()
何时应该调kill? 一次性脚本结束、或确认整个对话结束希望立刻把沙箱实例配额释放出来。
错误码说明
错误码 | 说明 |
SANDBOX_LIMIT_EXCEEDED | 并发实例数 / 总内存时长配额 / 单实例最大运行时长超限 |
SANDBOX_INVALID_PARAMETER | 参数校验失败,如缺少 conversation_id、授权 Token 等 |
SANDBOX_AUTHORIZATION_EXPIRED | 授权 Token 无效/过期 |
SANDBOX_FAILED_OPERATION | 沙箱服务操作失败(限频/超时等) |
SANDBOX_NETWORK_ERROR | 沙箱服务网络异常 |
SANDBOX_INSTANCE_UNAVAILABLE | 沙箱实例不存在或已过期 |
SANDBOX_NETWORK_ERROR | 数据面运行时客户端依赖缺失或创建失败 |
SANDBOX_UNKNOWN_ERROR | 兜底错误码,错误详情可查看 message 字段 |
FAQ
Q:
browser_screenshot 返回什么?base64 还是 URL?A:返回
{ base64Image }(PNG base64),不返回 URL,也不在沙箱内保存文件。如需展示给前端 / 持久化,自己落对象存储换 URL 即可。Q:
browser_fetch 和直接 HTTP 请求有什么区别?A:
browser_fetch 用真实 Chromium 导航(CDP + Playwright),能拿到 JS 渲染后的页面元信息和 HTML;普通 HTTP fetch 只能拿到原始响应。需要轻量抓接口的场景可在 commands 里用 curl。Q:能不能把沙箱实例的 timeout 调到 10 小时?
Q:可以只放开部分工具给 LLM 吗?
A:可以,
context.tools.all() 是全集;按需可用 context.tools.files() / context.tools.browser() 拿分组,或用 context.tools.get(name) 自行组装子集。