smolagents 文件

安全程式碼執行

Hugging Face's logo
加入 Hugging Face 社群

並獲得增強的文件體驗

開始使用

安全程式碼執行

如果您是構建代理的新手,請務必先閱讀代理簡介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 中,有兩種主要的沙箱程式碼執行方法,每種方法都具有不同的安全屬性和功能:

Sandbox approaches comparison

  1. 在沙箱中執行單個程式碼片段:這種方法(圖左側)僅在沙箱中執行 Agent 生成的 Python 程式碼片段,而將 Agent 系統的其餘部分保留在您的本地環境中。使用 `executor_type="e2b"` 或 `executor_type="docker"` 進行設定更簡單,但它不支援多 Agent,並且仍需要在您的環境和沙箱之間傳遞狀態資料。

  2. 在沙箱中執行整個 Agent 系統:這種方法(圖右側)在沙箱環境中執行整個 Agent 系統,包括 Agent、模型和工具。這提供了更好的隔離,但需要更多手動設定,並且可能需要將敏感憑據(如 API 金鑰)傳遞到沙箱環境。

本指南介紹瞭如何為您的 Agent 應用程式設定和使用這兩種沙箱方法。

E2B 設定

安裝

  1. e2b.dev 建立一個 E2B 賬戶
  2. 安裝所需軟體包
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 狀態傳送到伺服器。然後從本地環境呼叫模型,但生成的程式碼將被髮送到沙箱執行,並且只返回輸出。

下圖對此進行了說明。

sandboxed code execution

然而,由於任何對受管理 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 設定

安裝

  1. 在您的系統上安裝 Docker
  2. 安裝所需軟體包
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` 使用 PyodideDeno

安裝

  1. 在您的系統上安裝 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 上更新

© . This site is unofficial and not affiliated with Hugging Face, Inc.