跳转到内容

OpenSandbox 1.1.1:整体架构

本文回答三个问题:OpenSandbox 是什么?内部怎样分层?一次 AI 动作从产生到回收,怎样穿过这套系统? 教材基于 release-1.1.1(提交 531700ca,2026-10-09 发布)。路径均相对 $OSB_SRC。 用法:先读本文建立总图,再用学习路线安排节奏;每个阶段只深挖这条主线中的一段。

一、先理解问题,再理解项目

跳转到“一、先理解问题,再理解项目”

AI 应用一旦从“聊天”走向“做事”,就会遇到一个根本变化:模型输出不再只是文本,而是会变成动作。

动作可能是:

  • 运行模型生成的 Python、Shell 或 Node.js 代码;
  • 读写工作区文件,修改仓库,生成报告;
  • 启动浏览器、桌面或 HTTP 服务;
  • 访问包索引、模型 API、数据库或对象存储;
  • 长时间运行任务,并在之后恢复上下文。

如果这些动作直接发生在你的服务器上,风险会立刻出现:

  1. 代码不可信:模型可能写错、死循环、删除文件、耗尽内存。
  2. 数据不可信:网页、文档、工具结果都可能藏着提示注入。
  3. 边界不清:一次会话的进程和文件不能污染另一次会话。
  4. 网络失控:模型可能把数据发往任意地址,或下载不可信依赖。
  5. 资源失控:并发 Agent 可能同时拉爆 CPU、内存和磁盘。
  6. 运维困难:任务失败后,要能判断问题出在模型、工具、沙箱还是网络。

OpenSandbox 的定位可以用 README 的一句话概括:

Run AI agents in sandboxes on your own infrastructure.

它不是模型,不是 Agent 框架,也不是一个只能跑代码的在线 IDE。它提供的是 AI 应用与不可信执行之间的基础设施层:用统一 API 创建隔离环境,再通过命令、文件和代码接口,把模型动作安全地放进去执行。

初学时有三个误解,必须先排除:

误解 实际情况
“它替我做 Agent 编排” 不。它提供执行环境;循环、提示词、模型选择、工具调度仍由你的 Agent 负责。
“它就是一个 Docker 容器” 不。它是平台:控制面、数据面、网络、运行时、SDK 和运维能力各有边界。
“接口存在,就代表处处可用” 不。暂停恢复、快照、模板、凭据保险箱等能力依赖后端、配置和版本。

记住最后一条:这门课会反复训练你区分“契约里写了”“某个 SDK 包了”“当前后端支持”这三件事。

二、一条主线:一次沙箱任务的一生

跳转到“二、一条主线:一次沙箱任务的一生”

整本书只围绕一条主线展开。把它想成一次“外派工作”:应用把一件不可信的活交给一间隔离工作间,干完、取证、交回结果,最后把工作间归还。

模型决定“运行这段代码”
│
▼
应用 / Agent
│ ① 管理请求:创建、查询、续期、暂停、删除
▼
生命周期服务器(控制面)
│ ② 选择运行时,转成真实资源
▼
Docker 容器 / Kubernetes 资源 / FastSandbox 微虚拟机
│ ③ 里面运行用户负载 + execd
▼
沙箱 ───────────────────────────────┐
│ ④ 应用先解析端点,再直接访问 │
│ execd 或工作负载自己的服务 │
│ │
│ ⑤ 出站流量经过 egress sidecar │
▼ ▼
结果以 SSE / 文件 / 退出码返回 外部服务
│
▼
状态、日志、指标、审计记录持续产生
│
▼
续期、暂停、快照、销毁:资源有始有终

这条主线有三个关键动作,后面每一阶段都在拆其中一段:

  1. 安排:控制面把“我要一个环境”变成运行时里的真实资源。
  2. 使用:客户端解析端点后,直接与数据面交互,不把执行流量压回控制面。
  3. 收尾:TTL、显式销毁、暂停快照和审计记录,让资源不泄漏、过程可解释。

把主线拆成问题,就是全书的十个阶段:

