Agent 基建系列:E2B Go SDK

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 返回一个运行时类型,调用方按需要断言:

go 复制代码
execution, _ := sandbox.Commands.Run(ctx, "ls -l", nil)
result := execution.(*e2b.CommandResult)

后台模式同理:

go 复制代码
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 不一致。

调用时先声明变量再取地址即可:

go 复制代码
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、跑命令、读写文件是最常用的路径:

go 复制代码
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)

任务跑到一半要暂停节省资源,之后再从原来的状态恢复:

go 复制代码
paused, _ := sandbox.Pause(ctx, nil)

// ... 之后 ...
resumed, _ := sandbox.Connect(ctx, nil)

如果你想试

bash 复制代码
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。

相关推荐
挖坑的张师傅15 分钟前
Agent 基建系列(二):基于 Proxy 的凭证不入沙箱和网络管控方案
后端·agent
挖坑的张师傅18 分钟前
用 FUSE 为云端 Agent 构建文件系统
后端·agent
源于花海32 分钟前
LangChain学习:理解构建模块与核心组件
langchain·prompt·api·agent·模块与核心组件
隐向量39 分钟前
给Agent装上连接外部世界的双手 - 工具调用
agent
qinglongcn41 分钟前
“完成”是什么意思——Plan 步骤状态机的七个 Bug
agent·ai编程
米小虾43 分钟前
给正在干活的 Agent 插一句话:steering 的原理与实现
人工智能·agent
张彦峰ZYF1 小时前
放行、排队与拒绝:限流设计的算法选型、数据结构与并发代价
后端·架构·滑动窗口·漏桶·令牌桶·高并发+限流
jerrywus1 小时前
让 AI 帮你部署 Vercel,报错了也不用手动搬日志
前端·agent·mcp
Trae_陈冀1 小时前
写详细设计总堆代码没逻辑?我做了个自动生成工具,3套模板+规范内置,输出直接过评审
架构·agent