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 上更新