smolagents 文档
安全代码执行
并获得增强的文档体验
开始使用
安全代码执行
如果您是构建代理的新手,请务必先阅读代理简介和smolagents 入门指南。
代码 Agent
多篇 研究 论文 表明,让 LLM 以代码形式编写其动作(工具调用)要比当前工具调用的标准格式好得多,后者在业界各不相同,都是“将动作写成工具名称和使用参数的 JSON”。
为什么代码更好?因为我们特意设计了代码语言,使其能出色地表达计算机执行的动作。如果 JSON 代码片段是更好的方式,那么这个包就会用 JSON 代码片段编写,魔鬼都会嘲笑我们。
代码只是在计算机上表达动作的更好方式。它具有更好的:
- **可组合性:** 您可以将 JSON 操作相互嵌套,或者定义一组 JSON 操作供以后重用,就像您可以定义一个 Python 函数一样吗?
- **对象管理:** 如何在 JSON 中存储
generate_image
等操作的输出? - **通用性:** 代码旨在简单地表达计算机可以做的任何事情。
- LLM 训练语料库中的表示:为什么不利用这个天赐良机,即大量高质量的动作已经包含在 LLM 训练语料库中?
下图对此进行了说明,该图取自 可执行代码动作引发更好的 LLM Agent。

这就是为什么我们强调推出代码 Agent,在这种情况下是 Python Agent,这意味着要花更多精力构建安全的 Python 解释器。
本地代码执行??
默认情况下,CodeAgent
在您的环境中运行 LLM 生成的代码。
这本质上是有风险的,LLM 生成的代码可能对您的环境有害。
恶意代码执行可能以多种方式发生:
- 纯粹的 LLM 错误:LLM 远非完美,可能会在试图提供帮助时无意中生成有害命令。虽然这种风险很低,但已经观察到 LLM 试图执行潜在危险代码的实例。
- 供应链攻击:运行不受信任或被篡改的 LLM 可能会使系统暴露于有害代码生成。虽然在使用知名模型并在安全推理基础设施上运行时这种风险极低,但它仍然是理论上的可能性。
- 提示注入:浏览网页的 Agent 可能会访问包含有害指令的恶意网站,从而向 Agent 的内存中注入攻击。
- 利用可公开访问的 Agent:向公众开放的 Agent 可能会被恶意行为者滥用以执行有害代码。攻击者可能会精心设计对抗性输入以利用 Agent 的执行能力,从而导致意想不到的后果。一旦恶意代码被执行,无论是意外还是有意,它都可能损坏文件系统、利用本地或云端资源、滥用 API 服务,甚至危及网络安全。
有人可能会说,在 自主性谱系 中,代码 Agent 在您的系统上赋予了 LLM 比其他自主性较低的设置高得多的自主性:这与更高的风险相伴而生。
因此,您需要非常注意安全。
为了提高安全性,我们提出了一系列措施,这些措施提供了更高级别的安全性,但设置成本也更高。
我们建议您牢记,没有解决方案是 100% 安全的。

