Skip to content
0
/ Agent/AIO Sandbox
6/1/2026
10m
AI 摘要

AIO SandboxDocker 容器集成浏览器 VNC/CDP、终端、代码执行与 MCP;含 docker run 部署、agent-sandbox SDK 与 Playwright 调用示例。

AIO Sandbox

AIO Sandbox 把浏览器、Shell、代码执行、文件 API、MCP/Skills、Code Server 放进同一个 Docker 容器,共享 /home/gem 文件系统。下面按我实际会用到的能力来写;安装和背景一笔带过。

安装

$ docker run --security-opt seccomp=unconfined --rm -it -p 8080:8080 ghcr.io/agent-infra/sandbox:latest

国内可用火山镜像,见 快速开始。启动后仪表板:

服务URL
仪表板http://localhost:8080/index.html
API 文档http://localhost:8080/v1/docs
VNChttp://localhost:8080/vnc/index.html?autoconnect=true
终端http://localhost:8080/terminal
Code Serverhttp://localhost:8080/code-server/
MCPhttp://localhost:8080/mcp
$ pip install agent-sandbox
from agent_sandbox import Sandbox
client = Sandbox(base_url="http://localhost:8080")

浏览器与 VNC

Agent 要「看网页、点按钮、下文件」,沙盒里主要有四条路:

方式适合
VNC人要盯着完整桌面点;多标签、本地文件
CDPPlaywright/Puppeteer;DOM、网络、注入 JS
GUI 操作截图 + 键鼠,DOM 不好碰的风控页
MCP browser_*给模型接工具,少写 HTTP 胶水

VNC

浏览器打开(或 iframe 嵌入产品):

http://localhost:8080/vnc/index.html?autoconnect=true

传的是整块桌面像素,带宽和延迟都偏高,但交互最直观。

CDP

$ curl -s http://127.0.0.1:8080/v1/browser/info | jq '.data.cdp_url'
$ curl -s http://localhost:8080/cdp/json/version
from playwright.async_api import async_playwright
from agent_sandbox import Sandbox

client = Sandbox(base_url="http://localhost:8080")

async def main():
    async with async_playwright() as p:
        cdp_url = client.browser.get_info().cdp_url
        browser = await p.chromium.connect_over_cdp(cdp_url)
        page = await browser.new_page()
        await page.goto("https://example.com")
        await page.screenshot(path="shot.png")

import asyncio
asyncio.run(main())

产品里要嵌「只显示当前页、省带宽」,可用 @agent-infra/browser-uiBrowserCanvascdpEndpoint 指到 http://localhost:8080/json/version

GUI 操作

不查 DOM,按坐标点击、输入、滚动:

from agent_sandbox.browser import Action_MoveTo, Action_Click, Action_Typing

client.browser.execute_action(request=Action_MoveTo(x=100, y=100))
client.browser.execute_action(request=Action_Click(x=200, y=200))
client.browser.execute_action(request=Action_Typing(text="hello", use_clipboard=True))

VNC 和 CDP 怎么选

VNCCanvas + CDP
内容完整浏览器 UI主要是当前页
自动化键鼠模拟DOM / 网络 / JS
带宽

更多见 浏览器与 VNC


Shell 终端

基于 PTY 的真终端,适合 REPL、交互式安装;REST + WebSocket 两种接法。

Shell vs Bash 管道

Shell /v1/shellBash /v1/bash
输出单一 outputstdout / stderr 分开
读取wait + view 快照/output + offset 增量
场景Web 终端、交互Agent 程序化跑命令

一次性执行

$ curl -X POST http://localhost:8080/v1/shell/exec \
  -H "Content-Type: application/json" \
  -d '{"command": "pwd && ls -la"}'

复用会话

第一次返回 session_id,后续带上 id,工作目录和环境变量会保留:

