技术解读
Sandcastle:给编码 Agent 造一座用完即弃的沙堡
项目背景与痛点
2025 年,coding agent 早就不是演示品了。Claude Code、Codex CLI、Cursor 的 agent 模式、Aider,这些工具已经能独立完成一次像样的重构。但真正想把它们塞进生产流水线的人,基本都会撞上同一堵墙:agent 是要执行代码的。
执行就意味着权限。让它在你自己的工作区里 npm install、改文件、跑测试、顺手 curl 一个外部地址,风险是实打实的。更麻烦的还在工程侧——一次任务污染了本地环境怎么办?想并行跑十个任务怎么办?跑崩了想回滚怎么办?
于是"沙箱"成了标准答案。Docker、Firecracker microVM,以及 E2B、Daytona、Modal、Vercel Sandbox 这类云端方案,隔离能力都够用。但沙箱只是原料,真正难写的是外面那层编排:创建沙箱、注入代码与密钥、拉起 agent 进程、流式收日志、判断成败、把 diff 捞回来、销毁、失败重试、并发限流。这套胶水代码每个团队都要重写一遍,而且一旦写死在某家 SDK 上,换 provider 就得推倒重来。
sandcastle 就卡在这一层。它卖的不是沙箱,而是 sandcastle.run()——一个把"沙箱 + agent"当作一次性任务来调度的 TypeScript 入口。
核心技术揭秘
从公开的 API 形态看,run() 是典型的 Facade:对外一个函数,对内把异构 provider 的差异全部吃掉。
技术栈是纯 TypeScript / Node,没有引入额外的控制面服务——这一点很关键,它意味着这套东西能直接嵌进现有 CI、CLI 或一个 Next.js 后端,而不是逼你再部署一套调度系统。
架构上大致是三段式:Provider 适配层(Adapter 模式,把 Docker、云端 API、本地进程统一成同一组 create / exec / destroy 语义)、任务编排层(生命周期状态机 + 并发调度)、结果回收层(退出码、diff、产物文件、日志流)。
几个技术难点值得单独拎出来:
其一是生命周期与异步流的竞态。 沙箱是外部资源,agent 输出是流式的,run() 又必须是 Promise 语义。三者叠在一起,最容易出的 bug 是:任务超时取消了,沙箱却没销毁,钱在后台一直烧。合理的实现必须让 AbortSignal 贯穿全链路,并用 try/finally 或 TS 的 await using(Symbol.asyncDispose)兜住清理逻辑。
其二是类型上的能力建模。 不同 provider 能力并不对等——有的支持快照恢复,有的不支持持久卷,有的网络出口根本不可控。把这些差异表达成 discriminated union 而非 any,是这个库能不能被团队放心采用的分水岭。
其三是输入的可复现性。 沙箱需要的永远是"仓库快照 + 密钥 + 命令"三件套,任何一样不 pin 版本,昨天的成功今天就复现不了。
顺带一提,sandcastle 这个名字本身就是设计哲学:沙堡,建起来就是为了被潮水冲掉。短生命周期、无状态、用完即弃。
功能亮点与差异
第一,它站在编排层而非沙箱层。 E2B、Daytona 卖的是"隔离执行环境",sandcastle 卖的是"把 agent 当作可调度任务"。这个站位差异决定了它的竞品不是又一个 sandbox API,而是 Docker Compose 或 Temporal 在 agent 领域的对位物。
第二,agent 无关。 它不绑定某个具体的 coding agent,而是把 agent 当子进程跑。今天用 Claude Code,明天换 Codex CLI,编排逻辑不用改——这是长期价值里最扎实的一条。
第三,和 agent 框架不在同一层。 LangChain 那一类解决的是 prompt 与工具调用,sandcastle 解决的是"这些进程在哪跑、跑几个、跑砸了怎么收场"。两者互补,不是替代。
第四,TypeScript 一等公民。 配置即代码,类型即文档,天生适合塞进 package.json 的 script 里。
应用场景与落地建议
最适合的场景:跨仓库的批量重构与依赖升级;CI 里的自动修复(测试红了就让 agent 提个 PR);issue → PR 的自动化流水线;多 agent 并行探索同一问题的不同解法然后择优。
落地时有几条硬约束:
- 凭证别塞长期 token。 给沙箱短时、最小权限的凭证,任务结束即失效。
- 网络出口要收窄。 agent 会
curl任意地址,这是最大的攻击面。 - 结果必须人审。 agent 产出的 diff 不能直接 merge,编排层能做的是把 diff 干净地捞出来,不是替你判断对错。
- 镜像与依赖要 pin 死,否则可复现性就是一句空话。
- 并发要有配额。 沙箱按秒计费,十路并行失控起来账单很难看。
不适合的:需要长期驻留的有状态服务;对延迟极敏感的同步请求链路——沙箱冷启动就是几百毫秒到几秒,绕不过去。
综合评价
优点很清晰:抽象克制、边界干净,把最容易写错的那层胶水——生命周期、资源清理、并发控制——收进了库里,并且选对了 TypeScript 这个宿主,能无缝接入现有 CI。名字起得也好,定位说得很明白:它不解决"agent 聪不聪明",只解决"agent 在哪跑、怎么收场"。
风险同样明显。早期项目,API 稳定性存疑;provider 抽象一定会漏水,不同沙箱在文件系统语义、网络策略、快照能力上的差异,迟早会从统一接口下面冒出来;可观测性大概率得自己补(结构化日志、trace、成本统计);另外它把一部分命运押在了上游 agent CLI 的稳定性上。
一句话:2025 年的问题已经是"怎么让 agent 安全地跑代码",sandcastle 瞄准的是紧接着的下一个问题——怎么让一百个 agent 有序地跑起来,然后干净地消失。
评论