当 AI 学会“造沙箱“:OpenSandbox 如何让大模型安全地执行代码

当 AI 学会“造沙箱“:OpenSandbox 如何让大模型安全地执行代码
让 AI 写代码容易,让 AI 安全地运行代码?这才是真正的技术硬菜。

你有没有想过这样一个场景:你让 ChatGPT 或 Claude 帮你写了一段 Python 爬虫脚本,它写得漂漂亮亮,但你复制到本地一运行——"rm -rf /"——好家伙,人没了,数据没了,只剩下你和一台空空如也的电脑面面相觑。

当然,这只是一个极端的玩笑。但说真的,AI 生成的代码到底能不能直接运行?运行在哪里?出了问题谁来兜底?这些问题,在 AI 编程助手遍地开花的今天,已经从"理论问题"变成了"每天都要面对的问题"。

今天要介绍的 OpenSandbox,就是阿里巴巴开源的一套专门解决这个问题的"沙箱平台"。它的核心理念很简单:给 AI 生成的代码一个"隔离的游乐场",让它在里面随便折腾,但绝对不能影响外面的世界。

一、为什么我们需要"代码沙箱"?

1.1 AI 时代的"信任危机"

还记得小时候玩沙子吗?家长总会圈出一块"沙坑",你可以在里面尽情堆城堡、挖坑道,但绝对不能把沙子撒到客厅地板上。代码沙箱,本质上就是给程序圈出的一块"沙坑"。

在传统软件开发时代,代码都是人写的,经过 code review、测试、部署,每一步都有人把关。但 AI 时代不一样了——大模型可以在几秒钟内生成上百行代码,这些代码可能:

  • 功能正确但有副作用:比如写文件时不小心覆盖了重要数据
  • 无意中引入安全漏洞:比如 SQL 注入、命令注入
  • 直接就是恶意代码:如果 prompt 被注入了恶意指令

更可怕的是,AI 生成的代码往往需要立即执行才能验证效果。你总不能每次都让人工审核一遍吧?那 AI 还有什么效率优势?

1.2 现有方案的痛点

在 OpenSandbox 出现之前,业界已经有一些代码执行方案:

方案一:直接在服务器上跑

  • 优点:简单粗暴
  • 缺点:简单粗暴地把服务器搞崩

方案二:用 Docker 容器隔离

  • 优点:隔离性不错
  • 缺点:每次创建容器太慢,资源管理复杂,没有统一的 API

方案三:用 Kubernetes 调度

  • 优点:可扩展性强
  • 缺点:门槛太高,小团队玩不起

方案四:用第三方沙箱服务(如 E2B、Modal)

  • 优点:开箱即用
  • 缺点:数据安全堪忧,国内网络访问受限,成本不透明

OpenSandbox 的出现,某种程度上是想把这些方案的优点集于一身:既有 Docker 的隔离性,又有 Kubernetes 的可扩展性,还提供了统一的 API 和多语言 SDK,最关键的是——它是开源的,你可以完全掌控自己的数据。

二、架构全景:四层设计的优雅哲学

OpenSandbox 的架构设计遵循"协议优先"的原则,整体分为四层。如果把它比作一家餐厅的话:

┌─────────────────────────────────────────────────────────┐ │                      SDKs 层                            │ │    (服务员:Python/Java/Kotlin/TypeScript 多语言支持)    │ ├─────────────────────────────────────────────────────────┤ │                      Specs 层                           │ │    (菜单:OpenAPI 规范,定义了所有可用的"菜品")          │ ├─────────────────────────────────────────────────────────┤ │                     Runtime 层                          │ │    (后厨:Docker/K8s 运行时,负责"做菜")                │ ├─────────────────────────────────────────────────────────┤ │                   Sandbox 实例层                        │ │    (餐盘:每个容器就是一份独立的"套餐")                  │ └─────────────────────────────────────────────────────────┘ 

2.1 SDKs 层:程序员的"点餐台"

作为一个开发者,你不需要关心底层是用 Docker 还是 Kubernetes,你只需要:

from opensandbox import Sandbox from code_interpreter import CodeInterpreter # 创建一个沙箱,就像点一份套餐 sandbox = await Sandbox.create(     "opensandbox/code-interpreter:latest",     timeout=timedelta(minutes=10), ) # 创建代码解释器 interpreter = await CodeInterpreter.create(sandbox) # 执行代码,获取结果 result = await interpreter.codes.run(     "print('Hello, Sandbox!')",     language=SupportedLanguage.PYTHON, ) print(result.logs.stdout[0].text)  # Hello, Sandbox! # 用完别忘了"结账" await sandbox.kill() 

这段代码看起来是不是很简单?但背后发生了什么呢?

  1. SDK 通过 HTTP 请求告诉 Server:"我要一个 Python 环境的沙箱"
  2. Server 拉取镜像、创建容器、注入执行代理(execd)
  3. 容器启动后,SDK 通过 execd 发送代码执行请求
  4. execd 把代码交给内置的 Jupyter 内核执行
  5. 执行结果通过 SSE(Server-Sent Events)实时返回给 SDK

整个过程对开发者来说是透明的,就像你在餐厅点餐,不需要知道后厨是煤气灶还是电磁炉。

2.2 Specs 层:契约精神的体现

OpenSandbox 定义了两套核心规范:

1. Sandbox Lifecycle API(沙箱生命周期 API)

这套 API 负责沙箱的"生老病死":

操作端点说明
创建POST /sandboxes从镜像创建新沙箱
查询GET /sandboxes/{id}获取沙箱状态
暂停POST /sandboxes/{id}/pause暂停执行,保留状态
恢复POST /sandboxes/{id}/resume恢复暂停的沙箱
销毁DELETE /sandboxes/{id}终止并删除沙箱
续期POST /sandboxes/{id}/renew-expiration延长过期时间

沙箱有完整的状态机:

Pending → Running → Pausing → Paused     ↓         ↓                  ↓   Failed   Stopping          Running               ↓          Terminated 

2. Execd API(执行守护进程 API)

这套 API 负责沙箱内部的"干活":

  • 代码执行:支持 Python、Java、JavaScript、TypeScript、Go、Bash
  • 命令执行:运行 Shell 命令,支持前台和后台模式
  • 文件操作:读写、搜索、权限管理
  • 系统监控:CPU、内存使用率实时监控

两套规范相互独立,但完美配合。这种"协议优先"的设计有一个巨大的好处:你可以替换任何一层的实现,只要遵循规范,整个系统就能正常工作。

2.3 Runtime 层:真正的"苦力活"

Runtime 层是整个系统的核心引擎,目前支持两种运行时:

Docker 运行时(已就绪)

适合单机部署和开发测试,代码实现在 server/src/services/docker.py

class DockerSandboxService(SandboxService):     def create_sandbox(self, request):         # 1. 拉取镜像         self._ensure_image_available(image_uri, auth_config, sandbox_id)                  # 2. 创建容器(但先不启动)         container = self.docker_client.api.create_container(             image=image_uri,             entrypoint=[BOOTSTRAP_PATH],  # 使用自定义启动脚本             command=bootstrap_command,             environment=environment,             labels=labels,             host_config=host_config,         )                  # 3. 注入 execd 执行代理         self._prepare_sandbox_runtime(container, sandbox_id)                  # 4. 启动容器         container.start()                  # 5. 设置过期自动清理         self._schedule_expiration(sandbox_id, expires_at) 

这里有一个精妙的设计:execd 注入机制。OpenSandbox 不要求你的镜像预装任何东西,它会在容器创建后、启动前,把 execd 二进制文件"塞"进去。这意味着你可以用任何基础镜像(ubuntu、python、node),OpenSandbox 都能让它"听话"。

Kubernetes 运行时(开发中)

适合大规模生产部署,基于 Kubernetes Operator 模式:

apiVersion: sandbox.opensandbox.io/v1alpha1 kind: Pool metadata:   name: code-interpreter-pool spec:   template:     spec:       containers:         - name: sandbox           image: opensandbox/code-interpreter:latest   capacitySpec:     bufferMin: 1   # 最少预热 1 个     bufferMax: 3   # 最多预热 3 个     poolMax: 5     # 池子最大容量 