主线中的问题 对应阶段
系统能不能先真实跑起来? 0
一次任务经过哪些层、哪些 API? 1
环境怎样创建、续期、暂停和销毁? 2
命令、文件、代码怎样变成可验证的动作? 3
同一份契约怎样落到 Docker、Kubernetes、微虚拟机? 4
流量怎样进入、出去、被限制,密钥怎样不进沙箱? 5
SDK、CLI、MCP 与公开契约是什么关系? 6
怎样把沙箱接进 Agent 的循环和工具? 7
怎样让系统可测试、可观测、可上线? 8
能不能独立做出一个完整的受限执行应用? 9

除了主线,还要一直带着三个问题:

  1. 证据怎样流动? 状态、SSE 事件、退出码、日志和指标,是应用判断“真的成功了没有”的唯一依据。
  2. 信任边界在哪里? 用户、模型、工具、沙箱、宿主机、外部网络,各自能控制什么、不能控制什么。
  3. 能力依赖哪些条件? 看到“支持”时,追问:哪个后端、什么配置、什么版本、什么镜像。

三、八个部件:任何 AI 执行平台都要回答的八件事

跳转到“三、八个部件:任何 AI 执行平台都要回答的八件事”

不要先把学习目标定成“记住目录名”。目录会变,下面这套判断框架不会:

部件 要回答的问题 OpenSandbox 中的对应 阶段
入口 人和程序通过什么使用平台? Python/JS/Go/Kotlin/C# SDK、osb CLI、MCP 6
契约 客户端为什么不被某个后端锁死? specs/ 下的 OpenAPI 1、6
生命周期 环境何时创建、何时过期、何时销毁? server/(FastAPI 控制面) 2
运行时 环境实际跑在容器、Pod 还是微虚拟机? Docker、Kubernetes、FastSandbox 4
执行 模型动作怎样真正发生? components/execd/ 3
网络 流量怎样进入、怎样出去、怎样被限制? endpoint、components/ingress/、components/egress/ 5
安全 不可信代码和密钥怎样被约束? 隔离运行时、资源限制、网络策略、Credential Vault、租户 4、5、8
工程 怎样证明它可靠、可观测、可演进? 测试、诊断、指标、发布与供应链验证 8

一句话串起来:入口发起,契约约束,控制面安排,运行时落地,数据面执行,网络面治理,安全面兜底,工程面证明。

四、分层架构:每一层到底在做什么

跳转到“四、分层架构:每一层到底在做什么”

先记住一个总原则:OpenSandbox 把“管理环境”和“使用环境”拆成了两条路径。 换运行时、换客户端或增加网络策略时,只改对应的一层,不必推倒重来。

4.1 先看简化图:安排向下,执行旁路,证据回流

跳转到“4.1 先看简化图:安排向下,执行旁路,证据回流”
┌──────────────────────────────────────────────────────────────┐
│ 使用层:SDK / CLI / MCP / Agent 框架 │
│ 负责发起管理请求、解析端点、消费执行结果 │
└───────────────┬──────────────────────────────┬───────────────┘
│ ① 管理请求 │ ③ 执行请求
▼ ▼
┌───────────────────────────────┐ ┌───────────────────────────┐
│ 生命周期控制面(server) │ │ 数据面(execd / 工作负载) │
│ 认证、校验、状态机、TTL、 │ │ 命令、文件、代码、PTY、 │
│ 端点解析、快照元数据 │ │ 指标 │
└───────────────┬───────────────┘ └────────────▲──────────────┘
│ ② 选择并驱动运行时 │ ④ 端点由控制面解析
▼ │
┌───────────────────────────────┐ │
│ 运行时:Docker / Kubernetes │─────────────────┘
│ / FastSandbox │ 真实资源与端点
└───────────────┬───────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 网络与安全:ingress(入站)/ egress sidecar(出站)/ 凭据 │
└──────────────────────────────────────────────────────────────┘
证据沿反方向返回:状态、SSE 事件、退出码、日志、指标、审计。

看这张图,只需抓住三件事:

  1. 管理是低频的:创建、查询、续期、暂停、删除,走控制面。
  2. 执行是高频、长连接的:命令和文件直接走数据面,控制面只负责告诉你“去哪里”。
  3. 旁边还有一条证据流:状态、事件和日志决定你是否真的成功。

4.2 各层负责什么、不负责什么

