E2B 是事实上的沙箱协议标准,但 E2B 官方 SDK 只有 JavaScript/TypeScript 和 Python 版本。我们对照官方的 TS/Python SDK,实现了一个 Go 原生的 [e2b-go-sdk]: github.com/superduck-a… ,直接在 Go 服务里创建 Sandbox、跑命令、拿文件,不用再接一层其他语言的进程。
下面记录几个做的过程中做出的选择,以及为什么这么选。
调用方式照抄 JS/Python,而不是发明 Go 风格的 API
我们选择让 Go 的方法名、参数结构尽量跟官方 JS/Python SDK 对齐,而不是按 Go 的习惯重新设计一套。
原因是这个 SDK 的目标用户大概率已经在别的语言里用过 E2B——sandbox.Commands.Run、sandbox.Files.Read、sandbox.Pty.Create 这些名字和参数顺序,尽量让人一眼认出来,不用重新学一遍概念。
具体做法上,Commands.Run 是个典型例子。JS/Python 靠函数重载和联合类型,同一个 run() 前台返回结果、后台返回可以继续操作的 handle;Go 里我们让 Run 返回一个运行时类型,调用方按需要断言:
execution, _ := sandbox.Commands.Run(ctx, "ls -l", nil)
result := execution.(*e2b.CommandResult)
后台模式同理:
execution, _ := sandbox.Commands.Run(ctx, "sleep 10; echo done", &e2b.CommandStartOpts{
Background: true,
})
handle := execution.(*e2b.CommandHandle)
result, err := handle.Wait()
var exitErr *e2b.CommandExitError
if errors.As(err, &exitErr) {
// 进程以非零状态退出
}
我们也评估过拆成 RunForeground / RunBackground 两个方法名,但保留单一 Run 入口更贴近官方 SDK 的调用方式,熟悉 JS/Python 版本的人能直接迁移过来。
用指针类型表达"没传"和"传了零值"的区别
AllowInternetAccess、Force、Depth 这些字段在 Go 里用的是 *bool、*int,不是裸的 bool、int。
原因是 JS/Python 的可选参数天然能区分"没传"和"传了 false/0",比如 allowInternetAccess: false 和不传这个字段,在网络策略上是两种不同的行为。Go 的 struct 字段零值就是 false/0,如果直接用裸类型,调用方没法表达"我就是要显式传 false",行为会跟 JS/Python 不一致。
调用时先声明变量再取地址即可:
allowInternet := false
sandbox, _ := e2b.Create(ctx, "", &e2b.SandboxOpts{
AllowInternetAccess: &allowInternet,
})
拿官方测试套件当验收标准,而不是自己写用例验证"看起来对了"
最花时间的部分不是写功能,是对齐行为。我们把当前 worktree 逐项对照 JS/Python SDK 自己的测试文件(sandbox、filesystem、commands、PTY、git、template、volume、network、snapshot 全部覆盖),能跑的地方直接跑三种语言的官方测试用例打同一个后端,逐条对比结果,而不是自己拍脑袋写"应该长这样"的测试。
先做好 Sandbox 原语,不碰 Code Interpreter 那层封装
E2B 官方 SDK 除了 Sandbox 原语,还有一层面向数据分析场景的 Code Interpreter 封装(runCode 这种一行跑一段代码拿结构化结果的接口)。我们目前没做这层。
原因是 Code Interpreter 是在 Sandbox 原语之上包一层协议和结果解析,我们想先把底层的命令执行、文件读写、生命周期管理这些原语做扎实,再考虑往上叠更高层的封装。目前如果需要"传一段代码进去、拿结构化结果"的能力,可以直接在 Commands.Run 之上包一层。
几个更完整的例子
创建 Sandbox、跑命令、读写文件是最常用的路径:
sandbox, _ := e2b.Create(ctx, "", nil)
defer sandbox.Kill(context.Background(), nil)
execution, _ := sandbox.Commands.Run(ctx, `python3 -c "print('hello world')"`, nil)
result := execution.(*e2b.CommandResult)
_, _ = sandbox.Files.Write(ctx, "/home/user/out.txt", result.Stdout, nil)
entries, _ := sandbox.Files.List(ctx, "/home/user", nil)
任务跑到一半要暂停节省资源,之后再从原来的状态恢复:
paused, _ := sandbox.Pause(ctx, nil)
// ... 之后 ...
resumed, _ := sandbox.Connect(ctx, nil)
如果你想试
go get github.com/superduck-ai/e2b-go-sdk
export E2B_API_KEY=e2b_***
先跑 README 里那个创建 Sandbox、执行命令、查看文件的最小例子,能跑通再往上叠 PTY、Git、模板、卷这些能力。如果你在用别的语言的 E2B SDK 迁移过来,可以查一下 TEST_PARITY_AUDIT.md,里面记录了我们跟官方 SDK 对齐的过程和结论。项目还在迭代,欢迎试用,也欢迎在仓库提 issue。