Kubernetes 运行时引入了"池化"概念,可以提前预热一批沙箱,用户请求时直接分配,大大降低了冷启动延迟。

2.4 Sandbox 实例:每个容器都是一个独立王国

每个沙箱实例的内部结构是这样的:

┌──────────────────────────────────────────────┐ │                 容器边界                      │ │  ┌────────────────────────────────────────┐  │ │  │           用户进程(entrypoint)        │  │ │  │         python main.py / bash          │  │ │  └────────────────────────────────────────┘  │ │                      ↑                       │ │  ┌────────────────────────────────────────┐  │ │  │              execd 守护进程             │  │ │  │  - HTTP API 服务器                     │  │ │  │  - Jupyter 内核客户端                  │  │ │  │  - 文件系统操作                        │  │ │  │  - 系统指标采集                        │  │ │  └────────────────────────────────────────┘  │ │                      ↑                       │ │  ┌────────────────────────────────────────┐  │ │  │           Jupyter Server               │  │ │  │  - IPython (Python)                    │  │ │  │  - IJava (Java)                        │  │ │  │  - gophernotes (Go)                    │  │ │  └────────────────────────────────────────┘  │ └──────────────────────────────────────────────┘ 

execd 守护进程是这里的核心,它是用 Go 语言编写的轻量级 HTTP 服务器,负责:

  1. 接收外部的代码执行请求
  2. 通过 WebSocket 与 Jupyter 内核通信
  3. 将执行结果以 SSE 流的形式返回
// execd 的路由定义 func NewRouter(accessToken string) *gin.Engine {     r := gin.New()          // 代码执行     code := r.Group("/code")     code.POST("", runCode)           // 执行代码     code.DELETE("", interruptCode)   // 中断执行     code.POST("/context", createContext)  // 创建执行上下文          // 命令执行     command := r.Group("/command")     command.POST("", runCommand)     command.DELETE("", interruptCommand)          // 文件操作     files := r.Group("/files")     files.POST("/upload", uploadFile)     files.GET("/download", downloadFile)          return r } 

三、深入源码:几个令人拍案叫绝的设计

读源码最有趣的部分,就是发现那些"看起来简单,其实精心设计"的细节。

3.1 execd 注入:无侵入式的"寄生"

OpenSandbox 不需要你修改镜像,它是怎么做到的?

答案在 DockerSandboxService._prepare_sandbox_runtime 方法中:

def _prepare_sandbox_runtime(self, container, sandbox_id):     # 1. 从 execd 镜像中提取二进制文件     archive = self._fetch_execd_archive()          # 2. 在目标容器中创建目录     self._ensure_directory(container, "/opt/opensandbox", sandbox_id)          # 3. 把 execd 二进制文件塞进去     container.put_archive(path="/opt/opensandbox", data=archive)          # 4. 安装启动脚本     self._install_bootstrap_script(container, sandbox_id) 

启动脚本 bootstrap.sh 长这样:

#!/bin/sh set -e # 后台启动 execd /opt/opensandbox/execd >/tmp/execd.log 2>&1 & # 然后执行用户的原始命令 exec "$@" 

通过覆盖容器的 ENTRYPOINTbootstrap.sh,把用户原本的命令作为参数传入,实现了"先启动 execd,再运行用户进程"的效果,完全无侵入。

3.2 Jupyter 集成:站在巨人的肩膀上

为什么选择 Jupyter 作为代码执行引擎?因为它已经解决了"多语言代码执行"这个难题:

  • IPython 内核支持 Python
  • IJava 内核支持 Java
  • gophernotes 内核支持 Go
  • ITypeScript 内核支持 TypeScript

execd 通过 WebSocket 与 Jupyter Server 通信,使用标准的 Jupyter 消息协议:

// 连接到 Jupyter 内核 func (c *Client) ConnectToKernel(kernelId string) error {     wsURL := fmt.Sprintf("ws://%s/api/kernels/%s/channels", host, kernelId)     return c.executeClient.Connect(wsURL) } // 执行代码并流式返回结果 func (c *Client) ExecuteCodeStream(kernelId, code string, resultChan chan *ExecutionResult) error {     return c.executeClient.ExecuteCodeStream(code, resultChan) } 

Jupyter 的 Session 机制还天然支持"有状态执行"——你可以在第一次执行中定义变量,第二次执行中继续使用,非常适合交互式编程场景。

3.3 过期自动清理:没有内存泄漏的秘密

沙箱是有生命周期的,用完必须销毁,否则资源会被耗尽。OpenSandbox 使用了一个巧妙的 Timer 机制:

def _schedule_expiration(self, sandbox_id, expires_at):     # 计算还有多久过期     delay = max(0.0, (expires_at - datetime.now(timezone.utc)).total_seconds())          # 创建一个定时器     timer = Timer(delay, self._expire_sandbox, args=(sandbox_id,))     timer.daemon = True  # 守护线程,主进程退出时自动清理          # 取消旧的定时器(如果有),设置新的     with self._expiration_lock:         existing = self._expiration_timers.pop(sandbox_id, None)         if existing:             existing.cancel()         self._expiration_timers[sandbox_id] = timer          timer.start() 

更贴心的是,服务重启时会自动恢复所有沙箱的过期定时器:

def _restore_existing_sandboxes(self):     containers = self.docker_client.containers.list(         all=True,         filters={"label": [SANDBOX_ID_LABEL]},     )          for container in containers:         expires_at = parse_timestamp(labels.get(SANDBOX_EXPIRES_AT_LABEL))                  if expires_at <= now:             # 已经过期,立即清理             self._expire_sandbox(sandbox_id)         else:             # 重新设置定时器             self._schedule_expiration(sandbox_id, expires_at) 

这种设计保证了:即使服务意外重启,也不会有"僵尸沙箱"残留。

3.4 网络隔离:给沙箱戴上"紧箍咒"

AI 生成的代码可能会尝试访问互联网,下载恶意软件或者泄露数据。OpenSandbox 通过 NetworkPolicy 实现了精细的网络控制:

networkPolicy:   default_action: deny  # 默认禁止所有出站   egress:     - action: allow       target: "pypi.org"      # 允许访问 PyPI     - action: allow         target: "*.github.com"  # 允许访问 GitHub 

这就像给沙箱戴上了"紧箍咒"——它只能访问你明确允许的域名,其他一概不行。

四、实战演练:从零开始玩转 OpenSandbox

说了这么多理论,让我们动手实操一下。

4.1 环境准备

首先确保你的机器上装了 Docker:

docker --version # Docker version 24.0.0 或更高 

然后拉取 Code Interpreter 镜像:

docker pull opensandbox/code-interpreter:latest 

4.2 启动服务端

git clone https://github.com/alibaba/OpenSandbox.git cd OpenSandbox/server # 复制配置文件 cp example.config.toml ~/.sandbox.toml # 安装依赖并启动 uv sync uv run python -m src.main 

服务启动后会监听 http://localhost:8080

4.3 写一个简单的客户端

import asyncio from datetime import timedelta from opensandbox import Sandbox from code_interpreter import CodeInterpreter, SupportedLanguage async def main():     # 创建沙箱     sandbox = await Sandbox.create(         "opensandbox/code-interpreter:latest",         entrypoint=["/opt/opensandbox/code-interpreter.sh"],         timeout=timedelta(minutes=10),     )          async with sandbox:         # 创建代码解释器         interpreter = await CodeInterpreter.create(sandbox)                  # 执行 Python 代码         result = await interpreter.codes.run(             """             import math                          def calculate_pi(n):                 '''使用莱布尼茨公式计算 π'''                 pi = 0                 for i in range(n):                     pi += ((-1) ** i) / (2 * i + 1)                 return pi * 4                          estimated_pi = calculate_pi(1000000)             print(f"估算的 π 值: {estimated_pi}")             print(f"真实的 π 值: {math.pi}")             print(f"误差: {abs(estimated_pi - math.pi)}")             """,             language=SupportedLanguage.PYTHON,         )                  # 打印输出         for line in result.logs.stdout:             print(line.text)          # 清理资源     await sandbox.kill() if __name__ == "__main__":     asyncio.run(main()) 

