轻松安全地执行 LLM 生成的代码
LLM 沙盒 是一个轻量级、可移植的沙盒环境,旨在以安全、隔离的模式运行大语言模型(LLM)生成的代码。它为 AI 生成的代码提供了一个安全的执行环境,同时提供了灵活的容器后端和全面的语言支持,简化了运行 LLM 生成代码的过程。
文档: https://vndee.github.io/llm-sandbox/

✨ 新功能: 本项目现已支持 模型上下文协议(MCP) 服务器,允许您的 MCP 客户端(例如 Claude Desktop)在安全的沙盒环境中运行 LLM 生成的代码。
通过自动依赖管理执行多种编程语言的代码:
- Python - 完整的生态系统支持,包含 pip 包
- JavaScript/Node.js - npm 包安装
- Java - Maven 和 Gradle 依赖管理
- C++ - 编译与执行
- Go - 模块支持与编译
- R - 使用 CRAN 包进行统计计算和数据分析
与流行的 LLM 框架(如 LangChain、LangGraph、LlamaIndex、OpenAI 等)无缝集成。
pip install llm-sandbox
# 支持 Docker(最常见)
pip install 'llm-sandbox[docker]'
# 支持 Kubernetes
pip install 'llm-sandbox[k8s]'
# 支持 Podman
pip install 'llm-sandbox[podman]'
# 所有后端
pip install 'llm-sandbox[docker,k8s,podman]'
git clone https://github.com/vndee/llm-sandbox.git
cd llm-sandbox
pip install -e '.[dev]'
from llm_sandbox import SandboxSession
# 创建并使用一个沙盒会话
with SandboxSession(lang="python") as session:
result = session.run("""
print("Hello from LLM Sandbox!")
print("I'm running in a secure container.")
""")
print(result.stdout)
from llm_sandbox import SandboxSession
with SandboxSession(lang="python") as session:
result = session.run("""
import numpy as np
# 创建一个数组
arr = np.array([1, 2, 3, 4, 5])
print(f"Array: {arr}")
print(f"Mean: {np.mean(arr)}")
""", libraries=["numpy"])
print(result.stdout)
with SandboxSession(lang="javascript") as session:
result = session.run("""
const greeting = "Hello from Node.js!";
console.log(greeting);
const axios = require('axios');
console.log("Axios loaded successfully!");
""", libraries=["axios"])
with SandboxSession(lang="java") as session:
result = session.run("""
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello from Java!");
}
}
""")
with SandboxSession(lang="cpp") as session:
result = session.run("""
#include <iostream>
int main() {
std::cout << "Hello from C++!" << std::endl;
return 0;
}
""")
with SandboxSession(lang="go") as session:
result = session.run("""
package main
import "fmt"
func main() {
fmt.Println("Hello from Go!")
}
""")
with SandboxSession(
lang="r",
image="ghcr.io/vndee/sandbox-r-451-bullseye",
verbose=True,
) as session:
result = session.run(
"""
# Basic R operations
print("=== Basic R Demo ===")
# Create some data
numbers <- c(1, 2, 3, 4, 5, 10, 15, 20)
print(paste("Numbers:", paste(numbers, collapse=", ")))
# Basic statistics
print(paste("Mean:", mean(numbers)))
print(paste("Median:", median(numbers)))
print(paste("Standard Deviation:", sd(numbers)))
# Work with data frames
df <- data.frame(
name = c("Alice", "Bob", "Charlie", "Diana"),
age = c(25, 30, 35, 28),
score = c(85, 92, 78, 96)
)
print("=== Data Frame ===")
print(df)
# Calculate average score
avg_score <- mean(df$score)
print(paste("Average Score:", avg_score))
"""
)
对于类似笔记本的工作流,您可以使用 InteractiveSandboxSession,它能在多个 run 调用之间保持 Python 解释器状态。
from llm_sandbox import InteractiveSandboxSession
with InteractiveSandboxSession(
lang="python",
kernel_type="ipython",
history_size=200,
) as session:
session.run("value = 21 * 2")
result = session.run("print(f'Result: {value}')")
print(result.stdout) # -> Result: 42
# 使用魔法命令安装库
session.run("%pip install pandas")
result = session.run("import pandas as pd; print(pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}))")
print(result.stdout)
交互式会话支持 Docker、Podman 和 Kubernetes 后端,目前主要面向 Python 语言。它们在沙盒内启动一个长期运行的 IPython 内核,因此每个 run() 的行为都类似于一个笔记本单元格——状态、导入和魔法命令在上下文管理器退出之前一直保持活动状态,无需任何额外的网络或手动序列化。
from llm_sandbox import ArtifactSandboxSession
import base64
from pathlib import Path
with ArtifactSandboxSession(lang="python") as session:
result = session.run("""
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.figure(figsize=(10, 6))
plt.plot(x, y)
plt.title("Sine Wave")
plt.xlabel("x")
plt.ylabel("sin(x)")
plt.grid(True)
plt.savefig("sine_wave.png", dpi=150, bbox_inches="tight")
plt.show()
""", libraries=["matplotlib", "numpy"])
# 提取生成的图表
print(f"Generated {len(result.plots)} plots")
# 将图表保存到文件
for i, plot in enumerate(result.plots):
plot_path = Path(f"plot_{i + 1}.{plot.format.value}")
with plot_path.open("wb") as f:
f.write(base64.b64decode(plot.content_base64))
from llm_sandbox import ArtifactSandboxSession
import base64
from pathlib import Path
with ArtifactSandboxSession(lang="r") as session:
result = session.run("""
library(ggplot2)
# Create sample data
data <- data.frame(
x = rnorm(100),
y = rnorm(100)
)
# Create ggplot2 visualization
p <- ggplot(data, aes(x = x, y = y)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "lm", se = FALSE) +
labs(title = "Scatter Plot with Trend Line",
x = "X values", y = "Y values") +
theme_minimal()
print(p)
# Base R plot
hist(data$x, main = "Distribution of X",
xlab = "X values", col = "lightblue", breaks = 20)
""", libraries=["ggplot2"])
# 提取生成的图表
print(f"Generated {len(result.plots)} R plots")
# 将图表保存到文件
for i, plot in enumerate(result.plots):
plot_path = Path(f"r_plot_{i + 1}.{plot.format.value}")
with plot_path.open("wb") as f:
f.write(base64.b64decode(plot.content_base64))
from llm_sandbox import SandboxSession
# 创建一个新的沙盒会话
with SandboxSession(image="python:3.9.19-bullseye", keep_template=True, lang="python") as session:
result = session.run("print('Hello, World!')")
print(result)
# 使用自定义 Dockerfile
with SandboxSession(dockerfile="Dockerfile", keep_template=True, lang="python") as session:
result = session.run("print('Hello, World!')")
print(result)
# 或使用默认镜像
with SandboxSession(lang="python", keep_template=True) as session:
result = session.run("print('Hello, World!')")
print(result)
LLM 沙盒还支持在主机和沙盒之间复制文件:
from llm_sandbox import SandboxSession
with SandboxSession(lang="python", keep_template=True) as session:
# 从主机复制文件到沙盒
session.copy_to_runtime("test.py", "/sandbox/test.py")
# 在沙盒中运行复制的 Python 代码
result = session.execute_command("python /sandbox/test.py")
print(result)
# 从沙盒复制文件到主机
session.copy_from_runtime("/sandbox/output.txt", "output.txt")
from llm_sandbox import SandboxSession
pod_manifest = {
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test",
"namespace": "test",
"labels": {"app": "sandbox"},
},
"spec": {
"containers": [
{
"name": "sandbox-container",
"image": "test",
"tty": True,
"volumeMounts": {
"name": "tmp",
"mountPath": "/tmp",
},
}
],
"volumes": [{"name": "tmp", "emptyDir": {"sizeLimit": "5Gi"}}],
},
}
with SandboxSession(
backend="kubernetes",
image="python:3.9.19-bullseye",
dockerfile=None,
lang="python",
keep_template=False,
verbose=False,
pod_manifest=pod_manifest,
) as session:
result = session.run("print('Hello, World!')")
print(result)
import docker
from llm_sandbox import SandboxSession
tls_config = docker.tls.TLSConfig(
client_cert=("path/to/cert.pem", "path/to/key.pem"),
ca_cert="path/to/ca.pem",
verify=True
)
docker_client = docker.DockerClient(base_url="tcp://<your_host>:<port>", tls=tls_config)
with SandboxSession(
client=docker_client,
image="python:3.9.19-bullseye",
keep_template=True,
lang="python",
) as session:
result = session.run("print('Hello, World!')")
print(result)
from kubernetes import client, config
from llm_sandbox import SandboxSession
# 使用本地 kubeconfig
config.load_kube_config()
k8s_client = client.CoreV1Api()
with SandboxSession(
client=k8s_client,
backend="kubernetes",
image="python:3.9.19-bullseye",
lang="python",
pod_manifest=pod_manifest, # 默认为 None
) as session:
result = session.run("print('Hello from Kubernetes!')")
print(result)
⚠️ 自定义 Pod 清单的重要提示:
使用自定义 Pod 清单时,请确保您的容器配置包含:
- "tty": True(保持容器存活)
- Pod 和容器级别的适当 securityContext
- 容器名称可以是任何有效名称(无限制)
完整要求请参阅 配置指南。
from llm_sandbox import SandboxSession
with SandboxSession(
backend="podman",
lang="python",
image="python:3.9.19-bullseye"
) as session:
result = session.run("print('Hello from Podman!')")
print(result)
容器池化通过重用预热的容器而不是为每次执行创建新容器,显著提高了性能。这对于频繁执行代码的应用程序尤其有益。
from llm_sandbox import SandboxSession
from llm_sandbox.pool import PoolConfig, create_pool_manager
# 显式创建一个池管理器
pool = create_pool_manager(
backend="docker",
config=PoolConfig(
max_pool_size=10, # 最大容器数
min_pool_size=3, # 至少保持 3 个预热容器
idle_timeout=300.0, # 5 分钟后回收空闲容器
enable_prewarming=True, # 启动时创建容器
),
lang="python",
)
# 在会话中使用池
with SandboxSession(
lang="python",
pool=pool,
) as session:
result = session.run("print('Hello from pool!')")
# 会话关闭时容器自动返回到池中
# 完成后清理池
pool.close()
为了获得最高效率,可以在多个会话之间共享一个池:
```python
from llm_sandbox import SandboxSession
from llm_sandbox.pool import create_pool_manager, PoolConfig
pool = create_pool_manager(
backend="docker",
config=PoolConfig(
max_pool_size=10,
min_pool_size=3,
),
lang="python",
libraries=["numpy", "pandas"], # 在所有容器中预安装库
)
with SandboxSession(lang="python", pool=pool) as session1:
result1 = session1.run("import pandas; print(pandas.version)")
with SandboxSession(lang="python", pool=pool) as session2:
result2 = session2.run("import numpy; print(numpy.version)")