$ SESSION=$(curl -s -X POST http://localhost:8080/v1/shell/exec \
  -H "Content-Type: application/json" \
  -d '{"command": "cd /tmp && export FOO=bar"}' | jq -r '.data.session_id')

$ curl -X POST http://localhost:8080/v1/shell/exec \
  -H "Content-Type: application/json" \
  -d "{\"id\": \"$SESSION\", \"command\": \"pwd && echo $FOO\"}"

Web 终端

页面:http://localhost:8080/terminal。自研 UI 连 WebSocket:

const ws = new WebSocket('ws://localhost:8080/v1/shell/ws')
ws.send(JSON.stringify({ type: 'input', data: 'ls -la\n' }))
ws.onmessage = (e) => {
  const msg = JSON.parse(e.data)
  if (msg.type === 'output') terminal.write(msg.data)
}

长任务用 async_mode: true,再调 /v1/shell/wait/v1/shell/view。详见 Shell 终端Bash 管道


统一代码执行

不想自己管 Jupyter/Node 会话时,用 POST /v1/code/execute,按 language 路由到对应运行时:

语言底层
pythonJupyter kernel
javascriptNode.js
$ curl -X POST http://localhost:8080/v1/code/execute \
  -H "Content-Type: application/json" \
  -d '{"language": "python", "code": "print(sum([1,2,3]))"}'

$ curl -X POST http://localhost:8080/v1/code/execute \
  -H "Content-Type: application/json" \
  -d '{"language": "javascript", "code": "console.log([1,2,3].reduce((a,b)=>a+b,0))"}'

$ curl http://localhost:8080/v1/code/info