运行后你会看到:

估算的 π 值: 3.1415916535897743 真实的 π 值: 3.141592653589793 误差: 9.999989545520858e-07 

整个过程中,代码是在隔离的 Docker 容器中执行的,即使你写了 os.system('rm -rf /') 也只会把容器内的文件删掉,不会影响宿主机。

4.4 与 AI 编程助手集成

OpenSandbox 的真正威力在于与 AI 结合。项目自带了多个集成示例:

  • Claude Code:让 Claude 在沙箱中执行它生成的代码
  • Gemini CLI:Google Gemini 的代码执行环境
  • Codex CLI:OpenAI Codex 的代码执行环境
  • LangGraph:基于 LangChain 的 Agent 工作流

以 Claude Code 为例,集成思路大致是:

  1. 用户向 Claude 提问:"帮我写一个爬取豆瓣电影 Top250 的脚本"
  2. Claude 生成代码
  3. 代码发送到 OpenSandbox 执行
  4. 执行结果返回给 Claude
  5. Claude 根据结果调整代码(如果有错误)
  6. 循环直到成功

这种"生成-执行-反馈-修正"的循环,让 AI 编程助手从"只会写代码"进化到了"能写能调试"。

五、与同类产品的对比

市面上还有哪些类似的产品?让我们做个横向对比:

特性OpenSandboxE2BModalDocker + Jupyter
开源✅ Apache 2.0
多语言支持✅ 6+ 语言
统一 API✅ OpenAPI
多语言 SDK✅ Python/Java/TS
K8s 支持需自行实现
网络隔离需自行配置
国内可用受限受限
数据自主

OpenSandbox 的最大优势在于:开源 + 数据自主 + 国内友好。对于对数据安全有要求的企业,或者需要在国内部署的场景,OpenSandbox 几乎是唯一的选择。

六、未来展望:沙箱技术的星辰大海

OpenSandbox 的 Roadmap 里还有很多有趣的计划:

6.1 Go SDK

目前只有 Python、Java/Kotlin、TypeScript SDK,Go SDK 还在开发中。考虑到 Go 在云原生领域的广泛使用,这个 SDK 的呼声很高。

6.2 kubernetes-sigs/agent-sandbox 集成

这是 Kubernetes SIG 正在开发的一个官方沙箱标准。OpenSandbox 计划与之集成,这意味着未来可以用 kubectl 来管理沙箱!

# 未来可能的用法 kubectl create sandbox my-sandbox --image=python:3.11 kubectl exec -it my-sandbox -- python 

6.3 声明式网络隔离

目前的网络策略是基于 DNS 的,未来会增加基于网络层的控制,实现更精细的流量管理。

6.4 更多 AI 框架集成

除了现有的 Claude、Gemini、Codex 集成,还计划支持:

  • AutoGPT
  • CrewAI
  • AutoGen

七、写在最后:安全不是束缚,而是自由的前提

有人可能会问:搞这么复杂的隔离机制,是不是"杞人忧天"?

我的回答是:安全措施的价值,不在于它阻止了多少攻击,而在于它让你可以放心地做更多事情。

想象一下,如果没有沙箱:

  • 你敢让 AI 自动执行它生成的代码吗?
  • 你敢让用户在你的平台上运行任意代码吗?
  • 你敢把代码执行功能集成到生产系统中吗?

有了沙箱,这些都不是问题。就像有了安全带,你才敢踩油门;有了保险,你才敢创业;有了沙箱,AI 才敢真正"动手"。

OpenSandbox 的出现,不仅仅是一个技术产品,更是 AI 编程范式的一个重要基础设施。它让"AI 写代码"从 demo 走向了生产,让"人机协作编程"从概念变成了现实。