跳转到“4.2 各层负责什么、不负责什么”
层 可以把它想成 负责 不负责
使用层 前台 发起请求、解析端点、展示或转发结果 决定资源怎样创建、状态机怎样推进
契约层 合同 固定公开字段、端点、错误和状态语义 规定某个后端必须怎样实现
控制面 调度中心 认证、校验、生命周期、端点解析、快照元数据 承载命令流、保存所有沙箱事实
运行时 房东 提供容器、Pod 或微虚拟机,维护真实状态 定义用户可见 API
数据面 工头 在沙箱内执行命令、文件和代码,返回流式证据 管理沙箱生死、决定网络策略
网络面 门卫与来访通道 入站路由、出站策略、凭据注入 替代沙箱自身的进程隔离
工程面 质检与档案室 测试、诊断、指标、发布验证 改变业务语义

表格里的“不负责”很重要。分层清不清楚,主要看边界,而不是看名词多不多。

4.3 三对最容易混淆的对象

跳转到“4.3 三对最容易混淆的对象”
对象对 像什么 一句话区别
生命周期服务器 vs 运行时 调度中心 vs 实际工作间 服务器安排环境,运行时拥有环境的真实状态
execd vs 用户负载 工头 vs 工人 execd 提供执行 API,用户负载是真正被运行的程序
端点 vs 地址 前台给的通行证 vs 一扇具体的门 端点由服务器按部署拓扑解析,客户端不应自己拼 IP 和端口

还有一对概念会在阶段 2 反复出现:

  • 沙箱(远端资源):容器、Pod 或微虚拟机,会被创建、暂停、销毁。
  • Sandbox 对象(本地句柄):SDK 里的客户端对象,持有 ID、连接配置、端点缓存和服务适配器。close() 关的是它,不一定是远端资源。

4.4 服务器不保存所有沙箱记录,为什么反而更可靠?

跳转到“4.4 服务器不保存所有沙箱记录,为什么反而更可靠?”

这是初学者最容易误解的设计。直觉上,“平台应该有一个数据库,记录所有沙箱”。OpenSandbox 的选择相反:

  • Docker 容器、Kubernetes 资源、FastSandbox CR 才是运行时事实来源;
  • 服务器只持久化自己拥有的东西:快照元数据、模板目录等;
  • 查询沙箱时,服务器向运行时读取状态,再转换成公开 API 的状态。

这样做的好处是:运行时故障不会让控制面拥有一份“看起来正确、实际过期”的副本;服务器重启后,也能从运行时重新发现事实。代价是:每次查询都要和运行时交互,状态转换必须处理“运行时暂时不可达”。

4.5 两条贯穿全系统的规则

跳转到“4.5 两条贯穿全系统的规则”
  • 控制面安排,数据面执行。 创建沙箱和运行命令是两种不同流量;默认路径下,执行不经过生命周期服务器。
  • 安全默认关闭,能力显式开启。 API Key、资源上限、默认拒绝的出站策略、访问令牌、强隔离运行时,都需要显式配置;更宽松的模式必须由人开启,而不是默认存在。

这两条规则会在第二、三、五章反复出现,先各记一句即可。

五、一次沙箱任务的完整旅程

跳转到“五、一次沙箱任务的完整旅程”

这一章把第二章的图真正走一遍。代码名可以先跳过,只要每一步都能说出“谁把什么交给了谁”。

术语 一句话解释 最容易误解的地方
Sandbox 一个隔离的执行环境,可能由容器、Pod 或微虚拟机承载 它不是 SDK 里的那个 Python 对象
Lifecycle 创建、查询、续期、暂停、恢复、销毁这一套管理动作 它不等于“执行命令”
Endpoint 某个沙箱端口在当前部署下可访问的地址、协议和请求头 它不是固定 IP,也不该由客户端猜
execd 沙箱内的执行守护进程,提供命令、文件、代码等 API 它不是用户程序本身
Runtime 真正创建资源的后端:Docker、Kubernetes、FastSandbox 它不是 runtime.type 字符串那么简单
TTL 沙箱的绝对过期时间 它不是“最后一次活动后多久”
Snapshot 暂停时保存的可恢复检查点 它默认只保存根文件系统,不保存运行内存
Template FastSandbox 预先构建的不可变工作负载定义 它不是每次创建时临时传的镜像参数

优先记住 Sandbox、Endpoint、execd、Runtime、TTL 这五个词,后面会反复出现。

5.2 从“模型想做一件事”到“拿到证据”:分阶段看

跳转到“5.2 从“模型想做一件事”到“拿到证据”:分阶段看”