我们的本地 Python 执行器
为了增加第一层安全性,`smolagents` 中的代码执行不是由原生 Python 解释器执行的。我们从头开始重建了一个更安全的 `LocalPythonExecutor`。
确切地说,这个解释器通过从您的代码中加载抽象语法树 (AST) 并逐个操作地执行它,确保始终遵循某些规则。
- 默认情况下,除非用户已将其明确添加到授权列表中,否则不允许导入。
- 此外,默认情况下禁用对子模块的访问,每个子模块也必须在导入列表中明确授权,或者您可以传递例如 `numpy.*` 来允许 `numpy` 及其所有子包,如 `numpy.random` 或 `numpy.a.b`。
- 请注意,一些看似无害的包,如 `random`,可能会访问到潜在有害的子模块,如 `random._os`。
- 处理的基本操作总数有上限,以防止无限循环和资源膨胀。
- 任何在我们自定义解释器中未明确定义的操作都会引发错误。
您可以按如下方式尝试这些安全措施:
from smolagents.local_python_executor import LocalPythonExecutor
# Set up custom executor, authorize package "numpy"
custom_executor = LocalPythonExecutor(["numpy"])
# Utilisty for pretty printing errors
def run_capture_exception(command: str):
try:
custom_executor(harmful_command)
except Exception as e:
print("ERROR:\n", e)
# Undefined command just do not work
harmful_command="!echo Bad command"
run_capture_exception(harmful_command)
# >>> ERROR: invalid syntax (<unknown>, line 1)
# Imports like os will not be performed unless explicitly added to `additional_authorized_imports`
harmful_command="import os; exit_code = os.system('echo Bad command')"
run_capture_exception(harmful_command)
# >>> ERROR: Code execution failed at line 'import os' due to: InterpreterError: Import of os is not allowed. Authorized imports are: ['statistics', 'numpy', 'itertools', 'time', 'queue', 'collections', 'math', 'random', 're', 'datetime', 'stat', 'unicodedata']
# Even in authorized imports, potentially harmful packages will not be imported
harmful_command="import random; random._os.system('echo Bad command')"
run_capture_exception(harmful_command)
# >>> ERROR: Code execution failed at line 'random._os.system('echo Bad command')' due to: InterpreterError: Forbidden access to module: os
# Infinite loop are interrupted after N operations
harmful_command="""
while True:
pass
"""
run_capture_exception(harmful_command)
# >>> ERROR: Code execution failed at line 'while True: pass' due to: InterpreterError: Maximum number of 1000000 iterations in While loop exceeded
这些安全措施使我们的解释器更安全。我们已在多种用例中使用它,从未观察到对环境造成任何损害。
重要的是要理解,没有任何本地 Python 沙箱是完全安全的。虽然我们的解释器比标准 Python 解释器提供了显著的安全性改进,但对于一个坚定的攻击者或经过微调的恶意 LLM 来说,仍然有可能找到漏洞并可能损害您的环境。
例如,如果您允许像 `Pillow` 这样的包处理图像,LLM 可能会生成代码来创建数千个大图像文件以填满您的硬盘。其他高级的逃逸技术可能会利用授权包中更深层次的漏洞。
在本地环境中运行 LLM 生成的代码总是带有一定的固有风险。以真正强大的安全隔离运行 LLM 生成的代码的唯一方法是使用远程执行选项,如 E2B 或 Docker,详见下文。
使用来自可信推理提供商的知名 LLM 时,恶意攻击的风险很低,但并非为零。对于高安全性的应用程序或使用不太可信的模型时,您应考虑使用远程执行沙箱。
安全代码执行的沙箱方法
在使用执行代码的 AI Agent 时,安全性至关重要。在 smolagents 中,有两种主要的沙箱代码执行方法,每种方法都具有不同的安全属性和功能:
在沙箱中运行单个代码片段:这种方法(图左侧)仅在沙箱中执行 Agent 生成的 Python 代码片段,而将 Agent 系统的其余部分保留在您的本地环境中。使用 `executor_type="e2b"` 或 `executor_type="docker"` 进行设置更简单,但它不支持多 Agent,并且仍需要在您的环境和沙箱之间传递状态数据。
在沙箱中运行整个 Agent 系统:这种方法(图右侧)在沙箱环境中运行整个 Agent 系统,包括 Agent、模型和工具。这提供了更好的隔离,但需要更多手动设置,并且可能需要将敏感凭据(如 API 密钥)传递到沙箱环境。
本指南介绍了如何为您的 Agent 应用程序设置和使用这两种沙箱方法。
E2B 设置
安装
- 在 e2b.dev 创建一个 E2B 账户
- 安装所需软件包
pip install 'smolagents[e2b]'
在 E2B 中运行您的 Agent:快速入门
我们提供了一种使用 E2B 沙箱的简单方法:只需在 Agent 初始化时添加 `executor_type="e2b"`,如下所示:
from smolagents import InferenceClientModel, CodeAgent
with CodeAgent(model=InferenceClientModel(), tools=[], executor_type="e2b") as agent:
agent.run("Can you give me the 100th Fibonacci number?")
使用 Agent 作为上下文管理器(使用 `with` 语句)可确保在 Agent 完成任务后立即清理 E2B 沙箱。或者,您可以手动调用 Agent 的 `cleanup()` 方法。
此解决方案在每次 `agent.run()` 开始时将 Agent 状态发送到服务器。然后从本地环境调用模型,但生成的代码将被发送到沙箱执行,并且只返回输出。
下图对此进行了说明。
然而,由于任何对受管理 Agent 的调用都需要模型调用,并且我们不将机密信息传输到远程沙箱,因此模型调用将缺少凭据。因此,该解决方案尚不适用于更复杂的多 Agent 设置。
在 E2B 中运行您的 Agent:多 Agent
要在 E2B 沙箱中使用多 Agent,您需要完全在 E2B 内部运行您的 Agent。
具体方法如下:
from e2b_code_interpreter import Sandbox
import os
# Create the sandbox
sandbox = Sandbox()
# Install required packages
sandbox.commands.run("pip install smolagents")
def run_code_raise_errors(sandbox, code: str, verbose: bool = False) -> str:
execution = sandbox.run_code(
code,
envs={'HF_TOKEN': os.getenv('HF_TOKEN')}
)
if execution.error:
execution_logs = "\n".join([str(log) for log in execution.logs.stdout])
logs = execution_logs
logs += execution.error.traceback
raise ValueError(logs)
return "\n".join([str(log) for log in execution.logs.stdout])
# Define your agent application
agent_code = """
import os
from smolagents import CodeAgent, InferenceClientModel
# Initialize the agents
agent = CodeAgent(
model=InferenceClientModel(token=os.getenv("HF_TOKEN"), provider="together"),
tools=[],
name="coder_agent",
description="This agent takes care of your difficult algorithmic problems using code."
)
manager_agent = CodeAgent(
model=InferenceClientModel(token=os.getenv("HF_TOKEN"), provider="together"),
tools=[],
managed_agents=[agent],
)
# Run the agent
response = manager_agent.run("What's the 20th Fibonacci number?")
print(response)
"""
# Run the agent code in the sandbox
execution_logs = run_code_raise_errors(sandbox, agent_code)
print(execution_logs)
Docker 设置
安装
- 在您的系统上安装 Docker
- 安装所需软件包
pip install 'smolagents[docker]'
在 Docker 中运行您的 Agent:快速入门
与上面的 E2B 沙箱类似,要快速开始使用 Docker,只需在 Agent 初始化时添加 `executor_type="docker"`,如下所示:
from smolagents import InferenceClientModel, CodeAgent
with CodeAgent(model=InferenceClientModel(), tools=[], executor_type="docker") as agent:
agent.run("Can you give me the 100th Fibonacci number?")
使用 Agent 作为上下文管理器(使用 `with` 语句)可确保在 Agent 完成任务后立即清理 Docker 容器。或者,您可以手动调用 Agent 的 `cleanup()` 方法。
高级 Docker 用法
如果要在 Docker 中运行多 Agent 系统,您需要在一个沙箱中设置一个自定义解释器。
以下是如何设置 Dockerfile 的方法:
FROM python:3.10-bullseye
# Install build dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
python3-dev && \
pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir smolagents && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /app
# Run with limited privileges
USER nobody
# Default command
CMD ["python", "-c", "print('Container ready')"]
创建一个沙箱管理器来运行代码
import docker
import os
from typing import Optional
class DockerSandbox:
def __init__(self):
self.client = docker.from_env()
self.container = None
def create_container(self):
try:
image, build_logs = self.client.images.build(
path=".",
tag="agent-sandbox",
rm=True,
forcerm=True,
buildargs={},
# decode=True
)
except docker.errors.BuildError as e:
print("Build error logs:")
for log in e.build_log:
if 'stream' in log:
print(log['stream'].strip())
raise
# Create container with security constraints and proper logging
self.container = self.client.containers.run(
"agent-sandbox",
command="tail -f /dev/null", # Keep container running
detach=True,
tty=True,
mem_limit="512m",
cpu_quota=50000,
pids_limit=100,
security_opt=["no-new-privileges"],
cap_drop=["ALL"],
environment={
"HF_TOKEN": os.getenv("HF_TOKEN")
},
)
def run_code(self, code: str) -> Optional[str]:
if not self.container:
self.create_container()
# Execute code in container
exec_result = self.container.exec_run(
cmd=["python", "-c", code],
user="nobody"
)
# Collect all output
return exec_result.output.decode() if exec_result.output else None
def cleanup(self):
if self.container:
try:
self.container.stop()
except docker.errors.NotFound:
# Container already removed, this is expected
pass
except Exception as e:
print(f"Error during cleanup: {e}")
finally:
self.container = None # Clear the reference
# Example usage:
sandbox = DockerSandbox()
try:
# Define your agent code
agent_code = """
import os
from smolagents import CodeAgent, InferenceClientModel
# Initialize the agent
agent = CodeAgent(
model=InferenceClientModel(token=os.getenv("HF_TOKEN"), provider="together"),
tools=[]
)
# Run the agent
response = agent.run("What's the 20th Fibonacci number?")
print(response)
"""
# Run the code in the sandbox
output = sandbox.run_code(agent_code)
print(output)
finally:
sandbox.cleanup()
WebAssembly 设置
WebAssembly (Wasm) 是一种二进制指令格式,允许代码在安全的沙箱环境中运行。它被设计成快速、高效和安全,是执行潜在不受信任代码的绝佳选择。
`WasmExecutor` 使用 Pyodide 和 Deno。
安装
在 WebAssembly 中运行您的 Agent:快速入门
只需将 `executor_type="wasm"` 传递给 Agent 初始化,如下所示:
from smolagents import InferenceClientModel, CodeAgent
agent = CodeAgent(model=InferenceClientModel(), tools=[], executor_type="wasm")
agent.run("Can you give me the 100th Fibonacci number?")
沙箱的最佳实践
这些关键实践适用于 E2B 和 Docker 沙箱:
资源管理
- 设置内存和 CPU 限制
- 实施执行超时
- 监控资源使用情况
安全
- 以最低权限运行
- 禁用不必要的网络访问
- 使用环境变量存储机密
环境
- 保持依赖项最小化
- 使用固定的包版本
- 如果使用基础镜像,请定期更新
清理
- 始终确保正确清理资源,尤其是对于 Docker 容器,以避免出现占用资源的悬空容器。
✨ 通过遵循这些实践并实施适当的清理程序,您可以确保您的 Agent 在沙箱环境中安全高效地运行。
比较安全方法
如前图所示,两种沙箱方法具有不同的安全影响:
方法 1:仅在沙箱中运行代码片段
- 优点:
- 通过简单参数(`executor_type="e2b"` 或 `executor_type="docker"`)更容易设置
- 无需将 API 密钥传输到沙箱
- 更好地保护您的本地环境
- 缺点:
- 不支持多 Agent(受管理 Agent)
- 仍需要在您的环境和沙箱之间传输状态
- 仅限于特定的代码执行
方法 2:在沙箱中运行整个 Agent 系统
- 优点:
- 支持多 Agent
- 完全隔离整个 Agent 系统
- 对于复杂的 Agent 架构更灵活
- 缺点:
- 需要更多手动设置
- 可能需要将敏感的 API 密钥传输到沙箱
- 由于更复杂的操作,可能延迟更高
选择最能平衡您的安全需求与应用程序要求的方法。对于大多数具有较简单 Agent 架构的应用程序,方法 1 提供了安全性和易用性的良好平衡。对于需要完全隔离的更复杂的多 Agent 系统,方法 2 虽然设置更复杂,但提供了更好的安全保障。
< > 在 GitHub 上更新