如果你也在探索 AI 编程的可能性,不妨试试 OpenSandbox。毕竟,让 AI 在沙箱里"随便玩",总比让它在生产环境"随便搞"要安全得多。


项目地址:https://github.com/alibaba/OpenSandbox

更多AIGC文章

RAG技术全解:从原理到实战的简明指南

更多VibeCoding文章

Read more

uv终极技巧:一招精准指定Python版本,告别版本混乱!

还在为不同项目间Python版本冲突而烦恼?掌握uv的版本指定技巧,让每个项目都运行在“量身定制”的解释器环境中! 摘要 本文将深入解析在使用uv进行Python项目管理时,如何在不同场景下精准指定Python版本。从项目初始化、现有项目版本切换到全局版本管理,你将掌握一套完整的Python版本控制方案,彻底解决“我的代码需要Python 3.9,但系统默认是3.11”这类经典问题。 🎯 为什么需要指定Python版本? 在真实开发中,指定Python版本至关重要: * 依赖兼容性:某些包仅支持特定Python版本 * 团队统一:确保所有开发者使用相同版本 * 生产一致性:避免开发与生产环境版本不一致导致的Bug * 多版本测试:验证代码在不同Python版本下的表现 🚀 三大场景实战指南 场景一:创建新项目时指定版本(最常用) 在项目初始化阶段指定Python版本是最佳实践: # 方式1:使用 --python 参数直接指定 uv init --python 3.9# 这将创建一个使用Python 3.9的新项目# 方式2:指定精确版本 uv in

By Ne0inhk

3分钟搞定PythonWin7:Windows 7安装Python 3.9+全攻略

3分钟搞定PythonWin7:Windows 7安装Python 3.9+全攻略 【免费下载链接】PythonWin7Python 3.9+ installers that support Windows 7 SP1 and Windows Server 2008 R2 项目地址: https://gitcode.com/gh_mirrors/py/PythonWin7 还在为Windows 7无法安装最新Python版本而烦恼吗?PythonWin7项目专为解决这一问题而生,让您的旧系统也能享受现代化的Python开发体验。本文将为新手用户提供一份简单易懂的安装指南。 📝 Windows 7安装Python 3.9+的必要条件 在开始安装之前,请确保您的系统满足以下基本要求: 系统环境检查清单: * 操作系统:Windows 7 SP1 或 Windows Server 2008

By Ne0inhk
Python 驱动浏览器自动化:Playwright + AI 的 2026 最佳实践

Python 驱动浏览器自动化:Playwright + AI 的 2026 最佳实践

摘要:在 Web 自动化领域,Selenium 曾经的霸主地位已成历史,Playwright 凭其“快、稳、强”的现代特性成为了新标准。而在 2026 年,随着 LLM(大语言模型)和视觉多模态模型的爆发,自动化测试与 RPA(机器人流程自动化)迎来了范式革命。本文将深度解析 Playwright 的核心架构,并手把手教你构建一个具备“自愈能力”的 AI 驱动自动化 Agent。本文超 7000 字,包含大量实战代码与反爬对抗技巧。 第一章:Selenium 已死,Playwright 当立? 1.1 自动化的“不可能三角” 长期以来,Web 自动化工程师都在速度、稳定性和抗检测性之间做取舍: * Selenium:

By Ne0inhk
安装Anaconda+Python(2025超详细)

安装Anaconda+Python(2025超详细)

目录 第一步:下载Anaconda 第二步:安装Anaconda 第三步:配置环境变量 第四步:检查是否成功 第五步:添加快捷方式并打开   第一步:下载Anaconda 方法一: 登录Anaconda官网。(比较慢,略过,用方法二) 方法二:镜像网站下载:点击这里到清华镜像站下载 第二步:安装Anaconda 1.双击安装 2.点击 Next 3.点击 I Agree 4.选择 All Users,Next 5.选安装路径(最好不要C盘) 6.只选择第二个:默认带python环境 7.等待安装,注意:安装前关掉杀毒软件(例如火绒),否则进度条可能卡住 8.

By Ne0inhk