Agent 决定需要一个环境来运行代码。应用调用:

sandbox = await Sandbox.create(
"python:3.12",
timeout=timedelta(minutes=10),
resource={"cpu": "500m", "memory": "512Mi"},
)

SDK 把它变成 POST /v1/sandboxes,带上镜像、TTL、资源、元数据,可能还有网络策略和凭据代理配置。

阶段 B:控制面做“受理前检查”

跳转到“阶段 B:控制面做“受理前检查””

生命周期服务器依次处理:

  1. 认证:检查 OPEN-SANDBOX-API-KEY(或租户提供方解析出的身份)。
  2. 校验:镜像、TTL、资源、端口、策略是否符合契约。
  3. 选择运行时:根据 runtime.type 和请求特征,决定交给 Docker、Kubernetes 还是 FastSandbox。
  4. 提交运行时:创建容器、写入 BatchSandbox CR,或提交模板沙箱请求。
  5. 返回受理结果:可能是 Pending,也可能已经 Running。

关键认识:HTTP 创建是异步的。 服务端不必等镜像拉完、Pod 调度完才返回;SDK 的 create() 之所以看起来同步,是因为它替你轮询了状态、端点发布和健康检查。

阶段 C:运行时把资源真正建出来

跳转到“阶段 C:运行时把资源真正建出来”
  • Docker:创建容器,注入或启动 execd,映射端口。
  • Kubernetes:写入 BatchSandbox,控制器创建 Pod;execd 以 init container 或镜像内置方式存在。
  • FastSandbox:根据已构建模板分配预热微虚拟机,FastPath/Fastlet 负责控制与运行。

这一步的产物不是一个抽象对象,而是真实资源:容器、Pod、CR、微虚拟机。你可以用 docker ps 或 kubectl get 看见它。

阶段 D:等待就绪与发布端点

跳转到“阶段 D:等待就绪与发布端点”

状态从 Pending 走向 Running。SDK 通常会:

  1. 轮询 GET /v1/sandboxes/{id},等待状态可用;
  2. 解析 GET /v1/sandboxes/{id}/endpoints/44772,拿到 execd 的地址和请求头;
  3. 请求 execd 的 /ping 做健康检查;
  4. 返回一个可用的 Sandbox 句柄。

“创建返回”不等于“服务端一步完成了所有工作”,更不等于“业务进程已经准备好”。这三件事要分开看。

阶段 E:解析端点,而不是猜地址

跳转到“阶段 E:解析端点,而不是猜地址”

客户端不假设“Docker 就是 localhost:某端口”“Kubernetes 就是 Pod IP”。它调用:

GET /v1/sandboxes/{sandboxId}/endpoints/{port}

服务器按当前部署拓扑返回直连地址、网关地址或服务器代理地址,以及必要请求头。地址是结果,不是假设。 这条规则让同一套 SDK 能同时服务 Docker、Kubernetes 和网关部署。

阶段 F:执行命令,边跑边收

跳转到“阶段 F:执行命令,边跑边收”
SDK → POST {execdEndpoint}/command
execd 校验请求,启动进程
→ SSE 持续发送 stdout / stderr / result / complete
→ SDK 聚合成 Execution 对象

流式输出意味着客户端不能只等最终 JSON:它要处理分片、行尾、错误事件和连接中断。退出码非零、execd 报错、传输断开,是三种不同的失败。

阶段 G:出站流量经过 egress sidecar

跳转到“阶段 G:出站流量经过 egress sidecar”

如果创建时声明了 networkPolicy,平台会给沙箱附加 egress sidecar。它和沙箱共享网络命名空间,所以每个出站包都会经过策略引擎:

  • DNS 层按域名允许或拒绝;
  • dns+nft 模式再在包层做默认拒绝;
  • 匹配的 HTTPS 请求可以由 sidecar 注入凭据,真实密钥不进入沙箱。

没有在创建时声明策略的沙箱,通常没有可事后补上的 sidecar。出站控制是创建时决定的,不是运行中许愿来的。

阶段 H:收尾、暂停或恢复

跳转到“阶段 H:收尾、暂停或恢复”

任务完成后,应用应显式销毁:

destroy() → kill()(终止远端) + close()(释放本地连接)

