跳到主要内容

Sandbox 与代码执行工程

5-8 第 4.3 节提到 Coding Agent 必须有沙箱,但讲得很浅。本篇深入:什么场景必须沙箱、各类方案对比、E2B/Modal 实战、Code Interpreter 工程。这是 2025-2026 年新基础设施层的核心。

学前说明

让 AI 跑代码是它真正"做事"的关键能力。但代码执行的危险性是 AI 工具集中最高的——一行 rm -rf / 就能毁机器,一个 curl ... | sh 就能装恶意软件。

所以任何允许 AI 跑代码的系统都必须有沙箱。问题是:

  • Docker 够吗?容器逃逸风险有多大?
  • 云端沙箱(E2B)vs 本地沙箱怎么选?
  • 多租户怎么隔离?
  • 文件、网络、资源怎么限制?
  • 代码跑完结果怎么取回?

本篇回答这些。

学习目标

  • 区分四种主流沙箱方案(容器、microVM、WASM、云端)
  • 用 E2B / Modal / Daytona 在生产环境跑 AI 生成代码
  • 实现 Code Interpreter 模式
  • 设计文件、网络、资源的多层隔离
  • 处理多语言运行时(Python / Node / Shell)
  • 评估"沙箱逃逸"风险并设计纵深防御

与现有知识的衔接

  • 5-8 第 4.3 节:沙箱概览(前置)
  • 04 Lethal Trifecta:YOLO 模式必须沙箱
  • 05 第五章:YOLO + Docker 的本地实现
  • 07 Agentic Loop:沙箱让 loop 安全做暴力试错

第一章:为什么必须沙箱

1.1 AI 跑代码的真实风险

不只是"AI 写错代码"。是 AI 可能:

  1. 被注入指令(参考 04 Lethal Trifecta):网页里"忘了给 AI 看"的指令让它跑恶意代码
  2. 执行不受控的依赖pip install some-typo-squatting 装了恶意包
  3. 资源耗尽:死循环、fork bomb、内存泄漏
  4. 数据外泄:跑代码读 .env,HTTP 发出去
  5. 横向攻击:用你的机器扫描内网、攻击其他服务

1.2 三个真实事件(2024-2025)

社区报告的真实事故(脱敏后):

事件 1:开发者用 Claude Code YOLO 模式让 AI 处理一个 GitHub PR,PR 里有恶意 markdown,AI "总结" 时实际跑了 curl 拉远端 shell 脚本,开发者 .ssh 目录被打包外发。

事件 2:某 AI 平台让 AI 跑 Python 数据分析,攻击者通过提交"数据"包含 __import__('os').system('...'),逃出 Python 限制。

事件 3:开发者本地跑 Coding Agent,AI 误执行 npm publish 把含密钥的包发了。

1.3 "我不会被攻击"的错觉

很多人觉得"我又不是公开服务"。但风险来自:

  • 公开 GitHub 仓库的 issues / PRs
  • 第三方 npm 包(你装的)
  • 网页内容(AI 浏览)
  • 你以为安全的 RAG 文档(员工写的备忘录可能被攻击者编辑)

只要 AI 接触任何外部内容,就有被注入的可能。


第二章:四类沙箱方案

2.1 方案对比

方案隔离级别启动速度资源开销代表
容器(Docker)1-3 秒Docker、Podman
microVM(Firecracker)100-500msE2B、AWS Fargate
WASM极高(语言级)< 100ms极低Cloudflare Workers AI
云端进程取决于 provider由 provider 管理Modal、Daytona、Replicate

2.2 容器(Docker)

适合

  • 本地开发
  • 任务中等风险
  • 你信任宿主内核

不适合

  • 处理任意攻击者代码
  • 多租户公开服务
  • 极敏感场景

关键配置

docker run --rm \
--memory=512m \
--cpus=0.5 \
--pids-limit=100 \
--network=none \
--read-only \
--tmpfs /tmp:size=64m \
--user nobody \
--cap-drop=ALL \
--security-opt=no-new-privileges \
-v $(pwd)/input:/input:ro \
-v $(pwd)/output:/output:rw \
agent-runtime:latest

每个标志都重要:

  • --memory / --cpus / --pids-limit:资源限制
  • --network=none:网络隔离(按需放开)
  • --read-only:根文件系统只读
  • --tmpfs /tmp:内存盘(重启即清空)
  • --user nobody:非 root
  • --cap-drop=ALL:移除所有 Linux capabilities
  • --security-opt=no-new-privileges:防 setuid 提权

