提案:将整个智能体(含 LLM 调用)完全运行在 Docker 沙盒内
2026-06-17
约 17,000 行核心代码
无状态执行器,通过 docker exec 桥接
Host (Python) Sandbox (Docker) ┌─────────────────────┐ ┌──────────────────┐ │ ChatOrchestrator │ │ │ │ ├─ agent_loop() │ docker exec │ bash / file / │ │ ├─ LLM Client ───────────────────▶│ skill runner │ │ ├─ Tool Registry │ ◀─────────── │ │ │ ├─ Session Mgr │ stdout/exit │ │ │ └─ SocketBridge ──▶│ WebSocket └──────────────────┘ └─────────────────────┘
Host (精简) Sandbox (Docker)
┌─────────────────────┐ ┌──────────────────────┐
│ 容器管理 │ docker exec │ 完整 agent 进程 │
│ 事件流转发 │ ◀──stdout──── │ ├─ agent_loop() │
│ WebSocket 推流 │ │ ├─ LLM Client │
│ 持久化存储? │ │ ├─ Tool Registry │
└─────────────────────┘ │ ├─ Session Mgr? │
│ ├─ Skill 系统 │
│ └─ 本地 bash/file │
└──────────────────────┘
核心想法:host 退化为「容器管理 + 事件转发」,智能体决策和工具执行都在同一个进程内完成。
| 模块 | 代码量 | 原因 |
|---|---|---|
| SessionExecutionRuntime | ~800 行 | session routing 层不再需要 |
| SandboxProvider / DockerSandboxProvider | ~3000 行 | Docker exec 桥接全部消除 |
| BashToolProvider / FileToolProvider | 部分简化 | 直接用 subprocess / os,无需代理 |
| tool_host/ IO 隔离约束 | — | 不再需要强制走 runtime protocol |
预估可消除约 ~3,800 行桥接代码(占总量 ~20%)
| 模块 | 代码量 | 原因 |
|---|---|---|
| agent_loop() | ~1,100 行 | 核心循环逻辑,跟执行位置无关 |
| ChatOrchestrator | ~1,000 行 | 编排、prompt 构建、compaction、memory |
| Session 管理 | ~1,500 行 | 历史持久化、分支、rewind |
| Skill 系统 | ~3,500 行 | 语义搜索、解析、adapter 缓存 |
| LLM Client | ~800 行 | 模型适配、流式处理、image 压缩 |
| Engine 组装 (mixins) | ~4,000 行 | fork/resume、background、replay |
| Hook & Event & Projection | ~1,000+ 行 | 业务管道,不随执行位置变化 |
约 ~13,000 行业务代码不会因架构变更而简化(占总量 ~80%)
关键问题:复杂性不会消失,只是搬家
Host 确实变轻了,但容器内进程接管了全部复杂性。而且会引入新的问题:
Session index (SQLite)、history (JSONL) 目前在 host 管理。如果 agent 在容器内,要么容器维护状态(容器销毁 = 数据丢失),要么 RPC 回传到 host —— 又回到了「桥接」模式,只是方向反了。
目前一个 host 进程服务所有用户,session routing 隔离。每个 session 一个容器内 agent 进程 → 容器调度 + 内存开销显著增加。
LLM API key 需要注入到每个容器。当前只有 host 进程持有密钥,安全边界清晰。容器化后,每个沙盒都是攻击面。
目前 host 内存中 EventHandler → SocketBridge,零延迟。容器化后需要新的事件通道(stdout JSON lines / Unix socket / gRPC),增加序列化开销和调试复杂度。
Compaction、Memory、Skill Registry 等需要全局资源。要么部署进容器(镜像膨胀),要么 API 回调 host(又是 RPC 桥接,只是方向反了)。
桥接方向对比
现在: Host ──docker exec──▶ Sandbox (工具执行桥接) 提案: Host ◀──RPC/stdout── Sandbox (状态/资源桥接) 桥接层并没有消失,只是换了方向和内容。
嵌入式的诉求是合理的,但正确的路径不是「搬进容器」,而是做一个可独立运行的 agent binary。
不建议走「整个 agent 跑在沙盒里」这条路
Engine 的 4,000 行 mixin 是真正的复杂性根源。将 Engine 从「上帝对象 + mixin 拼装」重构为「组合式服务」,效果远大于搬迁执行位置。
core 只包含 loop + protocols(类似 Anthropic Agent SDK)。host 变成「BladeAI 的一种实现」。第三方可以用 core 接自己的 LLM / 工具 / 存储。
core + 精简 host(去掉 Docker / Server)打包为单进程,stdin/stdout 事件流。可跑在 ARM / 嵌入式设备。工具执行直接本地,无需容器。