如果只是 close(),远端沙箱可能还在,继续占用资源和费用。长任务还可以:

  • 用 renew() 延长绝对过期时间;
  • 在支持的后端上 pause(),把根文件系统提交成快照;
  • 用 resume() 用同一个 sandbox ID 恢复,但通常不恢复运行内存。

整个过程持续产生证据:

  • 状态:Pending、Running、Pausing、Paused、Stopping、Terminated、Failed,以及 reason / message;
  • 执行事件:stdout/stderr 分片、结果、完成、错误;
  • 文件产物:输出文件、日志、图表;
  • 指标:CPU、内存、创建延迟、失败率;
  • 审计:谁在什么时候创建了什么、执行了什么、为什么销毁。

好的基础设施不是“永远不失败”,而是“失败时知道为什么、能从哪里查”。

5.3 把全过程压成一张时序图

跳转到“5.3 把全过程压成一张时序图”
应用 / Agent
│
├─① Sandbox.create(...)
│ └─► POST /v1/sandboxes
│ ├─ 认证 / 校验 / 选择 runtime
│ ├─ Docker 容器 / BatchSandbox / FastVM
│ └─ 202 + sandboxId(可能 Pending)
│
├─② 轮询状态与端点
│ ├─ GET /v1/sandboxes/{id}
│ └─ GET /v1/sandboxes/{id}/endpoints/44772
│ └─ { url, protocol, headers }
│
├─③ 健康检查
│ └─ GET {execd}/ping
│
├─④ 执行
│ └─ POST {execd}/command
│ └─ SSE:stdout / stderr / result / complete
│
├─⑤ 出站(如有策略)
│ └─ 沙箱 → egress sidecar → 外部服务
│
└─⑥ 收尾
├─ destroy() / kill() / close()
├─ 或 pause() → 快照 → resume()
└─ 状态、日志、指标、审计留存

一句话记住:控制面把环境安排出来,端点把执行路径指出来,execd 把动作做出来,egress 把边界守住,状态与事件把结果证明出来。

容易这样理解 更准确的理解
“Sandbox.create() 返回了,所以创建是同步的。” 不。HTTP 创建是异步的;SDK 只是替你等待了端点发布和健康检查。
“执行命令也走生命周期服务器。” 默认不走。执行走解析出的 execd 端点;服务器代理只是兼容兜底。
“close() 会删除沙箱。” 不会。close() 释放本地连接;kill() 终止远端;destroy() 两者都做。
“沙箱有隔离,所以网络天然安全。” 不会。隔离限制的是对宿主机的影响;出站外泄仍需 egress 策略和凭据隔离。

完整细节见阶段 1(请求旅程与失败点)、《阶段2详解》(生命周期)与《阶段3详解》(执行数据面)。

六、七个关键设计取舍

跳转到“六、七个关键设计取舍”

OpenSandbox 的很多设计初看有些“拐弯”,其实都在解决一个具体麻烦。下面每个选择都按同一顺序讲:不这么做会怎样 → 它怎么做 → 你得到什么、要付出什么。

6.1 协议优先,而不是 SDK 优先

跳转到“6.1 协议优先,而不是 SDK 优先”

麻烦:五种语言、一个 CLI、一个 MCP 服务器,如果各自定义行为,很快就会出现五套语义、五套 bug。

做法:公开行为先定义在 specs/。SDK 是契约的消费者,不是契约本身。读 SDK 时先问“它最终调用哪个 API”,否则容易被语言封装遮住。

结果:跨语言行为可以对齐,后端可替换。代价是读代码时要分清“生成代码”“手写适配层”和“语言习惯封装”。

6.2 控制面与数据面分离

跳转到“6.2 控制面与数据面分离”

麻烦:创建沙箱是低频、慢操作;执行命令可能高频、长连接、持续流式输出。如果都走服务器,控制面会变成带宽和连接瓶颈,故障域也会混在一起。

做法:生命周期 API 只负责安排和解析;执行流量直接走 execd。服务器代理只作为无法直连时的兼容路径。

结果:控制面和数据面可以独立扩容、独立演进、独立排错。代价是客户端必须正确处理端点解析和流式连接。

6.3 生命周期异步化,TTL 是绝对时间

跳转到“6.3 生命周期异步化,TTL 是绝对时间”

麻烦:Pod 调度、镜像拉取、微虚拟机启动都可能很慢;如果用“空闲超时”,服务器重启或运行时抖动会悄悄改变沙箱寿命,审计也说不清。

