Skip to content
View as Markdown

架构 ​

        你的智能体 / 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:

  1. 控制面鉴权、解析沙箱、校验归属;
  2. 找到该沙箱所属 worker 的隧道 —— 本地,或在某个对端实例上(那就转发,见 多实例);
  3. 在隧道上开一条 yamux 流,请求访问 toolbox;
  4. worker 通过网络连接容器内的 toolbox;
  5. toolbox 执行进程,把结果沿原路返回。

延迟主要由进程决定,而不是这些跳数:隧道是一条热连接,不是每个请求新建一条。

八家云厂商,两种机制 ​

在云上创建 worker,八家的流程形状一致,底下有两种远程执行机制:

机制厂商
托管命令通道AWS(SSM)、阿里云(云助手)、Azure、腾讯云(TAT)、Oracle
临时密钥 SSHGCP、DigitalOcean、Hetzner

两种方式殊途同归:机器启动、装 Docker、带 join token 启动 worker、控制面等它上线。 如果它一直不上线,那台机器会被终止而不是留着计费 —— 这条流程里每个失败分支都会 把机器还回去。

接下来读什么 ​

Apache 2.0 — your clouds, your machines, your rules.