跳到主要内容

文档索引

在以下地址获取完整的文档索引:https://docs.langchain.org.cn/llms.txt

在进一步探索之前,请使用此文件发现所有可用页面。

智能体生成代码、与文件系统交互并运行 shell 命令。由于我们无法预测智能体可能执行的操作,因此隔离其环境以使其无法访问凭据、文件或网络至关重要。沙箱通过在智能体的执行环境和您的主机系统之间创建边界来提供这种隔离。 在 Deep Agents 中,沙箱是后端,定义了智能体运行的环境。与其他仅公开文件操作的后端(State、Filesystem、Store)不同,沙箱后端还为智能体提供了一个用于运行 shell 命令的 execute 工具。当您配置沙箱后端时,智能体会获得:
  • 所有标准文件系统工具 (ls, read_file, write_file, edit_file, glob, grep)
  • 用于在沙箱中运行任意 shell 命令的 execute 工具
  • 保护您主机系统的安全边界

为什么使用沙箱?

沙箱用于安全保障。它们允许智能体在不损害您的凭据、本地文件或主机系统的情况下执行任意代码、访问文件和使用网络。这种隔离在智能体自主运行时至关重要。 沙箱特别适用于:
  • 代码智能体:自主运行的智能体可以使用 shell、git、克隆存储库(许多提供商提供原生 git API,例如 Daytona 的 git 操作),并在构建和测试流水线中运行 Docker-in-Docker
  • 数据分析智能体:在安全、隔离的环境中加载文件、安装数据分析库(pandas、numpy 等)、运行统计计算,并创建诸如 PowerPoint 演示文稿之类的输出
正在使用 Deep Agents CLI? CLI 通过 --sandbox 标志内置了沙箱支持。有关 CLI 特定设置、标志 (--sandbox-id, --sandbox-setup) 和示例,请参阅使用远程沙箱

基本用法

这些示例假设您已经使用提供商的 SDK 创建了沙箱/开发箱 (devbox),并设置了凭据。有关注册、身份验证和特定于提供商的生命周期详细信息,请参阅可用提供商
import { createDeepAgent } from "deepagents";
import { ChatAnthropic } from "@langchain/anthropic";
import { DenoSandbox } from "@langchain/deno";

// Create and initialize the sandbox
const sandbox = await DenoSandbox.create({
  memoryMb: 1024,
  lifetime: "10m",
});

try {
  const agent = createDeepAgent({
    model: new ChatAnthropic({ model: "claude-opus-4-6" }),
    systemPrompt: "You are a JavaScript coding assistant with sandbox access.",
    backend: sandbox,
  });

  const result = await agent.invoke({
    messages: [
      {
        role: "user",
        content:
          "Create a simple HTTP server using Deno.serve and test it with curl",
      },
    ],
  });
} finally {
  await sandbox.close();
}

可用提供商

技能功能要求 deepagents>=1.7.0
没有看到您的提供商?您可以实现自己的沙箱后端。参阅贡献沙箱集成

生命周期和作用域

沙箱在关闭前会消耗资源并产生费用。如何管理它们的生命周期取决于您的应用程序。 选择沙箱生命周期如何映射到应用程序的资源。有关此决策的更多信息,请参阅推向生产环境

线程作用域(默认)

每个对话都有自己的沙箱。沙箱在第一次运行开始时创建,并在同一线程的后续消息中重复使用。当线程被清理(或沙箱 TTL 过期)时,沙箱将被销毁。这是大多数智能体的正确默认设置。 示例:一个数据分析机器人,其每个对话都从干净的环境开始。

助手作用域 (Assistant-scoped)

给定助手的所有线程共享一个沙箱。沙箱 ID 存储在助手的配置中,因此每次对话都会回到相同的环境。文件、安装的包和克隆的存储库在对话之间保持持久。当智能体维护长期运行的工作空间时,请使用此选项。 示例:一个编码助手,它在不同对话之间维护克隆的存储库和已安装的依赖项。
助手作用域的沙箱会随着时间的推移累积文件、安装的包和其他沙箱内状态。请为您的沙箱提供商配置 TTL(生存时间),使用快照定期重置,或实施清理逻辑,以防止沙箱的磁盘和内存无限制增长。线程作用域的沙箱通过每次对话重新开始来避免这种情况。

基础生命周期

// Create and initialize
const sandbox = await ModalSandbox.create(options);

// Use the sandbox (directly or via an agent)
const result = await sandbox.execute("echo hello");

// Clean up when done
await sandbox.close();

单次会话生命周期

在聊天应用中,对话通常由 thread_id 表示。通常,每个 thread_id 都应该使用自己唯一的沙箱。 将沙箱 ID 与 thread_id 之间的映射存储在您的应用程序中,或者如果沙箱提供商允许将元数据附加到沙箱,则存储在沙箱中。
聊天应用的 TTL。 当用户在空闲时间后可能重新参与时,您通常不知道他们是否或何时会回来。在沙箱上配置生存时间 (TTL)——例如归档 TTL 或删除 TTL——以便提供商自动清理空闲的沙箱。许多沙箱提供商都支持此功能。
import "dotenv/config";
import { randomUUID } from "node:crypto";
import { Daytona } from "@daytonaio/sdk";
import type { CreateSandboxFromSnapshotParams } from "@daytonaio/sdk";
import { DaytonaSandbox } from "@langchain/daytona";
import { createDeepAgent } from "deepagents";