需要会话、内核状态、更长代码块时,再直接用 /v1/jupyter/*/v1/nodejs/*(和统一入口写的是同一份文件系统)。见 统一代码执行


文件操作

所有能力读写的是同一棵树:浏览器下载在 Downloads/,Shell echo 出的文件,Code Server 里改的,API 都能立刻看到。

常用端点(前缀 /v1/file):

端点用途
read / write读写信,支持行范围、base64 二进制
replace / search / grep替换与搜索
find / glob / list列目录、匹配路径
upload / download上传表单、流式下载
watch / watch/wait等文件生成(如下载完成)
$ curl -X POST http://localhost:8080/v1/file/write \
  -H "Content-Type: application/json" \
  -d '{"file": "/home/gem/workspace/demo.txt", "content": "Hello"}'

$ curl -X POST http://localhost:8080/v1/file/read \
  -H "Content-Type: application/json" \
  -d '{"file": "/home/gem/workspace/demo.txt"}'

注意:很多接口失败时仍是 HTTP 200,要看 successdata.error_type(如 not_found)。download 失败则按 HTTP 状态码处理。

和 Shell 串起来:

$ curl -X POST http://localhost:8080/v1/shell/exec \
  -H "Content-Type: application/json" \
  -d '{"command": "echo ok > /tmp/from-shell.txt"}'

$ curl -X POST http://localhost:8080/v1/file/read \
  -H "Content-Type: application/json" \
  -d '{"file": "/tmp/from-shell.txt"}'

详见 文件操作


MCP 与 Skills

MCP Hub

一个地址 http://localhost:8080/mcp 聚合浏览器、文件、终端、Markitdown 等工具。Cursor 等客户端配置示例:

{
  "mcpServers": {
    "aio-sandbox": {
      "url": "http://localhost:8080/mcp"
    }
  }
}
前缀示例
browser_*browser_navigatebrowser_screenshotbrowser_extract
file_*file_readfile_writefile_grep
terminal_*terminal_execute
Markitdownmarkitdown_convert

MCP 抽象更高、连接相对稳;要细控 DOM 时再走 CDP。见 MCP 集成

Skills

Skills 是可注册的指令 + 脚本包,让 Agent 发现「什么时候用、怎么做」。目录结构大致如下:

my-skill/
  SKILL.md          # frontmatter + Markdown 说明
  scripts/
  requirements.txt

SKILL.md 示例:

---
name: report-writer
description: 需要把材料整理成结构化报告时使用
---

# Report Writer
...

注册与查询:

# 注册沙盒内已有目录
$ curl -X POST http://localhost:8080/v1/skills/register \
  -F "path=/home/gem/skills/report-writer"

# 上传 zip
$ curl -X POST http://localhost:8080/v1/skills/register \
  -F "[email protected]" \
  -F "path=/home/gem/skills" \
  -F "name=report-writer"

$ curl http://localhost:8080/v1/skills/metadatas
$ curl http://localhost:8080/v1/skills/report-writer/content

容器内也可用 aio skills list 查看。实践上:description 写清触发场景,大段逻辑放 scripts/,密钥不要写进 Skill。见 SkillsAIO CLI


Code Server

浏览器里的完整 VS Code:http://localhost:8080/code-server/。默认本地跑无鉴权,改的是和 API、终端同一套文件。

推荐目录习惯:

/home/gem/
├── projects/      # 项目
├── Downloads/     # 浏览器下载
└── workspace/     # 当前工作区

Agent 用文件 API 写出代码 → 人在 Code Server 里打开 /home/gem/projects/... 改 → Shell 里 npm run build,路径不用对齐。预装 Node、Python、Git、npm/pip 等。

进阶(扩展、工作目录、纯 API 部署)见 Code ServerCode Server 配置


鉴权

本地调试可以不开;对外暴露端口时,用 JWT(环境变量 JWT_PUBLIC_KEY,内容为 base64 后的 RSA 公钥)。

$ openssl genrsa -out private_key.pem 2048
$ openssl rsa -in private_key.pem -pubout -out public_key.pem
$ export JWT_PUBLIC_KEY=$(cat public_key.pem | base64)

# 启动容器时传入 JWT_PUBLIC_KEY ...

业务侧用私钥签发 JWT,请求带 Header:

$ curl http://localhost:8080/cdp/json/version \
  -H "Authorization: Bearer ${jwt}"

不能带 Header 的场景(例如浏览器直接打开 VNC):先用 JWT 换短时 ticket,再拼 URL:

$ curl -X POST http://localhost:8080/tickets \
  -H "Authorization: Bearer ${jwt}"
# 响应里的 ticket 用于:
# http://localhost:8080/vnc/index.html?ticket=...&path=websockify%3Fticket%3D...

票据默认约 30s,可用 TICKET_TTL_SECONDS 调整。详见 鉴权


串一次完整流程

浏览器抓页 → Jupyter 转 Markdown → Shell 列文件 → 文件 API 拉回本地(体现统一文件系统):

import asyncio, base64
from playwright.async_api import async_playwright
from agent_sandbox import Sandbox

async def main():
    c = Sandbox(base_url="http://localhost:8080")
    home = c.sandbox.get_context().home_dir
    async with async_playwright() as p:
        info = c.browser.get_info().data
        page = await (await p.chromium.connect_over_cdp(info.cdp_url)).new_page()
        await page.goto("https://sandbox.agent-infra.com/", wait_until="networkidle")
        html, shot = await page.content(), base64.b64encode(
            await page.screenshot(type="png")
        ).decode()
    c.jupyter.execute_code(code=f"""
from markdownify import markdownify
open('{home}/site.md','w').write(markdownify('''{html}'''))
""")
    print(c.shell.exec_command(command=f"ls -lh {home}").data.output)
    open("output.md", "w").write(c.file.read_file(file=f"{home}/site.md").data.content)

asyncio.run(main())

Agent 跑在沙盒外(HTTP/MCP)还是沙盒内(127.0.0.1:8080 / aio CLI),见 Agent Call Sandbox vs In Sandbox

延伸阅读

简介 · 快速开始 · 侧边栏「特性」里还有沙盒信息、屏幕录制、预览代理、错误处理等。

Released under the MIT License.