跳到主要内容

E2B Code Interpreter — 这是什么 · 全景 · 阅读地图

30 秒导读: 大模型能写代码,但它不能运行代码。E2B 提供一个云端安全沙箱来跑 AI 生成的代码;code-interpreter 是架在沙箱之上的一层,让你一句 run_code("...") 就把代码丢进去执行,并把执行结果——不只是文本,还有图片、表格、matplotlib 图表—— 结构化地流式带回来。本章讲清"这是什么、大盘怎么转",并给出后续五章的阅读顺序。


1. 这是什么(零基础也能懂)

一句话定义

E2B 是一套开源基础设施,让你把 AI 生成的代码放进云端隔离的安全沙箱里运行 (README.md:22-23,"run AI-generated code in secure isolated sandboxes")。 Code Interpreter 是架在这套沙箱之上的一层能力:跑一段代码,拿回富结果 (文本 + 图片 + 表格 + 图表)。

解决什么问题 / 给谁用

设想你在做一个 AI Agent:用户问"帮我把这份销售数据画成柱状图"。模型很擅长出 那段 matplotlib 代码——但代码得真的跑起来,才有图。你不能在自己的服务器上直接 exec() 模型吐出来的任意代码:那等于把机器交给一个不可信来源。

E2B 把这段"跑不可信代码"的活儿隔离进一次性云沙箱里:

  • 给 AI Agent 开发者:让 agent 拥有一双"能跑代码的手",且跑在别人机器上、炸了也不伤你。
  • 给 Code Interpreter 类产品:类似 ChatGPT 的"高级数据分析",自己搭一套。

它能做什么(功能)

  • 在沙箱里执行 Python / JavaScript / TypeScript / R / Java / Bash 六种语言的代码 (js/src/sandbox.ts:41-48RunCodeLanguage)。
  • 有状态:同一沙箱里前一次定义的变量、import、函数,下一次还在(README 的 x=1x+=1; x2 例子)。
  • 拿回富结果:不只 stdout,还有 matplotlib 图片、pandas DataFrame、被结构化抽取的图表数据。
  • 流式:stdout / stderr / 结果边产生边回传,可挂回调实时消费。
  • 多"上下文"(context):在一个沙箱里开多个互相隔离的执行环境。

用起来什么样(最小示例)

README 给的最小闭环——注意 x 的状态跨调用保留(README.md:50-68):

JavaScript / TypeScript:

import { Sandbox } from '@e2b/code-interpreter'

const sbx = await Sandbox.create() // 开一个云沙箱
await sbx.runCode('x = 1') // 第一次执行,定义 x
const execution = await sbx.runCode('x+=1; x') // 状态还在
console.log(execution.text) // 输出 2

Python:

from e2b_code_interpreter import Sandbox

with Sandbox.create() as sandbox: # with 退出时自动回收沙箱
sandbox.run_code("x = 1")
execution = sandbox.run_code("x+=1; x")
print(execution.text) # 输出 2

富结果长这样——仓库自带的 python/example.py:36-39 跑一段画饼图的代码,然后从 结果里取出结构化的图表对象(不是像素图,是被解析出来的 chart 数据):

async def run():
sbx = Sandbox.create(timeout=60)
e = sbx.run_code(code) # code 是一段 matplotlib 画饼图的代码
print(e.results[0].chart) # 拿到结构化 chart,而不只是 PNG

JS 侧的 js/example.mts 则演示了另一条主线:执行 → betaPause() 暂停 → Sandbox.connect() 恢复 → 状态(x)依旧在(js/example.mts:14-32)。

一句话直觉

把 E2B 沙箱当成"一台随叫随到、用完即弃的云端 Jupyter Notebook"。 你的代码是 notebook 里的一个 cell,run_code 就是"运行这个 cell";变量在 cell 之间保留, 运行完还能把图和表原样端回来。code-interpreter 就是这台 notebook 对外的遥控器。

本节到此不碰底层。往下才进大盘和代码。


2. 顶层全景(它大概怎么转)

三层架构

从你写下 run_code 那行,到代码真正在 CPU 上跑,中间穿过三层。关键在于: SDK 跑在你的机器上,后两层跑在云沙箱里;它们之间隔着一条 HTTPS 边界。

