一套 AI Agent 沙箱基础设施:SDK + 自托管 Web 控制台,让 Agent 的每一步操作都可观测、可追溯、可回放
当 AI Agent 开始在你的服务器上执行命令、读写文件、创建容器时,你真的知道它做了什么吗?
链接:
为什么做这件事
过去几个月,AI Agent 从"能聊天"进化到了"能干活"。Deep Agents、Manus、各种 Coding Agent 纷纷落地,它们需要真实的 Linux 环境来执行代码、安装依赖、运行测试。
但一个问题始终悬在工程师头上:
Agent 在沙箱里到底做了什么?出了问题怎么排查?删了什么文件?执行了什么命令?什么时候失败的?
市面上不缺沙箱运行时——E2B 用 Firecracker,Daytona 自研运行时,阿里开源了 OpenSandbox。但它们要么是纯 SaaS(数据不在自己手里),要么只提供基础 SDK(没有管理界面),没有一套方案能同时解决"给 Agent 用"和"给人看"这两个需求。
所以我做了两个开源项目,组合起来解决这个问题:
-
Agent Sandbox Backend SDK(
agent-sandbox-backends)— 面向 AI Agent 的 OpenSandbox 适配 SDK,一行代码接入 Deep Agents 框架,内置沙箱内操作历史数据库、并发控制、文件上传安全策略 -
Sandbox Explorer(
sandbox-explorer)— 自托管 Web 控制台,浏览器里管理沙箱、浏览文件、执行命令、打开终端、查看完整操作历史
两者通过沙箱内的 SQLite 历史数据库松耦合协作:SDK 写入,Console 读取,沙箱删除则历史一起删除,生命周期完全对齐。
整体架构
先看全貌:
┌─────────────────────────────────────────────┐ │ 你的 Python 进程 │ │ │ │ ┌───────────────────────────────────┐ │ │ │ Deep Agents / 你的 Agent 代码 │ │ │ └──────────────┬────────────────────┘ │ │ │ as_deepagents_backend() │ │ ┌──────────────▼────────────────────┐ │ │ │ agent-sandbox-backends (SDK) │ │ │ │ │ │ │ │ ┌─────────┐ ┌───────────────┐ │ │ │ │ │Operation│ │ History │ │ │ │ │ │Pipeline │──│ Store │ │ │ │ │ └────┬────┘ └───────┬───────┘ │ │ │ │ │ │ │ │ │ │ ┌────▼────┐ ┌───────▼───────┐ │ │ │ │ │Provider │ │ Concurrency │ │ │ │ │ │Adapter │ │ KeyedRWLock │ │ │ │ │ └────┬────┘ └───────────────┘ │ │ │ │ │ │ │ │ │ │ ┌────▼────┐ ┌───────▼───────┐ │ │ │ │ │ Upload │ │ Security │ │ │ │ │ │ Scanner │ │ Scanner │ │ │ │ │ └─────────┘ └───────────────┘ │ │ │ └───────────────────────────────────┘ │ │ │ HTTP/gRPC │ └──────────────────┼─────────────────────────┘ │ ┌──────────────────▼─────────────────────────┐ │ OpenSandbox 沙箱运行时 │ │ │ │ ┌──────────────────────────────────────┐ │ │ │ 沙箱实例 (Sandbox) │ │ │ │ │ │ │ │ /workspace/ ← Agent 工作目录 │ │ │ │ /.agent-history/ │ │ │ │ └── history.sqlite3 ← 操作历史DB │ │ │ │ /.agent-helper/ ← 历史写入工具 │ │ │ └──────────────────────────────────────┘ │ └──────────────────┬─────────────────────────┘ │ ┌──────────────────▼─────────────────────────┐ │ Sandbox Explorer (Web Console) │ │ │ │ ┌────────────┐ ┌────────┐ ┌──────────┐ │ │ │ File Browse │ │Command │ │ Terminal │ │ │ │ (Monaco) │ │(SSE) │ │(xterm.js)│ │ │ └────────────┘ └────────┘ └──────────┘ │ │ │ │ ┌──────────────────────────────────────┐ │ │ │ History Timeline (历史时间线) │ │ │ │ SDK 操作 + Console 操作 统一展示 │ │ │ └──────────────────────────────────────┘ │ └────────────────────────────────────────────┘
核心设计思想:
-
SDK 不实现沙箱运行时,而是适配 OpenSandbox,让 Deep Agents 框架能用一行代码接入
-
操作历史写在沙箱内的 SQLite 里,而非 Web 后端,沙箱删除则历史自动清除,生命周期完全对齐
-
Console 和 SDK 互不感知,通过沙箱内的历史数据库松耦合协作
-
Console 是可选的,SDK 独立工作不受影响;Console 独立工作也能直连沙箱
项目一:Agent Sandbox Backend SDK
仓库:Rainbow0328/agent-sandbox-backend PyPI 包名:agent-sandbox-backends
一行代码接入 Deep Agents
from agent_sandbox_backends import CleanupPolicy, create_opensandbox_backend from agent_sandbox_backends.integrations.deepagents import as_deepagents_backend from deepagents import create_deep_agent # 创建 Backend core_backend = await create_opensandbox_backend( "http://your-opensandbox-service:8080", cleanup=CleanupPolicy.ON_CLOSE, ) # 一行转换为 Deep Agents 后端 backend = as_deepagents_backend(core_backend) # 交给 Deep Agents agent = create_deep_agent(model=model, backend=backend)
Deep Agents 的文件查看、读取、写入、编辑、搜索、上传、下载和命令执行,全部自动适配到 OpenSandbox 沙箱。你不需要自己写任何 Adapter 代码。
沙箱内操作历史(核心差异化)
这是我认为这个项目最有价值的部分。
问题:Agent 在沙箱里执行了 50 条命令、改了 20 个文件,中间某一步失败了。你怎么排查?E2B 不记录,Daytona 不记录,OpenSandbox 官方 SDK 也不记录。
方案:SDK 的 OperationPipeline 在每次操作前后自动写入沙箱内的 /.agent-history/history.sqlite3,完整记录:
| 字段 | 说明 |
|---|---|
event_id |
全局唯一操作 ID(UUIDv7,时间有序) |
operation_type |
操作类型(command.execute / file.write / sandbox.create 等) |
status |
started / succeeded / failed / cancelled / timeout |
actor_type |
执行者类型(agent / system / console / user) |
actor_id |
执行者标识 |
thread_id |
会话线程 ID |
run_id |
运行批次 ID |
correlation_id |
关联 ID,用于追踪操作链 |
request_json |
完整请求参数 |
result_json |
完整结果 |
duration_ms |
耗时 |
stdout/stderr |
完整命令输出(分块存储,支持流式读取) |
occurred_at |
发生时间 |
completed_at |
完成时间 |
关键设计:
-
四种历史模式:
NONE(不记录)、PROVIDER(记到 Provider 端)、DATABASE(记到外部 PostgreSQL)、SANDBOX(记到沙箱内 SQLite,默认) -
TTL + 容量限制:默认 7 天过期,数据库最大 128MB,单次操作输出最大 16MB,超限自动删除最旧记录
-
增量同步:基于
history_changes变更日志 +history_consumers消费者游标,Console 只拉取增量 -
分布式租约:
history_leases表防止多个消费者同时清理历史 -
输出分块存储:大命令输出分 16KB 块存储,支持流式读取,不会因为一次
cat大文件就把数据库撑爆
安全保证:API Key 不会写入历史,但命令字符串会——所以不要把密码拼进命令里,优先用环境变量传递。
并发控制:KeyedRWLock
当多个子 Agent 同时操作同一沙箱时,SDK 提供 Writer-preferring Keyed Read/Write Lock:
# 多个 Agent 可以同时读同一个文件(共享锁)
async with backend._lock.read("/workspace/data.json"):
content = await backend.read_file("/workspace/data.json")
# 写操作排他(写优先,防止写饥饿)
async with backend._lock.write("/workspace/data.json"):
await backend.write_file("/workspace/data.json", new_content)
-
Writer-preferring:有等待中的写锁时,新读锁会让路,防止写饥饿
-
Keyed:不同文件不互相阻塞,粒度细
-
Idle-state cleanup:无引用的锁自动清理,不泄漏内存
-
超时控制:支持
timeout_seconds,防止死锁
文件上传安全
SDK 不会默认允许任意本地路径上传。必须显式声明允许的根目录:
from pathlib import Path from agent_sandbox_backends import UploadConfig, UploadSpec, create_opensandbox_backend backend = await create_opensandbox_backend( "http://your-opensandbox-service:8080", uploads=(UploadSpec(source="./project", target="/workspace/project"),), upload_config=UploadConfig(allowed_local_roots=(Path.cwd(),)), )
上传安全策略覆盖:
| 防护层 | 说明 |
|---|---|
| 路径逃逸防护 | 检查 .. 和绝对路径,防止写到沙箱任意位置 |
| 符号链接防护 | 检测 symlink,防止读到宿主机敏感文件 |
| 特殊文件防护 | 跳过 .env、.ssh、.aws、.git、虚拟环境 |
| 归档炸弹防护 | 限制解压后总大小和文件数量 |
| 校验和验证 | 上传后重新读取验证 SHA256,防止传输损坏 |
| Staging + 提交 | 先写暂存区,校验通过后原子提交,失败自动回滚 |
| 冲突策略 | 支持 skip / overwrite / if_changed(只覆盖有变化的) |
| 文件数量限制 | 默认单次上传最多 10000 个文件 |
| 总大小限制 | 默认单次上传最大 1GB |
Actor 上下文追踪
每个操作都携带完整的执行者上下文:
with backend.agent_context(
agent_id="research-agent",
thread_id="thread-1",
run_id="run-1",
):
await backend.execute("python --version")
# 这条命令的历史记录会带上 agent_id="research-agent"
correlation_id 自动生成并贯穿整个上下文范围内的所有操作,方便在历史时间线中追踪一次完整的 Agent 运行。
项目二:Sandbox Explorer(Web 控制台)
仓库:Rainbow0328/sandbox-web npm 包名:sandbox-explorer
一键启动
# 生产模式:构建前端 + 后端服务 python start.py # 开发模式:前后端热更新 python start.py --dev # Docker docker compose up -d
打开浏览器,就是完整的沙箱管理控制台。无需配置环境变量,认证默认关闭,开箱即用。
全功能沙箱管理
沙箱生命周期:创建、暂停、恢复、删除,支持通过 Connection 快速创建,也支持直接输入 URL + API Key 创建。
文件浏览器:
-
目录树浏览,支持面包屑导航
-
Monaco Editor 在线编辑代码(和 VS Code 同款编辑器)
-
上传文件(支持选择目标目录的自定义弹窗)
-
下载文件
-
创建文件夹(自定义弹窗,不用浏览器 prompt)
-
删除文件/文件夹
命令执行器:
-
SSE 实时流式输出,命令执行过程中可以看到逐行输出
-
支持中断正在执行的命令
-
命令历史记录
交互式终端:
-
基于 xterm.js + WebSocket 的完整交互终端
-
支持 Ctrl+C、Tab 补全、颜色输出
-
和真实终端体验一致
操作历史时间线(核心功能)
这是 Console 最有价值的页面。它会从沙箱内的 history.sqlite3 同步操作记录,并和 Console 自己的操作日志合并展示,形成一个统一的时间线。
你会看到什么:
-
SDK 的操作:Agent 执行的每一条命令、每一次文件写入、每一次沙箱创建
-
Console 的操作:你在 Web 界面上执行的命令、上传的文件、创建的文件夹
-
完整上下文:谁执行的(actor_type)、耗时多少、成功还是失败、完整的请求参数和结果
历史时间线的设计:
┌─────────────────────────────────────────────────────────────┐
│ History Timeline │
│ │
│ ┌─ 14:32:01 ─ [SDK] sandbox.create ✅ succeeded 120ms│
│ │ actor: research-agent | run: run-1 │
│ │ request: { image: "python:3.12", workdir: "/workspace" }│
│ └───────────────────────────────────────────────────────────│
│ │
│ ┌─ 14:32:05 ─ [SDK] command.execute ✅ succeeded 2.1s│
│ │ actor: research-agent | run: run-1 │
│ │ command: pip install fastapi │
│ │ ▸ stdout: Collecting fastapi... (点击展开) │
│ └───────────────────────────────────────────────────────────│
│ │
│ ┌─ 14:35:12 ─ [Console] file.write ✅ succeeded 45ms│
│ │ actor: admin | path: /workspace/main.py │
│ └───────────────────────────────────────────────────────────│
│ │
│ ┌─ 14:35:30 ─ [SDK] command.execute ❌ failed 5.0s │
│ │ actor: research-agent | run: run-1 │
│ │ command: python main.py │
│ │ ▸ stderr: ModuleNotFoundError: No module named 'uvicorn' │
│ └───────────────────────────────────────────────────────────│
└─────────────────────────────────────────────────────────────┘
技术实现:
-
Console 通过 SDK 的
SandboxHistoryStore读取沙箱内 SQLite -
基于
history_changes变更日志做增量同步,只拉取上次同步之后的新记录 -
消费者游标(
history_consumers)记录已确认的 seq,支持多 Console 实例独立消费 -
Console 自己的操作也会写入沙箱历史(best-effort),确保 SDK 和 Console 的操作在同一个时间线里
-
历史同步是限流的,不会阻塞正常操作
连接管理
Console 可以管理多个 OpenSandbox 服务连接,凭据使用 Fernet 对称加密存储:
端口可配置
支持通过 CLI、环境变量或 .env 文件配置端口:
# CLI python start.py --port 3000 --frontend-port 3001 # 环境变量 EXPLORER_PORT=3000 python start.py # .env 文件 echo "EXPLORER_PORT=3000" > .env python start.py
实战演示:Deep Agents + OpenSandbox + Web Console
场景:用 Deep Agents 在沙箱里做代码审查
import asyncio
from agent_sandbox_backends import CleanupPolicy, create_opensandbox_backend
from agent_sandbox_backends.integrations.deepagents import as_deepagents_backend
from deepagents import create_deep_agent
async def main():
# 1. 创建沙箱 Backend
backend = await create_opensandbox_backend(
"http://your-opensandbox-service:8080",
sandbox_name="code-review-session",
image="python:3.12",
cleanup=CleanupPolicy.NEVER, # 不自动删除,方便后续在 Console 查看
)
# 2. 转换为 Deep Agents 后端
da_backend = as_deepagents_backend(backend)
# 3. 创建 Agent
agent = create_deep_agent(
model="claude-sonnet-4-20250514",
backend=da_backend,
)
# 4. 设置 Actor 上下文
with backend.agent_context(
agent_id="code-reviewer",
thread_id="review-001",
run_id="run-20260720",
):
# 5. 让 Agent 审查代码
result = await agent.run(
"Clone https://github.com/example/repo, "
"review the codebase for security issues, "
"and write a report to /workspace/report.md"
)
print(f"Review complete: {result}")
# 6. 不关闭 Backend(cleanup=NEVER),沙箱保留
# 7. 打开 Web Console 查看完整操作历史!
asyncio.run(main())
运行完毕后,打开 Sandbox Explorer:
-
在沙箱列表找到
code-review-session -
Files 标签页:查看 Agent 生成的
report.md -
History 标签页:查看 Agent 执行了哪些
git clone、grep、python命令,每条命令的完整输出 -
Terminal 标签页:进入沙箱终端,自己验证 Agent 的发现
这就是"可观测的 AI Agent"——不是黑盒,是透明盒子。
安全设计
安全是这套系统的核心设计目标,不是事后补丁:
SDK 侧
| 安全机制 | 说明 |
|---|---|
| 上传路径白名单 | 必须显式声明 allowed_local_roots,默认不允许任何路径 |
| 符号链接检测 | 扫描所有上传文件,遇到 symlink 直接拒绝 |
| 特殊文件排除 | 自动排除 .env、.ssh、.aws、.git、__pycache__、node_modules |
| 归档炸弹防护 | 限制解压后总大小(默认 1GB)和文件数量(默认 10000) |
| 校验和验证 | 上传后重新读取并校验 SHA256,防止传输损坏 |
| Staging + 原子提交 | 先写暂存区,全部校验通过后原子提交,失败自动回滚 |
| API Key 不入历史 | 历史记录中不保存 API Key,但命令字符串会保存(注意不要拼密码) |
| 并发 KeyedRWLock | Writer-preferring,防止写操作饥饿 |
| 操作活动门控 | 关闭/删除沙箱时等待所有活动操作完成,阻止新操作进入 |
Console 侧
| 安全机制 | 说明 |
|---|---|
| 凭据加密存储 | API Key 使用 Fernet 对称加密(AES-128-CBC + HMAC-SHA256) |
| Master Key 可配 | 通过 EXPLORER_MASTER_KEY 环境变量配置加密密钥 |
| Admin Token 认证 | 可选的 Bearer Token 认证,空则禁用(本地开发友好) |
| 路径逃逸防护 | 文件操作做 POSIX 路径校验,防止 .. 逃逸 |
| CORS 可配 | 通过 EXPLORER_CORS_ORIGINS 限制跨域 |
| WebSocket Token 验证 | 终端 WebSocket 连接需要有效 Token |
与同类产品的对比
| 能力 | 本方案 | E2B | Daytona | OpenSandbox 官方 SDK |
|---|---|---|---|---|
| 沙箱运行时 | OpenSandbox | E2B (Firecracker) | Daytona 自研 | OpenSandbox |
| Deep Agents 原生集成 | ✅ 一行代码 | ❌ 需自己封装 | ❌ 需自己封装 | ❌ 无 |
| 沙箱内操作历史 DB | ✅ 完整 Schema | ❌ | ❌ | ❌ |
| 自托管 Web 控制台 | ✅ 全功能 | ❌ SaaS 为主 | ❌ CLI 为主 | ❌ 无 |
| 文件上传安全策略 | ✅ 9 层防护 | ❌ | ❌ | ❌ |
| 并发控制 (KeyedRWLock) | ✅ | ❌ 基础 | ❌ 基础 | ❌ 基础 |
| 文件浏览器 | ✅ Monaco 编辑器 | ❌ | ❌ | ❌ |
| 交互式终端 | ✅ xterm.js | ❌ | ❌ | ❌ |
| SSE 流式命令输出 | ✅ | ❌ | ❌ | ❌ |
| 多沙箱连接管理 | ✅ 加密凭据 | ❌ | ❌ | ❌ |
| 部署方式 | Docker / 本地 | SaaS / 自建 | CLI / SaaS | SDK only |
| 开源协议 | Apache-2.0 | Apache-2.0 | Apache-2.0 | Apache-2.0 |
一句话总结差异化:E2B 和 Daytona 是"自己做运行时 + 自己做 SDK + 做 SaaS 管理界面"的全栈方案;本方案是"适配 OpenSandbox + 做 Deep Agents 桥梁 + 做自托管全功能控制台 + 做沙箱内操作历史"的补充方案。不竞争,互补。
技术栈
SDK(agent-sandbox-backends):
-
Python 3.11+
-
Pydantic v2(领域模型)
-
SQLAlchemy 2.0 + aiosqlite / asyncpg(历史存储)
-
pathspec(上传安全扫描)
-
Hatchling(构建)
-
Ruff + Pyright(代码质量)
Console(sandbox-explorer):
-
后端:FastAPI + SQLAlchemy + aiosqlite
-
前端:React 18 + TypeScript + Vite
-
UI:Tailwind CSS + lucide-react
-
状态管理:Zustand + TanStack Query
-
编辑器:Monaco Editor (@monaco-editor/react)
-
终端:xterm.js + WebSocket
-
打包:Docker multi-stage build
快速上手
1. 安装 SDK
git clone https://github.com/Rainbow0328/agent-sandbox-backend.git cd agent-sandbox-backend pip install -e ".[deepagents]"
2. 启动 Web Console
git clone https://github.com/Rainbow0328/sandbox-web.git cd sandbox-web python start.py
3. 用 SDK 创建沙箱并执行操作
from agent_sandbox_backends import create_opensandbox_backend
backend = await create_opensandbox_backend(
"http://your-opensandbox-service:8080",
sandbox_name="my-first-sandbox",
)
with backend.agent_context(agent_id="my-agent"):
result = await backend.execute("echo 'Hello from sandbox!'")
print(result.stdout)
4. 打开浏览器查看
打开 http://localhost:8080,在沙箱列表中找到 my-first-sandbox,点击进入,切换到 History 标签页,你就能看到刚才那条 echo 命令的完整记录。
开源信息
| 项目 | 仓库 | 包名 | 协议 |
|---|---|---|---|
| Agent Sandbox Backend SDK | Rainbow0328/agent-sandbox-backend | agent-sandbox-backends (PyPI) |
Apache-2.0 |
| Sandbox Explorer | Rainbow0328/sandbox-web | sandbox-explorer (npm) |
Apache-2.0 |
欢迎 Star、Issue、PR!
路线图
SDK
- 更多 Provider 适配器(E2B、Daytona)
- 历史数据导出(JSON / CSV)
- Webhook 通知(操作失败时回调)
- 更丰富的 Actor 权限模型
Console
- 沙箱快照与回滚
- 多用户协作(同时操作同一沙箱)
- 操作历史搜索与过滤
- 暗色主题
- 国际化(i18n)
写在最后
AI Agent 正在从"能聊天"走向"能干活"。当 Agent 真正开始操作你的服务器时,可观测性不是锦上添花,是安全底线。
这套方案的核心价值不是"又造了一个沙箱",而是:
-
让 Agent 的每一步操作都有据可查——操作历史是设计的,不是事后补的
-
让数据生命周期对齐——沙箱删除,历史一起删除,不残留
-
让管理界面可以自托管——数据在自己手里,不在 SaaS 平台
-
让 Deep Agents 一行代码接入——降低 Agent 开发门槛
如果你也在做 AI Agent 相关的项目,如果你也需要在沙箱里运行 Agent 代码,欢迎试试这套方案。
如果觉得有用,给个 Star 是对开源作者最大的鼓励 🙏
本文涉及的两个项目均为 Apache-2.0 开源协议,可免费用于商业用途。
更多推荐


所有评论(0)