智能体和沙箱的两种集成方式

分类技术博客
来源跳转
发表时间

内容

感谢 Witan Labs 的 Nuno Campos、E2B 的 Tomas Beran 和 Mikayel Harutyunyan、Runloop 的 Jonathan Wall 以及 Zo Computer 的 Ben Guo 对本文的审阅和评论。

TL;DR:

  • 越来越多的代理需要一个工作空间:一个可以运行代码、安装包并访问文件的计算机。沙盒提供了这一功能。
  • 将代理与沙盒集成有两种架构模式:
    • 模式 1(代理在沙盒中): 代理在沙盒中运行,您通过网络与其通信。优点:与本地开发环境相似,代理与环境之间的耦合度高。
    • 模式 2(沙盒作为工具): 代理在本地或服务器上运行,远程调用沙盒执行代码。优点:易于更新代理逻辑,API 密钥保持在沙盒外,关注点分离更清晰。
  • deepagents 支持两种模式,配置简单

越来越多的代理需要一个工作空间 - 一个可以运行代码、安装包并访问文件的计算机。这个工作空间需要被隔离,以防止代理访问您的凭据、文件或网络。沙盒通过在代理环境和主机系统之间创建边界提供了这种隔离。构建这些代理的团队面临的问题不是 是否 使用沙盒,而是 如何将其集成 到代理架构中。

根据代理运行的位置,有两种常见的模式:在沙盒内或在沙盒外。每种模式都有不同的优点和权衡。

注意:本文重点介绍为代理提供完整“计算机”的沙盒,例如 Docker 容器或虚拟机。我们不会涵盖进程级沙盒(如 bubblewrap)或语言级沙盒(如 Pyodide)。

模式 1:代理在沙盒中运行

在这种模式中,代理在沙盒中运行,您通过网络与其通信。

这种模式在实践中的应用:

您构建一个带有代理框架预安装的 Docker 或 VM 镜像,在沙盒中运行,并从外部连接以发送消息。代理暴露一个 API 端点(通常是 HTTP 或 WebSocket),您的应用程序通过沙盒边界与其通信。

优点:

这种模式与本地开发环境非常相似 - 如果您在本地终端运行 deepagents,您也可以在沙盒中运行相同的命令。代理具有直接的文件系统访问权限,可以修改其环境。这在代理和执行环境紧密耦合时很有用,例如代理需要与特定库交互或维护复杂的环境状态。

权衡:

跨沙盒边界的通信需要基础设施。一些提供商在其 SDK 中处理了这一点 - 例如,像 OpenCode 这样的代理在沙盒中运行服务器,而像 E2B 这样的提供商可以通过干净的 API 暴露它。如果您的提供商不提供此功能,您需要自己构建 WebSocket 或 HTTP 层,包括会话管理和错误处理。

API 密钥必须位于沙盒内,以允许代理进行推理调用。这在沙盒被破坏时创建了潜在的安全风险,无论是通过隔离技术中的漏洞还是通过提示注入攻击来泄露凭据。注意:我们看到像 E2B 和 Runloop 这样的提供商正在开发秘密存储功能,这解决了这个问题。

更新需要重新构建容器镜像和重新部署,这可能会减慢开发过程中的迭代速度。

另一个缺点是沙盒必须在代理激活之前恢复,这通常需要额外的逻辑。

对于那些担心保护代理 IP 的人来说,如果代理在沙盒中运行,很容易泄露代理的整个代码和提示。

Witan Labs 的 Nuno Campos 指出另一个安全风险:“我认为代理在沙盒中的另一个缺点是,代理的任何部分都不能比 bash 工具具有更高的权限。例如,想象一个具有 bash 工具和可以进行 Web 搜索或 Web 获取的工具的代理,那么所有由 LLM 生成的代码都可以进行无限制的 Web 获取(这是一个巨大的安全风险)。如果是沙盒作为工具,那么您可以拥有比 LLM 生成的代码具有更高权限的工具,这对于许多代理来说听起来很有用,因为安全边界在 bash 工具周围,而不是整个代理周围。”

在这种模式中,代理在您的机器或服务器上运行。当它需要执行代码时,它会通过 API 远程调用沙盒。