你的进程(agent / 脚本) 云端安全沙箱(一台隔离的 Linux 机器)
┌────────────────────────┐ HTTPS ┌──────────────────────────────────────────────┐
│ ① SDK 客户端 │ POST │ ② 沙箱内 FastAPI 服务 ③ Jupyter 内核 │
│ js / python │ /execute │ :49999 :8888 │
│ │ ───────► │ ┌──────────────┐ WebSocket ┌─────────────┐ │
│ sbx.run_code(code) │ (流式) │ │ 路由 + 上下文 │ ─────────► │ IPython/ │ │
│ │ │ │ FastAPI │ Jupyter │ 其它语言内核 │ │
│ 逐行读 NDJSON ◄─────────┼───────────┼──│ 消息协议桥 │ ◄───────── │ 真正跑代码 │ │
│ 拼成 Execution 对象 │ NDJSON │ └──────────────┘ 消息回流 └─────────────┘ │
└────────────────────────┘ 流回 └──────────────────────────────────────────────┘
本章之外 (②③ 就是 template/ 构建出来的那台机器)

怎么读这张图: 从左到右是一次调用的去程(run_code → HTTP → WebSocket → 内核); 回程沿原路把结果流式带回。三层各自有主人:① 是你 pip/npm 装的库,②③ 是 template/ 目录在构建镜像时烤进沙箱的。

部件一句话职责

部件干什么在哪个目录讲它的章
① SDK 客户端暴露 run_code 等 API;把调用变成一次流式 HTTP,逐行解析回来的结果js/src/python/e2b_code_interpreter/01
② 沙箱内 FastAPI 服务沙箱内监听 :49999;/execute/contexts 路由;管理"上下文"template/server/(main.py)02
③ 内核桥服务与 Jupyter 内核之间的 WebSocket 桥;翻译 Jupyter 消息协议,把执行流式化template/server/messaging.py03
富结果解析内核侧 IPython 格式器 + SDK 侧反序列化:DataFrame、图片、图表抽取js/src/charts.tspython/.../charts.pytemplate/startup_scripts/04
沙箱模板Template() DSL 把上面这台机器(内核 + 服务 + 配置)烤成镜像template/(template.py)05

template/server/ 是 ②③,template.py / systemd/ / startup_scripts/ 是把这台机器 装配起来的图纸;js/python/ 是 ①。见文末代码地图。

端口小抄(容易绕晕的一点)

