This commit is contained in:
V-LiuShuang
2026-07-29 16:33:23 +08:00
parent 70c80e4048
commit 8979eca3a0

View File

@@ -2,5 +2,240 @@
分析 agentscope、agentscope-java 对于容器沙箱的支持。
## agentscope
## 支持的沙箱类型
| 沙箱类型 | agentscope | agentscope-java | 共同点 |
| --- | --- | --- | --- |
| Docker | ✅ `DockerWorkspace` | ✅ `DockerFilesystemSpec`harness 内置) | 本地隔离、需 Docker |
| Kubernetes | ✅ `K8sWorkspace`Pod + PVC | ✅ `KubernetesFilesystemSpec`extension | 集群级资源、适合生产 K8s |
| E2B | ✅ `E2BWorkspace` | ✅ `E2bFilesystemSpec` | 云沙箱 SDK、metadata/API 重连 |
| Daytona | ✅ `DaytonaWorkspace` | ✅ `DaytonaFilesystemSpec` | 云沙箱、标签/API 重挂接 |
| AgentRun | ❌ 暂未支持 | ✅ `AgentRunFilesystemSpec`(阿里云) | — |
| OpenSandbox | ✅ `OpenSandboxWorkspace` | ❌ 暂未支持 | — |
| Bubblewrap | ✅(另有 Local | ❌(有 LocalFilesystemSpec | Linux 轻量沙箱 / 本机模式 |
### agentscope
| 后端 | 供给方式 | 持久化 | Teardown | Bootstrap |
| --- | --- | --- | --- | --- |
| **Docker** | aiodocker 建容器 | Bind-mount 或 ephemeral | kill + delete 容器 | 镜像已含 gateway |
| **K8s** | Pod + PVC`as-ws-{id}` | PVC 跨 Pod 存活 | 删 Pod默认可保留 PVC | 首次 apt + uv + gateway |
| **E2B** | `AsyncSandbox.create/connect` | pause 保留磁盘 | `pause()` | 首次 bootstrap |
| **Daytona** | SDK create / label 查找 | `stop(force=False)` | stop + close client | 首次 bootstrap路径由 SDK 推导) |
| **OpenSandbox** | `Sandbox.create` / resume / connect | `pause()` | pause + close | 首次 bootstrap |
云后端共性:用 `agentscope.workspace.id`(或等价 metadata/label索引Manager 缓存 miss 时可跨服务副本重连——这是文档推荐的**分布式部署**路径。
[OpenSandbox](https://open-sandbox.ai/getting-started) 是通用沙箱平台Docker/K8s 运行时 + 多语言 SDK。agentscope 通过官方 `opensandbox` SDK
- 按 metadata 过滤 RUNNING/PAUSED 沙箱并 resume/connect
- close 时 **pause** 保文件系统;
- 与 E2B 类似走 `_bootstrap_commands` 安装 gateway。
Java 侧 v2.0.0 **未集成**,若要在 Java 使用需自研 `SandboxClient` 或等待官方 extension。
## 隔离模型
| | agentscope `IsolationPolicy` | agentscope-java `IsolationScope` |
| --- | --- | --- |
| 会话级 | `PER_SESSION` | `SESSION`(沙箱默认) |
| 用户级 | `PER_USER`(跨 agent 慎用) | `USER`(跨 session 共享记忆/快照) |
| Agent 级 | `PER_AGENT`(默认,按 user+agent | `AGENT`(按 agent 名共享) |
| 全局 | 无对等枚举 | `GLOBAL` |
| 绑定时机 | Session 创建时写入 `workspace_id` | 每次 call 用 RuntimeContext 算 isolation key |
### agentscope-java
| 后端 | 模块位置 | 交互方式 | 持久化侧重 |
| --- | --- | --- | --- |
| **Docker** | harness 核心 | CLI | Tar 快照 + 可选 bind |
| **Kubernetes** | extension | fabric8 / Pod 侧 exec+tar文档侧亦描述 agent-sandbox WarmPool 演进) | 快照 Spec集群侧还可结合 PVC/模板 |
| **E2B** | extension | E2B HTTP + envd支持 TAR / NATIVE_SNAPSHOT 等持久化模式 | 平台快照或 tar |
| **Daytona** | extension | Control Plane HTTP API | 快照 Spec不应用 host bind-mount有则 WARN |
| **AgentRun** | extension | 阿里云 AgentRun API可配 NAS/OSS mount、MCP URL | 云侧空闲超时 + 快照 Spec |
公共能力均来自 `SandboxFilesystemSpec``isolationScope``snapshotSpec``executionGuard``workspaceProjection*`
## 架构对比
### agentscope
Workspace + Backend + Gateway
```
WorkspaceManager (服务侧缓存 / TTL / IsolationPolicy)
SandboxedWorkspaceBase.initialize()
├─ _provision_backend() ← Docker/E2B/K8s/Daytona/OpenSandbox 各实现
├─ _ensure_workspace_layout() (/workspace、skills、sessions、data、.mcp)
└─ _setup_mcp_gateway() ← 容器内 FastAPI MCP Gateway
BackendBase (exec_shell / read_file / write_file)
└─ 内置工具 Bash/Read/Write/Edit/Grep/Glob 透明落到沙箱内
```
关键设计点:
1. **模板方法**:子类只实现 `_provision_backend` / `_teardown_backend` / `_bootstrap_commands`
2. **容器内 MCP Gateway**:宿主机通过 `GatewayClient` + `backend.exec_shell` 驱动网关(一般不依赖宿主机到沙箱的端口映射)。
3. **WorkspaceManager**`PER_AGENT` / `PER_SESSION` / `PER_USER`,空闲 TTL 驱逐;云后端可按 metadata/label 跨节点重连。
### agentscope-java
Filesystem Spec + SandboxManager
```
HarnessAgent.Builder.filesystem(DockerFilesystemSpec / …)
SandboxFilesystemSpec.toSandboxContext(hostWorkspaceRoot)
└─ SandboxContext(client, options, snapshotSpec, workspaceSpec, isolationScope)
SandboxLifecycleHook
PreCall → SandboxManager.acquire → Sandbox.start() (四分支恢复)
PostCall → Sandbox.stop() (tar 快照) → persist state → release
SandboxBackedFilesystem + ShellExecuteTool
└─ 文件工具 / execute 全部转发到沙箱
```
关键设计点:
1. **声明式 Spec**`DockerFilesystemSpec` 等只描述「如何创建」,不是运行时文件系统本身。
2. **Call 边界生命周期**:每次推理前后自动 acquire/start/stop适合多租户按次计费与快照恢复。
3. **快照与执行后端正交**:换 Docker/K8s/E2B 不影响 `LocalSnapshotSpec` / `RedisSnapshotSpec` / `OssSnapshotSpec` 的选择。
4. **Workspace Projection**:启动时把宿主 `AGENTS.md``skills/``subagents/``knowledge/` 等打 tar 注入沙箱,按内容 SHA-256 增量跳过。
## 基于Docker的沙箱
双端对照表
| 对比项 | agentscope | agentscope-java |
| --- | --- | --- |
| API 形态 | aiodockerEngine API | docker CLI |
| 保活命令 | `sleep infinity` | `while :; do sleep 3600; done` |
| 镜像策略 | 自动构建并内容哈希缓存 | 用户指定现成镜像 |
| 默认网络 | Docker 默认(通常有网) | **`none`** |
| 持久化 | Bind-mount可选 | Tar 快照为主 + 可选 bind-mount |
| 生命周期 | Workspace 长生命周期 | 按 Agent `call` 借还 |
| MCP | 容器内 Gateway | Harness 侧注册;沙箱只做 FS/Shell |
| 资源限制 | 较弱(构造参数少) | memory / cpu / ports / network |
| 水平扩展 | 不适合 | 需外置快照/状态存储 |
### agentscope
#### 实现原理
1. **镜像构建(内容哈希缓存)**
- `prepare_build_context()` 渲染 Dockerfile打包 gateway 脚本、`requirements.txt`、glob helper。
- Tag 形如 `agentscope-workspace:<12hex>`,对 Dockerfile + COPY 文件做 SHA-256本地已有则跳过 build。
- 默认基础镜像 `python:3.11-slim`,镜像内预装 gateway venv + agentscopeDocker 路径**不做**首次 bootstrap
- 可选 `node_version` 从官方 Node slim 镜像拷贝 `node`/`npm`(供 npx MCP
2. **容器启动**
- 通过 **aiodocker** `containers.create_or_replace`
- `Cmd: ["sleep", "infinity"]`,工作目录 `/workspace`
- Label`agentscope.workspace=true``agentscope.workspace.id=<id>`
- **Gateway 端口仅容器内监听,不做 host port 映射**;宿主经 `DockerBackend.exec` 访问。
3. **持久化**
- 可选 `host_workdir` bind-mount → `/workspace``is_persistent`)。
- 无 mount 则为 ephemeral 容器文件系统。
- Linux 上 teardown 时尝试 `chown` 把 bind-mount 文件所有权还给宿主用户。
4. **I/O 原语(`DockerBackend`**
- `exec_shell`:容器 `exec` API直传 argv无中间 shell需要时包 `sh -c`)。
- `read_file` / `write_file``get_archive` / `put_archive`tar
5. **服务侧**
- `DockerWorkspaceManager``basedir` 下为每个 workspace 建宿主目录并 bind-mountTTL sweeper 回收空闲容器。
#### 使用限制
| 限制 | 说明 |
| --- | --- |
| 依赖 Docker daemon | 需本机/远端可达的 Docker Engine + aiodocker |
| 基础镜像须含 `python3` | Gateway 与工具链假设 Python 可用 |
| **单节点** | 官方文档明确Docker/Local/Bubblewrap 不适配水平扩容;跨节点请用 E2B/Daytona/OpenSandbox/K8s |
| 首次镜像构建成本 | 缓存未命中时 build 较慢;构建失败需解读 docker stream 日志 |
| 无细粒度 CPU/内存 API | 构造参数侧重镜像与环境变量,资源限额不如 Java Spec 直接 |
| Linux bind-mount 权限 | 容器内 root 写文件可能留下错误 uid框架仅在 teardown 做 chown 尽力修复 |
#### 好处
- 镜像内预置 gateway**冷启动无需 apt/uv/pip bootstrap**(对比 E2B/K8s/OpenSandbox
- 内容哈希镜像缓存Dockerfile 不变则秒级复用。
- Workspace 长期存活MCP / skills / sessions 与服务模型一致。
- Bind-mount 可把工作区落在宿主磁盘,便于调试与备份。
-`WorkspaceManager` 隔离策略PER_AGENT 等)无缝衔接。
#### 弊端
- 强依赖本机 Docker水平扩展与多副本亲和困难。
- 常驻 `sleep infinity` 容器占用资源,依赖 TTL 清扫。
- Gateway 健康检查失败时排查需看容器内日志路径。
- 与 Java 版相比,缺少一等公民的「跨 call tar 快照后端」抽象。
### agentscope-java
#### 实现原理
1. **配置层Spec**
Fluent API`image``workspaceRoot`(默认 `/workspace`)、`memorySizeBytes``cpuCount``exposedPorts``network``environment``additionalRunArgs``snapshotSpec``workspaceSpec`
2. **创建与客户端**
- `DockerSandboxClient.create(...)` 生成 `DockerSandboxState`sessionId、镜像、资源参数、快照句柄
- **不引入 docker-java**:一律 `docker run` / `exec` / `inspect` / `stop` / `rm` CLI。
- 要求宿主 `PATH` 上有 `docker`,且 daemon 可达。
3. **容器命令**
```text
docker run -d --name agentscope-sandbox-<sessionId>
[--memory] [--cpus] [-p] [--network=none|...] [-v bind...]
<image> sh -c "while :; do sleep 3600; done"
```
- 默认 **`--network=none`**(未配置 network 时),比 Python 版更偏「默认断网隔离」。
- 支持 `WorkspaceSpec` 中的 `BindMountEntry` → `-v host:container:ro|rw`。
- `exec``docker exec -w <workspaceRoot> <id> sh -c <command>`。
4. **工作区 tar 快照**
- Persist`docker exec tar -cf - -C /workspace .`(并对 bind-mount 路径 `--exclude`)。
- Hydrate`docker exec -i tar -xf - -C /workspace`。
- `AbstractBaseSandbox` **四分支恢复**:容器是否仍保留目录 × 是否有可恢复快照。
5. **编排**
- `start()`:确保容器 running → 四分支初始化 → workspace projection。
- `stop()`:写快照,**容器可继续跑**。
- `shutdown()`:自管容器则 `docker stop` + `docker rm --force`。
#### 使用限制
| 限制 | 说明 |
| --- | --- |
| 依赖 Docker CLI | 无嵌入式 Engine APIWindows/远程 Docker 场景需确保 CLI 行为一致 |
| 默认无网络 | `network` 未设时为 `none`;需要拉包/访问外网必须显式配置 |
| 镜像需自备 | 不像 Python 那样自动构建含 gateway 的专用镜像;由用户指定(如 `ubuntu:24.04` |
| 输出截断 | stdout/stderr 单流约 512KB 上限 |
| 并发语义 | 同一 IsolationScope 并发 call 可起多个容器stop 时 **last-write-wins** 覆盖快照 |
| 多副本 | 本地 Docker + 本地快照会成单点;生产需 Redis/OSS 快照 + 分布式 `AgentStateStore` |
| AgentRun/K8s 等扩展 | Docker 在 harness 核心;其它后端在 extension 模块,需单独依赖 |
#### 好处
- **零额外 Java Docker 库依赖**,部署简单。
- 资源限额CPU/内存)、端口、网络、额外 run args 一等配置。
- 快照体系成熟,可跨 call / 跨副本恢复 `node_modules` 等重状态。
- Workspace projection 把静态资产与运行态分离,宿主改 skills 可增量注入。
- `IsolationScope`SESSION/USER/AGENT/GLOBAL覆盖多租户 SaaS 常见模型。
- `executionGuard` 可对 AGENT/GLOBAL 做串行化,缓解快照互踩。
#### 弊端
- 每次 call 的 start/stop/snapshot 有固定开销(尤其大工作区 tar
- CLI 进程模型:高并发时大量 `docker exec` 子进程与线程池开销。
- 无内置 MCP GatewayMCP 走 Harness 侧 `tools.json` 注册,与沙箱内进程模型不同。
- 默认断网 + 裸镜像,冷启动后常需 agent 自己装依赖(靠快照摊销)。