const client = new Daytona();
const threadId = randomUUID();

// Get or create sandbox by thread_id
let sandbox;
try {
    sandbox = await client.findOne({ labels: { thread_id: threadId } });
} catch {
    const params: CreateSandboxFromSnapshotParams = {
        labels: { thread_id: threadId },
        // Add TTL so the sandbox is cleaned up when idle (minutes)
        autoDeleteInterval: 3600,
    };
sandbox = await client.create(params);
}

const backend = await DaytonaSandbox.fromId(sandbox.id);
const agent = createDeepAgent({
    backend,
    systemPrompt:
        "You are a coding assistant with sandbox access. You can create and run code in the sandbox.",
});

try {
    const result = await agent.invoke(
        {
            messages: [
                {
                role: "user",
                content: "Create a hello world Python script and run it",
                },
            ],
        },
        {
            configurable: {
                thread_id: threadId,
            },
        },
    );
    const lastMessage = result.messages[result.messages.length - 1];
    console.log(
        typeof lastMessage.content === "string"
        ? lastMessage.content
        : String(lastMessage.content),
    );
} catch (err) {
    // Optional: delete the sandbox proactively on an exception
    await client.delete(sandbox);
    throw err;
}

集成模式

根据智能体运行的位置,将智能体与沙箱集成的架构模式有两种。

“沙箱中的智能体”模式

智能体在沙箱内部运行,您通过网络与其通信。您使用预安装了智能体框架的 Docker 或 VM 镜像构建它,在沙箱中运行,并从外部连接以发送消息。 优点:
  • ✅ 非常贴近本地开发。
  • ✅ 智能体与环境紧密耦合。
权衡
  • 🔴 API 密钥必须保留在沙箱内(安全风险)。
  • 🔴 更新需要重新构建镜像。
  • 🔴 需要通信基础设施(WebSocket 或 HTTP 层)。
要在沙箱中运行智能体,请构建镜像并在其上安装 deepagents。
FROM python:3.11
RUN pip install deepagents-cli
然后在沙箱内运行智能体。要在沙箱内使用智能体,您必须添加额外的基础设施来处理您的应用程序与沙箱内智能体之间的通信。

“沙箱作为工具”模式

智能体在您的机器或服务器上运行。当它需要执行代码时,它会调用沙箱工具(如 execute, read_file, 或 write_file),这些工具调用提供商的 API 以在远程沙箱中运行操作。 优点:
  • ✅ 无需重新构建镜像即可立即更新智能体代码。
  • ✅ 智能体状态与执行更清晰的分离。
    • API 密钥保留在沙箱外部。
    • 沙箱故障不会丢失智能体状态。
    • 可以选择并行在多个沙箱中运行任务。
  • ✅ 仅为执行时间付费。
权衡
  • 🔴 每次执行调用都有网络延迟。
示例
import "dotenv/config";
import { DaytonaSandbox } from "@langchain/daytona";
import { createDeepAgent } from "deepagents";

// Can also do this with E2B, Runloop, Modal
const sandbox = await DaytonaSandbox.create();

const agent = createDeepAgent({
  backend: sandbox,
  systemPrompt:
    "You are a coding assistant with sandbox access. You can create and run code in the sandbox.",
});

try {
  const result = await agent.invoke({
    messages: [
      {
        role: "user",
        content: "Create a hello world Python script and run it",
      },
    ],
  });
  const lastMessage = result.messages[result.messages.length - 1];
  console.log(
    typeof lastMessage.content === "string"
      ? lastMessage.content
      : String(lastMessage.content),
  );
} catch (err) {
  // Optional: delete the sandbox proactively on an exception
  await sandbox.close();
  throw err;
}
本说明文档中的示例使用的是“沙箱作为工具”模式。当您的提供商 SDK 处理通信层并且您希望生产环境与本地开发保持一致时,请选择“沙箱中的智能体”模式。当您需要快速迭代智能体逻辑、将 API 密钥保留在沙箱外部或更喜欢更清晰的关注点分离时,请选择“沙箱作为工具”模式。

沙箱的工作原理

隔离边界

所有沙箱提供商都能保护您的主机系统免受智能体文件系统和 shell 操作的影响。智能体无法读取您的本地文件、访问您机器上的环境变量或干扰其他进程。然而,仅靠沙箱不能防止:
  • 上下文注入:控制部分智能体输入的攻击者可以指示其在沙箱内运行任意命令。沙箱是隔离的,但智能体在其中拥有完全控制权。
  • 网络外泄:除非阻塞了网络访问,否则被上下文注入的智能体可以通过 HTTP 或 DNS 从沙箱中发送数据。一些提供商支持阻塞网络访问(例如 Modal 上的 blockNetwork: true)。
有关如何处理密钥和降低这些风险的信息,请参阅安全注意事项

execute 方法

