Files
tmp/agentscope-sandbox.md
V-LiuShuang 28f3727f43 add
2026-07-29 17:25:12 +08:00

200 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Intro
分析 agentscope、agentscope-java 对于容器沙箱的支持。
## 支持的沙箱类型
| 沙箱类型 | agentscope | agentscope-java |
| --- | --- | --- |
| Docker | ✅ `DockerWorkspace` | ✅ `DockerFilesystemSpec` |
| Kubernetes | ✅ `K8sWorkspace`| ✅ `KubernetesFilesystemSpec` |
| E2B | ✅ `E2BWorkspace` | ✅ `E2bFilesystemSpec` |
| Daytona | ✅ `DaytonaWorkspace` | ✅ `DaytonaFilesystemSpec` |
| AgentRun | ❌ | ✅ `AgentRunFilesystemSpec` |
| OpenSandbox | ✅ `OpenSandboxWorkspace` | ❌ |
| Bubblewrap | ✅(依赖操作系统) | ❌ |
## 架构对比
### 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 透明落到沙箱内
```
关键设计:
- **容器内 MCP Gateway**:宿主机通过 `GatewayClient` + `backend.exec_shell` 驱动网关(一般不依赖宿主机到沙箱的端口映射)。
- **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 全部转发到沙箱
```
关键设计:
- **生命周期管理**:每次推理前后自动 acquire/start/stop适合多租户与快照恢复。
- **快照与沙箱解耦**:换 Docker/K8s/E2B 不影响 `LocalSnapshotSpec` / `RedisSnapshotSpec` / `OssSnapshotSpec` 的选择。启动时把宿主 `AGENTS.md``skills/``subagents/``knowledge/` 等打 tar 注入沙箱,按内容 SHA-256 增量跳过。
## Docker沙箱双端对照表
| 对比项 | agentscope | agentscope-java |
| --- | --- | --- |
| API 形态 | Docker Engine API | CLI |
| 保活命令 | `sleep infinity` | `while :; do sleep 3600; done` |
| 镜像策略 | all-in-one镜像自动构建并内容哈希缓存 | 用户指定 |
| 默认网络 | Docker 默认| 用户指定 |
| 持久化 | Bind-mount可选 | Tar 快照为主 + 可选 bind-mount |
| 生命周期 | Workspace 长生命周期 | 按 Agent `call` 借还 |
| MCP | 容器内 Gateway | Harness 侧注册;沙箱只做 FS/Shell |
| 资源限制 | 较弱(构造参数少) | memory / cpu / ports / network |
| 水平扩展 | 不适合 | 需外置快照/状态存储 |
关键agentscope 通过 HTTP API 端点和 Docker 引擎交互agentscope-java 通过 cli 与 Docker 引擎交互。明显 agentscope 的设计更靠谱一些,因为通过 HTTP API 端点交互有2个好处
- agentscope 实例本身可以容器化部署,而 agentscope-java 必需在宿主机用 `java -jar` 运行,因为它需要在宿主机上执行 `docker run` 命令。
- 通过 HTTP API 端点 agentscope 可以控制远程服务器上的 Docker 容器。
### 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 自己装依赖(靠快照摊销)。