架构
你的智能体 / SDK / CLI
│ HTTPS
▼
┌──────────────────────────────┐
│ 控制面 (pkg/server) │ 调度 · 隧道 · 策略 · API
└──────────────┬───────────────┘
│ 反向 WebSocket + yamux ← worker 主动拨出
▼
┌──────────────────────────────┐
│ worker (cmd/poder) │ 一台机器上的 Docker 生命周期
└──────────────┬───────────────┘
│ 容器网络
▼
┌──────────────────────────────┐
│ toolbox(在沙箱内) │ 代码执行 · PTY · 文件
└──────────────────────────────┘控制面
pkg/server 就是整个 API:把创建调度到某个 worker、持有隧道对象、做鉴权和配额、 调用准入闸门、发出生命周期事件。它可以作为库被 import —— server.New(...) 返回的 handler 就是命令行二进制在服务的那个 handler —— 商业构建正是靠这一点加上账号和 计费,而不需要 fork。
持久化可以是 SQLite(单实例)或 PostgreSQL(机队)。schema 只做加法:旧二进制能在 新 schema 上跑,这也是"回滚只是改个镜像 tag"的原因。
Worker
cmd/poder 跑在有 Docker socket 的机器上。它向控制面拨一次号,然后一直保持这条 连接:worker 上不开放任何入站端口。正是这条性质,让它能用在 NAT 后面的笔记本、 客户的虚拟机、或者员工工位上。
通过这条隧道它收到"建这个容器""删那个容器",并把执行请求转发给每个沙箱内的 toolbox。
Toolbox
cmd/toolbox 跑在每个沙箱内部。真正执行代码的是它:语言运行时、PTY、文件操作、 流式输出、端口预览代理。它在容器内监听 8080,外面不直接访问它。
Agent(不需要 Docker)
cmd/agent 把本机自身注册成沙箱,内嵌 toolbox。这就是 SandrPod 能跑在 macOS 笔记本 或没有 Docker 的裸机上的方式:机器本身就是沙箱。同一个二进制还带着权限闸门、决策 审计、出网策略,以及操作系统级沙箱(bwrap、seatbelt)。
一个请求实际做了什么
对运行中的沙箱发 POST /sandboxes/execute:
- 控制面鉴权、解析沙箱、校验归属;
- 找到该沙箱所属 worker 的隧道 —— 本地,或在某个对端实例上(那就转发,见 多实例);
- 在隧道上开一条 yamux 流,请求访问 toolbox;
- worker 通过网络连接容器内的 toolbox;
- toolbox 执行进程,把结果沿原路返回。
延迟主要由进程决定,而不是这些跳数:隧道是一条热连接,不是每个请求新建一条。
八家云厂商,两种机制
在云上创建 worker,八家的流程形状一致,底下有两种远程执行机制:
| 机制 | 厂商 |
|---|---|
| 托管命令通道 | AWS(SSM)、阿里云(云助手)、Azure、腾讯云(TAT)、Oracle |
| 临时密钥 SSH | GCP、DigitalOcean、Hetzner |
两种方式殊途同归:机器启动、装 Docker、带 join token 启动 worker、控制面等它上线。 如果它一直不上线,那台机器会被终止而不是留着计费 —— 这条流程里每个失败分支都会 把机器还回去。
接下来读什么
- Worker 与隧道 —— 这条连接、它的身份、它的生命周期。
- 隔离与放置 —— 谁能跑在谁上面。
- 生产部署 —— 真实流量前推荐采用的形态。