端口谁在听谁来连
49999沙箱内 FastAPI 服务(即 JUPYTER_PORT,js/src/consts.ts:2)SDK 从你的机器经 HTTPS 连过来
8888沙箱内的 Jupyter Server(template/server/consts.pyJUPYTER_BASE_URL)只由沙箱内的 FastAPI 服务经 WebSocket 连(ws://localhost:8888/...)

即:外界只碰 49999;8888 是沙箱内部私有,SDK 永远不直接碰内核。


3. 主线一句话走一遍(一次 run_code 从调用到结果)

不进代码细节,先把主干串起来。以 sbx.run_code("x+=1; x") 为例:

  1. SDK 发请求。 run_code 组一个 POST 到沙箱的 https://<host>:49999/execute,body 里带 code、可选的 context_id / language / env_vars,并用 AbortController 挂上超时 (js/src/sandbox.ts:227-238)。

  2. 服务选上下文。 沙箱内 FastAPI 的 post_execute 收到请求:按 languagecontext_id 找到对应的执行上下文(找不到就现建一个),拿到那条通往内核的 WebSocket (template/server/main.py:79-127)。

  3. 桥打到内核。 服务通过已连好的 WebSocket(ws://localhost:8888/api/kernels/{id}/channels, template/server/messaging.py:70)把代码作为一条 Jupyter execute_request 发给内核。

  4. 内核跑代码,消息回流。 IPython 内核执行 x+=1; x,一路吐出 Jupyter 消息: stream(stdout/stderr)、display_data / execute_result(富结果)、最后 idle。桥把这些 翻译成本项目自己的输出模型。

  5. NDJSON 流式回传。 服务用 StreamingListJsonResponse 把每个输出对象逐行编码成 一行 JSON 往回吐(template/server/stream.py),结尾补一行 {"type":"end_of_execution"}

  6. SDK 拼装结果。 SDK 逐行读这条流(readLines + parseOutput),把 stdout/stderr/结果/ 错误分别喂给回调,最终攒成一个 Execution 对象——execution.text 就是 "2" (js/src/sandbox.ts:261-280)。

一句话:run_code → HTTP /execute → WebSocket → Jupyter 内核 → 消息 → NDJSON 流回 → Execution 五章就是把这条主线的每一段拆开细讲。


4. 阅读地图(建议顺序)

五章由浅入深,顺着上面那条主线从两端往中间挖。建议按序读:

顺序讲什么深度
101-sdk-client.mdSDK 客户端:run_code 如何变成一次流式 HTTP;超时/中止、逐行解析、Execution 怎么攒出来。js 与 python 两套 SDK 的对照。
202-server-routing.md沙箱内服务:FastAPI 的 /execute/contexts 路由;"上下文(context)"是什么、默认上下文怎么来、并发锁怎么防重复建。
303-kernel-messaging.md内核桥(全项目最深):Jupyter 消息协议、WebSocket 生命周期、断线重连、一次执行如何被切成流式消息并归并成结果。
404-rich-results.md富结果:内核侧 IPython 显示格式器如何把对象变成多种 MIME;SDK 侧如何反序列化;DataFrame 与 matplotlib 图表的结构化抽取(charts.ts)。
505-template-runtime.md沙箱模板:template.pyTemplate() DSL 一步步装出这台机器——装内核、装服务 venv、配 systemd/startup,如何构建 code-interpreter-v1

怎么选着读:

  • 只想会 SDK → 读 01 足矣。
  • 想懂上下文 / 多语言如何路由 → 01 + 02
  • 想懂流式 / 断线重连 / Jupyter 协议这类硬核 → 直奔 03
  • 关心图表 / DataFrame 怎么变结构化数据04
  • 自建/定制沙箱镜像05(也可配合 template/README.md)。

5. 代码地图(总表)

一张跳转表:想下钻哪块,直接按符号 grep 进源码(行号可能随上游漂移,符号名更稳)。

主题文件路径符号名
JS SDK · 沙箱与 run_codejs/src/sandbox.tsSandboxrunCodecreateCodeContext
JS SDK · 结果/图表模型js/src/messaging.tsExecutionResultparseOutputextractError
JS SDK · 图表反序列化js/src/charts.tsChartTypedeserializeChart
JS SDK · 常量(端口/超时)js/src/consts.tsJUPYTER_PORTDEFAULT_TIMEOUT_MS
Python SDK · 同步沙箱python/e2b_code_interpreter/code_interpreter_sync.pySandboxrun_codecreate_code_context
Python SDK · 异步沙箱python/e2b_code_interpreter/code_interpreter_async.pyAsyncSandbox
Python SDK · 结果模型python/e2b_code_interpreter/models.pyExecutionResult
Python SDK · 包入口python/e2b_code_interpreter/__init__.pySandboxAsyncSandboxExecutionResult
服务 · 路由 + lifespantemplate/server/main.pypost_executepost_contextslifespan
服务 · 上下文创建template/server/contexts.pycreate_contextnormalize_language
服务 · 内核桥(WebSocket)template/server/messaging.pyContextWebSocketExecutionexecute
服务 · NDJSON 流式响应template/server/stream.pyStreamingListJsonResponse
服务 · 内核基址常量template/server/consts.pyJUPYTER_BASE_URL
模板 · 镜像装配 DSLtemplate/template.pymake_template
模板 · 生产构建脚本template/build_prod.py(同级 build_*.py)
富结果 · 图表抽取(内核侧)python/e2b_code_interpreter/charts.pyChartChartType
示例 · 富结果(饼图)python/example.pyrune.results[0].chart
示例 · 暂停/恢复(JS)js/example.mtsbetaPauseSandbox.connect
工作区布局pnpm-workspace.yamljs / python / chart_data_extractor / template

说明:本章只讲大盘,刻意不进任何一层的代码内部。每层的细节、坑、巧妙处在对应的 01–05 章;需要跨章时用相对链接互引,不在这里重复。