沙箱后端的架构很简单:提供商唯一必须实现的方法是 execute(),它运行 shell 命令并返回其输出。所有其他文件系统操作 (read, write, edit, ls, glob, grep) 都是由 BaseSandbox 基类通过 execute() 在沙箱内构造并运行脚本来构建的。 这种设计意味着
  • 添加新提供商非常简单。 只需实现 execute()——基类会处理其他所有事情。
  • execute 工具是按需可用的。 在每次模型调用时,该工具集都会检查后端是否实现了 SandboxBackendProtocol。如果没有实现,该工具将被过滤掉,智能体将永远看不到它。
当智能体调用 execute 工具时,它会提供一个 command 字符串,并获得合并的 stdout/stderr、退出代码,以及在输出过大时的截断通知。 您也可以在应用程序代码中直接调用后端 execute() 方法。 例如:
4
[Command succeeded with exit code 0]
bash: foobar: command not found
[Command failed with exit code 127]
如果命令产生非常大的输出,结果会自动保存到文件中,并指示智能体使用 read_file 增量访问该文件。这可以防止上下文窗口溢出。

文件访问的双重平面

文件进出沙箱有两种截然不同的方式,理解何时使用每种方式非常重要: 智能体文件系统工具read_file, write_file, edit_file, ls, glob, grep, 和 execute 是 LLM 在其执行期间调用的工具。这些操作通过沙箱内部的 execute() 进行。智能体使用它们来读取代码、写入文件并运行命令作为其任务的一部分。 文件传输 API:即您的应用程序代码调用的 uploadFiles()downloadFiles() 方法。这些使用提供商的原生文件传输 API(而非 shell 命令),旨在您的主机环境和沙箱之间移动文件。使用它们来:
  • 在智能体运行前,为沙箱植入源代码、配置或数据
  • 在智能体完成后,检索产物(生成的代码、构建输出、报告)
  • 预填充智能体需要的依赖项

处理文件

为沙箱植入种子

使用 uploadFiles() 在智能体运行前填充沙箱。文件内容作为 Uint8Array 提供
const encoder = new TextEncoder();
const responses = await sandbox.uploadFiles([
  ["src/index.js", encoder.encode("console.log('Hello')")],
  ["package.json", encoder.encode('{"name": "my-app"}')],
]);

// Each response indicates success or failure
for (const res of responses) {
  if (res.error) {
    console.error(`Failed to upload ${res.path}: ${res.error}`);
  }
}

检索产物

使用 downloadFiles() 在智能体完成后从沙箱中检索文件
const results = await sandbox.downloadFiles(["src/index.js", "output.txt"]);

const decoder = new TextDecoder();
for (const result of results) {
  if (result.content) {
    console.log(`${result.path}: ${decoder.decode(result.content)}`);
  } else {
    console.error(`Failed to download ${result.path}: ${result.error}`);
  }
}
在沙箱内部,智能体使用其自己的文件系统工具 (read_file, write_file):而不是 uploadFilesdownloadFiles。那些方法是供您的应用程序代码在主机和沙箱边界之间移动文件的。

安全注意事项

沙箱将代码执行与您的主机系统隔离,但它们不能防止上下文注入。控制部分智能体输入的攻击者可以指示其读取文件、运行命令或从沙箱内泄露数据。这使得沙箱内部的凭据变得尤为危险。
绝不要将密钥放在沙箱中。 注入到沙箱中的 API 密钥、令牌、数据库凭据和其他密钥(通过环境变量、挂载文件或 secrets 选项)可以被上下文注入的智能体读取并泄露。即使是短期或有作用域的凭据也是如此——如果智能体可以访问它们,攻击者也可以。

安全地处理密钥

如果您的智能体需要调用经过身份验证的 API 或访问受保护的资源,您有两种选择
  1. 将密钥保留在沙箱外部的工具中。 定义在主机环境(而非沙箱内部)运行的工具,并在那里处理身份验证。智能体按名称调用这些工具,但永远看不到凭据。这是推荐的做法。
  2. 使用注入凭据的网络代理。 一些沙箱提供商支持拦截来自沙箱的传出 HTTP 请求并在转发前附加凭据(例如 Authorization 标头)的代理。智能体永远看不到密钥——它只是向 URL 发出普通请求。这种方法尚未在提供商中广泛使用。
如果您必须向沙箱注入密钥(不推荐),请采取以下预防措施
  • 所有工具调用启用人机回环 (HITL)审批,而不只是敏感调用
  • 阻塞或限制来自沙箱的网络访问以限制外泄路径
  • 使用尽可能窄的凭据范围和尽可能短的生命周期
  • 监控沙箱网络流量以查找异常的传出请求
即使有这些保护措施,这仍然是一种不安全的折中方案。一个足够有创造力的上下文注入攻击可以绕过输出过滤和 HITL 审查。

通用最佳实践

  • 在您的应用程序根据沙箱输出采取行动之前,请先审查这些输出
  • 在不需要时阻塞沙箱的网络访问
  • 使用中间件过滤或脱敏工具输出中的敏感模式
  • 将沙箱内产生的一切内容视为不可信输入

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