2.3 microVM(Firecracker)

AWS 在 2018 年开源的 microVM 技术,现在是 E2B、Modal、Fly.io 的底层。

优点

  • 启动 < 500ms(接近容器)
  • 完整 VM 隔离(KVM 级别)
  • 攻击面小(最小化的 VMM)

不适合自己跑:运维复杂,建议用 SaaS。

2.4 WASM 沙箱

把代码编译到 WebAssembly 跑,语言级隔离。

优点

  • 极快(启动 < 100ms)
  • 极轻(开销小)
  • 跨平台

限制

  • 不是所有代码都能编译到 WASM
  • Python、Node 部分功能受限
  • 不能做"真实 IO"(要 host bridge)

适合

  • 用户提交的小函数
  • 不需要文件/网络的场景
  • 极高并发

代表:Cloudflare Workers、Spin。

2.5 云端沙箱(E2B、Modal、Daytona)

把执行外包给 SaaS。

优点

  • 不用自己运维
  • 现成的多语言支持
  • 内置文件、网络、超时控制
  • 通常更安全(专业团队)

缺点

  • 数据要传出去(合规问题)
  • 按用量付费
  • 网络延迟

适合

  • 大多数生产场景
  • 不想自建基础设施
  • 多租户

第三章:E2B 实战

E2B 是 2025 年最流行的 AI Sandbox SaaS。专为 AI Agent 设计。

3.1 基础用法

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

const sandbox = await Sandbox.create();

// 跑 Python
const execution = await sandbox.runCode(`
import pandas as pd
df = pd.DataFrame({'a': [1, 2, 3]})
print(df.sum())
`);

console.log(execution.text); // a 6

// 文件操作
await sandbox.files.write('/tmp/data.csv', 'a,b\n1,2\n3,4');
const content = await sandbox.files.read('/tmp/data.csv');

// 跑 shell
const result = await sandbox.commands.run('ls -la /tmp');

// 销毁
await sandbox.kill();

3.2 关键特性

隔离

  • 每个 Sandbox 是独立的 microVM
  • 默认 5 分钟无操作自动销毁
  • 可手动 kill

多语言

  • Python(默认带 pandas、numpy 等)
  • Node.js
  • 任何能装的(apt-get / pip / npm)

网络

  • 默认有外网(按需限制)
  • 可以代理流量

3.3 给 AI Agent 用的模式

// AI Agent 调用沙箱的标准模式
const tools = [
{
name: 'execute_python',
description: '在隔离沙箱中执行 Python 代码并返回输出',
input_schema: {
type: 'object',
properties: {
code: { type: 'string' }
}
}
}
];

async function executePython({ code }: { code: string }) {
// 复用沙箱(同一个 session 内)
if (!session.sandbox) {
session.sandbox = await Sandbox.create({ timeoutMs: 30 * 60 * 1000 });
}

const exec = await session.sandbox.runCode(code, { timeoutMs: 30_000 });

// 限制返回大小
const output = exec.text.slice(0, 50_000);

return {
stdout: output,
error: exec.error?.value,
images: exec.results.filter(r => r.png).map(r => r.png), // matplotlib 图
};
}

3.4 多文件项目

const sandbox = await Sandbox.create();

// 上传整个项目
await sandbox.files.write('/project/package.json', '...');
await sandbox.files.write('/project/src/index.ts', '...');
// ...更多文件

// 跑
await sandbox.commands.run('cd /project && npm install');
await sandbox.commands.run('cd /project && npm test');

// 取产物
const builtFile = await sandbox.files.read('/project/dist/bundle.js');

3.5 计费与限制

  • 按秒计费
  • 默认 1 vCPU / 512MB
  • 可升到 8 vCPU / 16GB
  • 长期跑(> 1 小时)成本要算

不适合:

  • 跑训练任务(用 Modal)
  • 极高并发(用 Cloudflare)

第四章:Modal 实战

Modal 适合更重的工作负载。

4.1 与 E2B 的区别

维度E2BModal
定位AI 临时沙箱通用 serverless
启动速度< 500ms1-3 秒
GPU 支持有限强(A100/H100)
定价按秒按秒 + GPU 时间
适合短任务、试错训练、批处理、长任务

4.2 给 Agent 用的模式

import modal

app = modal.App("ai-sandbox")

