引言:把「执行」这件事搬走
让 AI Agent 跑一段它自己生成的代码,看输出,再决定下一步,今天已经很常见。让它跑不难,难的是让它安全地跑、干净地跑,而且下一次还能接着跑。
云沙箱就是干这个的。但真把它塞进业务流程之后你会发现,只提供一次性执行,很快就不够用了。
一、云沙箱到底在解决什么问题

云沙箱是一个按需拉起、用完即弃、与宿主机强隔离的临时执行环境。它把执行一段不受信任的代码,变成一次 HTTP 调用的事。
最常见的用法是给 AI Agent 当执行器:模型生成的代码、用户粘贴的脚本,都得在受控边界里跑,不能直接落在自己的机器上。再就是 CI 和构建测试,每次都要一个干净、可复现的环境,上一次的临时文件不能污染这一次的结果。还有一次性数据处理,文件丢进去,结果拿回来,中间过程不必留着。
四件事说起来简单,同时做到不容易:不可信代码不能逃逸,环境不复用脏状态,不为偶发的峰值长期养机器,还得能被自动化流程直接调用。
二、技术原理:一个沙箱是怎么长出来的
拆开看,云沙箱大致由四层构成。 
第一层是隔离层。 沙箱本质上是在同一台宿主机上切出一块「看起来独立」的运行环境:namespace 切进程、网络和挂载视图,cgroup 限制 CPU、内存、进程数,再叠加系统调用过滤,把危险入口收窄。资源不够就拒绝请求,不会拖慢邻居。
第二层是镜像层。 镜像决定沙箱里有什么,而镜像本身就是代码入口,所以必须受控。平台目前只允许 Docker Hub 的公网镜像,其他仓库直接返回 INVALID_IMAGE。不指定镜像时用平台默认镜像,这也是冷启动最快的路径。另外注意,镜像自带的 ENTRYPOINT / CMD 不生效,执行什么完全由传入的命令决定。
第三层是生命周期层。 一个沙箱的一生是:创建 → ready → busy 执行中 → 销毁,中间夹着计时、配额、网络模式(none 彻底断网,default 走平台出网白名单)、资源规格一堆状态机。这层做得好不好,用户能感知到的只有一个指标:从发出请求到第一条输出,要等多久。
第四层是数据与可观测层。 三个容易被低估、但决定「能不能被工程信任」的细节:
- 交换目录。输入输出统一走
/workspace,用.zip/.tar.gz/.tgz压缩包传递,不把大文件塞进请求体;导出的链接可以直接作为下一次任务的输入,天然形成任务链。 - 流式输出。长任务的 stdout / stderr 走 SSE 增量推送,事件按
started → stdout/stderr → completed到达,片段由客户端自己按序拼接。 - 结果判断。HTTP 200 只说明接口调用成功,命令成不成功要看
data.status;每个逻辑任务带一个稳定的幂等键,重试时复用原值,服务端就不会重复执行、重复计费。
计费也直白:一次性任务按「固定费用 + 已完成整分钟」,会话按存活时长,快照都在响应的 billing 里。
三、百智云云沙箱:让沙箱活到你把话说完
前面两节是通用原理。我们自己的产品叫百智云云沙箱(Huskbox) ,地址在 https:// huskbox.app.baizhi.cloud
我们把这些能力封装成一套 OpenAPI:请求用 Authorization: Bearer <token> 或 X-API-Key 鉴权,响应统一是 code / message / data 的信封结构。调用方不用自己维护容器、调度和隔离边界,发一个 HTTP 请求就能拿到一台沙箱。
它最初只有一种形态:一次性任务。POST /executions/run 提交一条命令,连接挂着直到任务结束,返回状态、输出和工作区链接。很适合脚本和 CI,每次调用都是一个全新的、彼此无状态依赖的沙箱。
但真实的工作流往往有状态:装依赖、跑构建、再跑测试,或者 Agent 要多轮「执行 → 观察 → 修正」。每一步都重新拉沙箱的话,冷启动重复一遍,依赖重装一遍,两次执行之间还传不了任何东西。
所以我们补上了会话型沙箱。用起来三步:
bash
# 1. 创建会话,保存返回的 data.id
POST /openapi/v1/sandboxes # { "timeout_seconds": 600 }
# 2. 在同一个 id 上连续执行命令
POST /openapi/v1/sandboxes/:id/commands
# 3. 用完显式销毁,顺带导出整个 /workspace
DELETE /openapi/v1/sandboxes/:id
比一次性任务多出来的,主要是以下内容:
- 连续执行。同一环境里连续跑多条命令,文件系统、已装依赖、中间产物都保留。同一时刻只允许一条命令运行,
busy时新命令会被拒绝,两条命令不会互相踩数据。 - 两类超时是分开的。会话的
timeout_seconds是存活窗口,跟单条命令的超时没有关系。存活窗口随时可以用POST /sandboxes/:id/timeout从当前时刻重算;auto_extend让活跃会话自动续期,但不会超过max_deadline_at这个硬上限。 - 状态可查。
GET /sandboxes/:id返回ready、busy、destroyed等明确状态;万一丢了 id,GET /sandboxes能找回来,顺手清掉闲置的会话。 - 可审计。命令历史分页返回程序名、参数个数、耗时、退出码,但不返回完整参数。要看细节再查单条命令详情,argv 里的 Token、密码和 Authorization 请求头都已经脱敏。
- 用完销毁。
DELETE时会尽量导出整个/workspace,返回临时下载链接。工作区太大就返回WORKSPACE_TOO_LARGE,不销毁,删掉一些文件再试就行。
两种形态放在一起:
| 维度 | 一次性任务 | 会话型沙箱 |
|---|---|---|
| 生命周期 | 命令结束自动释放 | 命令结束仍存活,需显式销毁 |
| 状态保持 | 无 | 文件系统、依赖、产物全部保留 |
| 典型场景 | 脚本、CI、单次执行 | 多步构建、多轮 Agent 交互 |
| 超时语义 | 单条命令超时 | 存活窗口 + 单条命令超时,两层独立 |
| 计费 | 固定费用 + 已完成整分钟 | 按沙箱存活时长 |
最后一个容易踩的坑:命令结束,会话还在。计费继续、资源继续占着,不用了一定要 DELETE,那之后计费才停。
结语
回到开头。跑一段代码,一次性任务就够了;要一段连着一段地跑,就用会话型沙箱。两种形态共用一套接口,从单次脚本到多轮 Agent 交互都覆盖得到。
完整接口与示例在百智云控制台生成的 API 文档里,欢迎试用。
访问地址:百智云·云沙箱