这种模式在实践中的应用:

您的代理在本地运行(或在您的服务器上),当它生成需要执行的代码时,它会调用沙盒提供商的 API(如 E2BModalDaytonaRunloop)。提供商的 SDK 处理所有通信细节。从代理的角度来看,沙盒只是另一个工具。

优点:

您可以在不重新构建容器镜像的情况下立即更新代理代码,这加快了开发过程中的迭代速度。API 密钥保持在沙盒外 - 只有执行发生在隔离中。这提供了更清晰的关注点分离:代理状态(对话历史、推理链、内存)生活在代理运行的地方,与沙盒分开。这意味着沙盒故障不会丢失代理的状态,您可以在不影响代理核心逻辑的情况下切换沙盒后端。

E2B 的 Tomas Beran 指出这种选项的两个其他优点:

  1. 有选择在多个远程沙盒中并行运行任务的选项
  2. 只为执行代码付费,而不是为整个过程运行时间付费

Ben Guo 添加了一个关于将代理运行时与沙盒运行时分离的好处的最后一点:“我们选择模式 2 的原因是您提到的原因,但也为未来做准备,在这种未来中,在 GPU 机器上运行代理Harness 是有意义的 - 一般来说,环境要求将在持久沙盒和推理Harness 之间发散”

权衡:

网络延迟是主要的缺点。每个执行调用都会跨越网络边界。对于有许多小型执行的工作负载来说,这可能会累加起来。

许多沙盒提供商提供有状态会话,其中变量、文件和安装的包在同一会话中的调用之间保持不变。这可以减轻一些延迟问题,通过减少需要的往返次数。

选择模式

选择模式 1 时:

  • 代理和执行环境紧密耦合(例如,代理需要对特定库或复杂环境状态进行持久访问)
  • 您希望生产环境与本地开发环境密切匹配
  • 您的提供商的 SDK 为您处理通信层

选择模式 2 时:

  • 您需要在开发过程中快速迭代代理逻辑
  • 您希望将 API 密钥保持在沙盒外
  • 您更喜欢代理状态和执行环境之间的更清晰的分离

实现示例

为了使这些模式具体化,我们将使用 deepagents 示例,这是一个具有内置沙盒支持的开源代理框架。其他代理框架也可以应用类似的模式。

模式 1:代理在沙盒中

对于模式 1,首先您构建一个带有代理预安装的镜像:

FROM python:3.11
RUN pip install deepagents-cli

然后在沙盒中运行它。完整的实现需要额外的基础设施来处理应用程序和沙盒中的代理之间的通信(WebSocket 或 HTTP 服务器、会话管理、错误处理)。这超出了本文的范围,但我们将在后续文章中更详细地介绍这一点。

模式 2:沙盒作为工具

from daytona import Daytona
from langchain_anthropic import ChatAnthropic

from deepagents import create_deep_agent
from langchain_daytona import DaytonaSandbox

# 也可以使用 E2B、Runloop、Modal
sandbox = Daytona().create()
backend = DaytonaSandbox(sandbox=sandbox)

agent = create_deep_agent(
    model=ChatAnthropic(model="claude-sonnet-4-20250514"),
    system_prompt="您是一个具有沙盒访问权限的 Python 编码助手。",
    backend=backend,
)

result = agent.invoke(
    {
        "messages": [
            {
                "role": "user",
                "content": "运行一个小的 Python 脚本",
            }
        ]
    }
)

sandbox.stop()

以下是当此代码运行时发生的情况:

  1. 代理在本地机器上规划
  2. 它生成 Python 代码来解决问题
  3. 它调用 Runloop API,该 API 在远程沙盒中执行代码
  4. 沙盒返回结果
  5. 代理看到输出并继续在本地推理

结论

代理需要在隔离环境中执行代码以确保安全。有两种架构模式:在沙盒中运行代理(与本地开发环境相似,代理与环境紧密耦合)或在外部运行代理,使用沙盒作为工具(易于更新,API 密钥安全)。每种模式都有不同的优点和权衡,取决于您的需求。

deepagents 支持两种模式,配置简单。尝试一下,看看哪种模式最适合您的用例。

评论

(0)
未配置登录方式
暂无评论