@app.function(
image=modal.Image.debian_slim().pip_install("pandas", "numpy"),
timeout=300, # 5 分钟
cpu=1,
memory=512,
)
def execute_python(code: str) -> dict:
"""在隔离环境跑 Python"""
import sys, io, contextlib

stdout = io.StringIO()
stderr = io.StringIO()

try:
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
exec(code, {})
return {
'stdout': stdout.getvalue(),
'stderr': stderr.getvalue(),
'success': True
}
except Exception as e:
return {
'stdout': stdout.getvalue(),
'stderr': str(e),
'success': False
}

# Agent tool 调用
@app.function()
async def agent_run_code(code: str):
return execute_python.remote(code)

4.3 长任务、GPU 任务

Modal 在这里有优势:

@app.function(
gpu="A100",
timeout=3600,
)
def fine_tune_model(dataset_url: str):
# AI Agent 派出来的微调任务
# 跑几小时也没问题
...

适合:让 Agent 自主决定"我来微调一个小模型解决这个问题"。


第五章:Code Interpreter 工程

OpenAI 和 Claude 都内置了 "Code Interpreter" 模式。它不是简单的代码执行——是Agent + 沙箱 + 持久会话的组合。

5.1 Code Interpreter 的特点

持久会话

# 第一轮
> 加载这个 CSV
df = pd.read_csv('data.csv')
print(df.head())

# 第二轮(df 还在!)
> df 的均值是多少
print(df.mean())

# 第三轮
> 画个柱状图
df.plot.bar()

变量在会话内保留。这跟"每次跑独立代码"完全不同。

多模态输出

  • print 输出 → 文字
  • matplotlib → 图片
  • pandas DataFrame → 表格
  • HTML → 交互组件

文件持久

  • 上传的文件在会话期间保留
  • 生成的文件可以下载

5.2 自建 Code Interpreter

class CodeInterpreterSession {
private sandbox: E2BSandbox;
private session_id: string;

constructor(userId: string) {
this.session_id = `ci-${userId}-${Date.now()}`;
}

async ensureSandbox() {
if (!this.sandbox || !this.sandbox.isRunning()) {
this.sandbox = await Sandbox.create({
template: 'code-interpreter', // 预装 jupyter kernel
timeoutMs: 60 * 60 * 1000, // 1 小时
metadata: { session_id: this.session_id }
});
}
return this.sandbox;
}

async runCode(code: string): Promise<ExecutionResult> {
const sb = await this.ensureSandbox();
const exec = await sb.runCode(code);

// 提取多种输出
return {
stdout: exec.text,
images: this.extractImages(exec.results),
tables: this.extractTables(exec.results),
html: this.extractHtml(exec.results),
error: exec.error,
};
}

async uploadFile(name: string, content: Buffer) {
const sb = await this.ensureSandbox();
await sb.files.write(`/uploads/${name}`, content);
return `/uploads/${name}`;
}

async listFiles() {
const sb = await this.ensureSandbox();
const result = await sb.commands.run('ls /uploads /workspace');
return result.stdout.split('\n').filter(Boolean);
}

async cleanup() {
if (this.sandbox) await this.sandbox.kill();
}
}

5.3 与 LLM 集成

// LLM 通过 Tool Call 用 Code Interpreter
const tools = [
{
name: 'run_code',
description: '在持久 Python 会话中执行代码。变量和文件在会话内保留。',
input_schema: { code: { type: 'string' } }
},
{
name: 'list_files',
description: '列出沙箱中的文件',
input_schema: {}
}
];

async function handleConversation(userId: string, message: string) {
const ci = await getOrCreateSession(userId);

// 让 LLM 决定调用哪些 tool
const response = await llm.chat({
messages: [{ role: 'user', content: message }],
tools,
tool_handler: async (toolName, args) => {
if (toolName === 'run_code') {
return await ci.runCode(args.code);
}
// ...
}
});

return response;
}

第六章:多层隔离设计

单层隔离不够。生产系统需要纵深防御。

6.1 文件隔离

层级 1:进程级

  • --user nobody
  • 限制写入路径

层级 2:容器级

  • --read-only 根文件系统
  • --tmpfs 临时盘

层级 3:宿主级

  • 容器 mount 的目录最小化
  • 没有 /host 之类的逃出路径

6.2 网络隔离

# 三种网络模式
none: # 完全无网络
- 适合:纯计算任务
- 风险:极低