做法:创建先返回 Pending;过期时间是一个绝对时间点。续期语义是“从现在起再给多久”,而不是“在原过期时间上累加”。

结果:慢创建不会占住 HTTP 请求,寿命可从创建时间推算。代价是客户端要学会轮询、等待和续期预算。

6.4 端点解析属于公开契约

跳转到“6.4 端点解析属于公开契约”

麻烦:Docker 用端口映射,Kubernetes 用 Pod/Service/网关,FastSandbox 用 FastPath;客户端如果自己拼地址,换一种部署就失效。

做法:GET /sandboxes/{id}/endpoints/{port} 返回地址、协议和必要请求头。客户端原样使用,不自行推断。

结果:同一套 SDK 适配多种拓扑。代价是端点解析本身成为一个需要认证、授权和排错的环节。

6.5 运行时中立,但能力有矩阵

跳转到“6.5 运行时中立,但能力有矩阵”

麻烦:如果 API 绑定 Docker,就上不了 Kubernetes;如果假装所有后端完全等价,又会把“接口存在”误写成“能力可用”。

做法:统一的是资源、超时、端点、策略等概念;具体创建 Pod、挂卷、快照、微虚拟机,由后端实现。教材会明确标注能力边界。

结果:同一份契约覆盖单机和集群。代价是开发者必须追问“哪个后端、什么配置、什么版本”。

6.6 安全默认关闭,失败即拒绝

跳转到“6.6 安全默认关闭,失败即拒绝”

麻烦:不可信代码一旦拿到网络和密钥,隔离就只剩“保护宿主机”这一半;而“配置错了但看起来在运行”比直接失败更危险。

做法:API Key、资源上限、能力丢弃、no_new_privs、默认拒绝的出站策略、访问令牌、强隔离运行时都需要显式开启。egress sidecar 如果装不上规则,就退出,而不是静默放行。

结果:安全姿态可预期、可审计。代价是初始配置更多,且必须理解每个开关的边界。

6.7 状态和证据必须可解释

跳转到“6.7 状态和证据必须可解释”

麻烦:分布式系统一定会失败。如果只返回“创建失败”,用户和运维都无法判断是容量、镜像、权限还是网络问题。

做法:状态不仅有一个词,还有 reason、message、转换时间;执行有错误类型;网络策略失败显式报错;诊断 API 提供日志和事件。

结果:失败可定位、可重试、可审计。代价是客户端要区分“可重试”和“不可重试”,不能把所有错误都当成同一种。

  • 协议优先:五类入口说同一种语言。
  • 控制/数据分离:安排和执行各自优化。
  • 异步 + 绝对 TTL:慢创建不拖住请求,寿命可审计。
  • 端点契约:客户端不猜拓扑。
  • 运行时中立:一套 API 覆盖多种基础设施。
  • 安全默认拒绝:不可信动作有边界。
  • 证据可解释:失败能定位。

它们不是孤立的设计,而是互相配合的:契约定义行为,控制面安排资源,运行时提供隔离,数据面执行动作,网络面治理流量,证据流把所有环节串起来。

七、源码目录:先看边界,再看细节

跳转到“七、源码目录:先看边界,再看细节”
路径 一句话职责 建议阅读顺序
specs/ 公开协议:生命周期、执行、出站、诊断 先看接口和模型名,不背字段
server/ FastAPI 生命周期控制面 api/lifecycle.py → services/sandbox_service.py → 具体 runtime
components/execd/ 沙箱内执行守护进程 main.go → pkg/web/router.go → 命令/文件/代码实现
components/egress/ 出站策略、DNS/nft、凭据代理 先看策略模式和 credential vault
components/ingress/ Kubernetes 入站反向代理 看 header/URI 路由和错误语义
components/nodeagent/ 可选节点代理与审计采集 按需读,不是主链路入口
kubernetes/ Operator、CRD、控制器、任务执行 BatchSandbox、Pool、SandboxSnapshot
manifests/charts/ Helm charts 看 base → controller → ingress → server 的顺序
sdks/sandbox/python/ Python 高层封装 sandbox.py → services/ → adapters/ → api/
sdks/code-interpreter/ 有状态代码解释器 看 context 与 Jupyter 内核
sdks/mcp/ MCP 工具服务器 看工具 schema 与生命周期
cli/ osb 命令 看命令组织与输出格式
examples/ 可运行集成样例 按场景挑读
tests/ 跨语言端到端验证 学契约驱动测试