restricted: # 白名单
- 允许:pypi.org、npm registry、特定 API
- 拒绝:其他一切
- 适合:装包、调研

full: # 完整外网
- 适合:浏览器自动化
- 风险:高,必须配合其他隔离

实现:

# Docker 模式 1:完全隔离
docker run --network=none ...

# Docker 模式 2:白名单(用 iptables)
docker network create --internal restricted-net
# 在容器内通过代理访问白名单

6.3 资源隔离

docker run \
--memory=512m \
--memory-swap=512m \ # 不允许 swap 扩容
--cpus=0.5 \
--pids-limit=100 \ # 防 fork bomb
--ulimit nofile=1024:1024 \ # 文件句柄
--ulimit nproc=50:50 \ # 进程数
...

每个 limit 都防一种攻击。

6.4 时间隔离

  • 单次执行:超时(30s)
  • 整个会话:超时(1h)
  • 闲置:自动销毁(5min)
async function safeExecute(code: string, timeoutMs = 30_000) {
return Promise.race([
sandbox.runCode(code),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('execution_timeout')), timeoutMs)
)
]);
}

6.5 多租户隔离

每个用户独立的沙箱实例。不要共享沙箱

// ❌ 错误:用户共享沙箱
const sharedSandbox = await Sandbox.create();
async function run(userId: string, code: string) {
return sharedSandbox.runCode(code); // 用户 A 能看到 B 的变量
}

// ✅ 正确:每用户独立
const userSandboxes = new Map<string, Sandbox>();
async function run(userId: string, code: string) {
if (!userSandboxes.has(userId)) {
userSandboxes.set(userId, await Sandbox.create());
}
return userSandboxes.get(userId)!.runCode(code);
}

第七章:多语言运行时

7.1 Python 沙箱

最常用。E2B / Modal 默认支持。

关键考虑

  • 预装常用包(pandas、numpy、matplotlib、requests)
  • 安装新包:pip install(在沙箱内)
  • 内存:DataFrame 容易爆(限 4GB+)

7.2 Node.js 沙箱

const sandbox = await Sandbox.create({ template: 'node' });

await sandbox.commands.run('npm install lodash');
await sandbox.runCode(`
const _ = require('lodash');
console.log(_.sum([1, 2, 3]));
`, { language: 'javascript' });

注意:

  • npm install 慢(用本地 cache 镜像可加速)
  • 防止 child_process 滥用

7.3 Shell 沙箱

最危险但也最强大。

// 白名单命令
const ALLOWED_COMMANDS = ['ls', 'cat', 'grep', 'find', 'git', 'pnpm', 'pytest'];

function isAllowed(command: string): boolean {
const cmd = command.split(/\s+/)[0];
return ALLOWED_COMMANDS.includes(cmd);
}

async function safeShell(command: string) {
if (!isAllowed(command)) {
throw new Error(`Command not allowed: ${command}`);
}
return await sandbox.commands.run(command);
}

或者完全开放但在严格沙箱里跑(取决于风险)。

7.4 跨语言统一接口

interface SandboxRuntime {
language: 'python' | 'node' | 'shell';
run(code: string, options?: RunOptions): Promise<Result>;
installPackage(name: string): Promise<void>;
uploadFile(path: string, content: Buffer): Promise<void>;
downloadFile(path: string): Promise<Buffer>;
cleanup(): Promise<void>;
}

class UnifiedSandbox implements SandboxRuntime {
// 用 E2B / Modal / 自建容器都实现这个接口
// Agent 不关心底层
}

第八章:沙箱逃逸风险

8.1 已知逃逸路径

容器逃逸(CVE 案例):

  • runc 漏洞(2019、2024)
  • 内核漏洞
  • /sys/fs/cgroup 误配置
  • 共享 namespace