第一遍:只画边界。 找到“谁调用谁”,不进入实现。比如 SDK 的 Sandbox 调服务接口,适配器再调 HTTP 客户端;服务器 API 调服务接口,服务调 Docker/K8s。

第二遍:只追一条主路径。 选“创建沙箱”或“运行命令”,沿调用栈走到底,记录每一层的输入、输出和错误。

第三遍:只问失败。 超时、鉴权失败、端点不可达、命令退出码非零、连接中断分别在哪层处理?这比正常路径更能看出设计质量。

八、版本边界:1.1.1 必须知道的事实

跳转到“八、版本边界:1.1.1 必须知道的事实”

教材不会把“接口存在”写成“处处可用”。请记住以下边界:

  1. Docker 适合本地和单机;Kubernetes 才有 Operator、池化和大规模编排。
  2. 暂停/恢复和快照依赖后端与配置;不是所有运行时都等价,rootfs 快照默认不保留运行内存。
  3. 模板(template)依赖 Kubernetes 的 FastSandbox 集成;Docker 参考服务会拒绝模板管理。
  4. 凭据保险箱依赖 egress sidecar;模板沙箱没有沙箱侧保险箱;暂停后内存中的保险箱状态会丢失,需要重新注入。
  5. Code Interpreter 需要专用镜像;普通最小镜像不等于支持 Jupyter 代码上下文。
  6. Windows 本地运行依赖 Docker Desktop 的 Linux 容器和 WSL2;Windows 容器配置是另一条路径。
  7. 资源池是容量优化,不会把“创建”本身变成免费操作;Pool 里已存在的 Pod 也不能随意注入每请求的网络策略和卷。
  8. 多租户是 Kubernetes 命名空间隔离,Docker 后端不能把 [tenants] 配置当作安全边界。

这些边界不是缺陷,而是基础设施系统正常的“能力矩阵”。优秀的开发者会先确认边界,再写代码。

九、为什么它适合用来学习 AI 应用工程

跳转到“九、为什么它适合用来学习 AI 应用工程”

OpenSandbox 把 AI 应用最容易含糊的几个问题都逼到了明面上:

  • 模型生成的代码去哪里执行?
  • 工具输出怎样流式传给 Agent?
  • 会话之间怎样隔离?
  • 外部网络怎样限制?
  • 密钥怎样不进入沙箱?
  • 长任务怎样恢复?
  • 创建延迟和成本怎样优化?
  • 失败怎样观测和定位?

把这些问题一个个回答清楚,你得到的不只是 OpenSandbox 的知识,而是一套可迁移到任何 Agent 平台的工程判断力。

先不看资料回答,再对照答案:

  1. OpenSandbox 的控制面和数据面分别负责什么? 控制面负责认证、校验、生命周期、端点解析和快照元数据;数据面负责在沙箱里执行命令、文件和代码,并返回流式证据。

  2. 为什么执行请求默认不经过生命周期服务器? 执行是高频、长连接、数据量大的路径;控制面负责低频管理。分开可以避免控制面成为带宽和连接瓶颈,也让故障域更清楚。

  3. 创建沙箱为什么可能返回 Pending?SDK 又为什么常常看起来是同步返回? 运行时创建、调度、拉镜像和启动 execd 都可能很慢;HTTP 先受理。SDK 在 create() 内部轮询状态、端点并做健康检查,所以看起来同步。

  4. 端点解析为什么必须属于公开契约? 不同部署拓扑的可达地址不同(Docker 端口映射、Pod/Service、网关、代理);只有服务器知道当前拓扑,客户端猜地址会在换部署时失效。

  5. 举出三个“接口存在但当前后端不一定支持”的能力。 暂停/恢复与快照、模板沙箱、凭据保险箱、Code Interpreter、多租户等,均依赖后端、配置或镜像;任选三个并说明条件即可。

  6. close()、kill()、destroy() 的区别是什么? close() 释放本地连接;kill() 终止远端沙箱;destroy() 先 kill 再 close。

能答出五个以上,再进入《学习清单》安排节奏。


配套学习路线编写 · 2026-10-30 · 基于 release-1.1.1(531700ca)