防御:

  • 用 microVM(更小攻击面)
  • 用 gVisor 等 user-space kernel
  • 限制 capabilities(--cap-drop=ALL
  • 用 seccomp 限制系统调用

8.2 应用层逃逸

不是逃出容器,是绕开应用层限制:

# 假设 Python 沙箱拦截了 import os
# 攻击者的绕过:
__builtins__.__import__('os').system('rm -rf /')

# 或者通过 dunder 方法
().__class__.__bases__[0].__subclasses__()
# 找到 subprocess.Popen 的引用

防御:

  • 用真实进程隔离(不是 Python AST 限制)
  • 不要试图用语言级 sandbox(容易被绕过)

8.3 侧信道攻击

  • 缓存时序攻击
  • 资源使用泄露信息
  • ...

通常不在 AI 沙箱的威胁模型内(成本极高)。但如果你处理高敏感数据需要考虑。

8.4 纵深防御

不要靠单一防线:

威胁:恶意代码执行

防线 1:用户输入校验(基础)

防线 2:LLM 拒绝(Constitutional AI)

防线 3:沙箱(容器 / VM)

防线 4:网络白名单

防线 5:资源限制

防线 6:审计日志(事后追溯)

每层都有概率失效,多层叠加将组合失效概率压到极低。


第九章:实战案例

9.1 案例:数据分析 Agent

需求:用户上传 CSV,Agent 写代码分析,返回结果和图表。

架构

用户上传 CSV

后端:创建用户专属 E2B Sandbox

LLM 看到任务,生成 Python 代码

通过 Tool Call 调用 sandbox.runCode()

拿到结果(文字 + 图片)

LLM 综合给用户回答

关键决策

  • 沙箱生命周期 = 用户会话(关闭则销毁)
  • 每个用户独立沙箱(不共享)
  • 30 分钟自动 timeout

9.2 案例:CI 中的 AI 代码 Reviewer

需求:PR 提交后 AI 自动 review,包括"试着跑一下"。

架构

# .github/workflows/ai-review.yml
- uses: actions/checkout@v4
- name: Create sandbox
uses: e2b-dev/action-create-sandbox@v1
with:
template: ${{ matrix.language }}
- name: Upload PR diff
run: e2b upload pr-diff
- name: Run AI review in sandbox
run: e2b exec "python /scripts/review.py"
- name: Post comments
run: ...

为什么用沙箱:PR 代码可能恶意(比如内部威胁、被入侵的 contributor)。直接在 CI runner 跑 PR 代码 = 灾难。

9.3 案例:Coding Agent 试错

需求:让 Claude Code 自由跑 npm install / pnpm test 但不能搞坏开发机。

方案:用 Anthropic 官方的 Dev Container

# 项目根
.devcontainer/
├── devcontainer.json
├── Dockerfile
└── init-firewall.sh # 网络白名单

# 启动
code . # VS Code 自动 prompt 用 Dev Container
# 在 container 里跑 claude --dangerously-skip-permissions

容器内:

  • 文件系统挂载到 /workspaces(项目目录)
  • 网络限制到必要的域名
  • 资源有限制
  • 即使被注入也只能搞坏容器,不影响宿主机

第十章:踩坑总结

10.1 反模式

反模式表现后果
用 eval / vm.runInContext"节省" 启动时间没真隔离,能逃出
用 chroot 当沙箱老办法早就有逃逸方法
共享沙箱多用户节省成本数据泄露
不限网络默认外网exfiltration 风险
不限超时让它跑到完DoS、成本爆炸
不审计不存执行日志出事不可追溯

10.2 起步建议

不要一上来就 microVM。优先级:

  1. 本地 Coding Agent:Anthropic Dev Container(开箱即用)
  2. 生产 AI 应用:E2B(最简单的 SaaS 方案)
  3. 重负载:Modal(GPU、长任务)
  4. 极高并发:WASM(Cloudflare)
  5. 极敏感:自建 microVM(最后选项)

10.3 监控指标

指标健康范围
平均沙箱寿命1-30 分钟
沙箱启动失败率< 0.5%
超时执行比例< 5%
资源耗尽比例< 1%
安全告警次数接近 0

第十一章:未来方向

11.1 unikernel 沙箱

unikernel = 最小化内核 + 只跑一个应用。比 microVM 更轻、更安全。

代表:Nanos、IncludeOS。 2026 年开始有 AI 应用尝试。

11.2 Confidential Computing

CPU 级隔离(Intel SGX、AMD SEV):

  • 即使云厂商也看不到内存
  • 适合极敏感场景(医疗、金融)

成本高,2026 年开始普及。

11.3 AI 沙箱的标准化协议

类似 MCP 之于工具,可能出现"Sandbox Protocol":

  • 统一的沙箱接口
  • 跨厂商兼容
  • AI 可以"自己选"沙箱

E2B、Modal 已经有讨论。

11.4 沙箱即服务的成本下降

2025 年 E2B 一个会话 $0.01-0.10/小时。2026 年随竞争加剧成本下降,可能进入"免费配额够用"阶段。


权威资料

核对日期:2026-06-12