Agents 会生成 code、与 filesystems 交互,并运行 shell commands。因为无法预测 agent 可能执行什么操作,所以隔离其环境很重要,避免它访问 credentials、files 或 network。Sandboxes 通过在 agent execution environment 和你的 host system 之间创建边界来提供这种隔离。 在 Deep Agents 中,sandboxes 是 backends,用于定义 agent 运行的 environment。不同于只暴露 file operations 的其他 backends(State、Filesystem、Store),sandbox backends 还会给 agent 一个用于运行 shell commands 的 execute tool。配置 sandbox backend 后,agent 会获得:
  • 所有 standard filesystem tools(lsread_filewrite_fileedit_fileglobgrep
  • 用于在 sandbox 中运行 arbitrary shell commands 的 execute tool
  • 保护 host system 的 secure boundary

Why use sandboxes?

Sandboxes 用于 security。 它们让 agents 可以 execute arbitrary code、access files,并使用 network,而不会危及你的 credentials、local files 或 host system。 当 agents autonomously 运行时,这种 isolation 至关重要。 Sandboxes 尤其适用于:
  • Coding agents:Autonomously 运行的 agents 可以使用 shell、git、clone repositories(许多 providers 提供 native git APIs,例如 Daytona’s git operations),并为 build 和 test pipelines 运行 Docker-in-Docker
  • Data analysis agents:在 safe、isolated environment 中 load files、install data analysis libraries(pandas、numpy 等)、运行 statistical calculations,并创建 PowerPoint presentations 等 outputs
正在使用 Deep Agents Code? Deep Agents Code 通过 --sandbox flag 提供 built-in sandbox support。请参阅 Use remote sandboxes 获取 Deep Agents Code-specific setup、flags(--sandbox-id--sandbox-setup)和 examples。

Basic usage

这些 examples 假设你已使用 provider 的 SDK 创建 sandbox/devbox,并已设置 credentials。有关 signup、authentication 和 provider-specific lifecycle details,请参阅 Available providers
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();
}
LangSmith traces 会显示在 sandbox 内运行了哪些 shell commands,以及 agent 如何使用 filesystem tools。按照 observability quickstart 完成设置。有关 managed sandbox hosting,请参阅 LangSmith Sandboxes建议你同时设置 LangSmith Engine,它会监控 traces、检测问题,并提出修复建议。

Available providers

Skills 需要 deepagents>=1.7.0
没有看到你的 provider?你可以实现自己的 sandbox backend。请参阅 Contributing a sandbox integration

Lifecycle and scoping

多数 applications 会选择每个 thread 一个 sandbox(thread-scoped),或同一个 assistant 上的所有 threads 共享一个 sandbox(assistant-scoped)。 Sandboxes 在 shut down 前会消耗 resources 并产生费用。请确保在不再使用时关闭 sandboxes。 有关完整 lifecycle table、async graph factory notes、TTL behavior、LangGraph Deployment wiring 和 client-side examples,请参阅 Going to production 中的 Sandbox lifecycle

Thread-scoped (default)

每个 conversation 都有自己的 sandbox。第一次 run 会创建它;同一 thread 上的 follow-up turns 会复用它。当 thread 结束或 sandbox TTL 过期时,environment 会消失。请像下面示例一样使用 provider labels 或 metadata 存储 mapping,使每次 run 都 resolve 到同一个 sandbox。
当 users 可能在 idle time 后返回时,请在 sandbox 上配置 TTL,让 provider 自动删除或归档 idle environments。
agent.py
from daytona import CreateSandboxFromSnapshotParams, Daytona
from deepagents import create_deep_agent
from langchain_core.runnables import RunnableConfig
from langchain_daytona import DaytonaSandbox

client = Daytona()


async def agent(config: RunnableConfig):
    thread_id = config["configurable"]["thread_id"]
    try:
        sandbox = await client.find_one(labels={"thread_id": thread_id})
    except Exception:
        sandbox = await client.create(
            CreateSandboxFromSnapshotParams(
                labels={"thread_id": thread_id},
                auto_delete_interval=3600,  # TTL: clean up when idle
            )
        )
    return create_deep_agent(
        model="google_genai:gemini-3.5-flash",
        backend=DaytonaSandbox(sandbox=sandbox)
    )

Assistant-scoped

同一 assistant 上的每个 thread 都复用同一个 sandbox。Files、installed packages 和 cloned repositories 会跨 conversations 持续存在。
Assistant-scoped sandboxes 会随时间累积 in-sandbox state。请通过 sandbox provider 配置 TTL,使用 snapshots 定期 reset,或实现 cleanup logic,避免 disk 和 memory 无限制增长。
agent.py
from daytona import CreateSandboxFromSnapshotParams, Daytona
from deepagents import create_deep_agent
from langchain_core.runnables import RunnableConfig
from langchain_daytona import DaytonaSandbox

client = Daytona()


async def agent(config: RunnableConfig):
    assistant_id = config["configurable"]["assistant_id"]
    try:
        sandbox = await client.find_one(labels={"assistant_id": assistant_id})
    except Exception:
        sandbox = await client.create(
            CreateSandboxFromSnapshotParams(labels={"assistant_id": assistant_id})
        )
    return create_deep_agent(
        model="google_genai:gemini-3.5-flash",
        backend=DaytonaSandbox(sandbox=sandbox)
    )
有关 graph factory 外部的 manual create、execute 和 teardown,请参阅 Basic usagesandbox integrations 了解 provider-specific APIs。

Integration patterns

根据 agent 运行位置,integrating agents with sandboxes 有两种 architecture patterns。

Agent in sandbox pattern

Agent 在 sandbox 内运行,你通过 network 与它通信。你构建一个预装 agent framework 的 Docker 或 VM image,在 sandbox 内运行它,并从外部连接以发送 messages。 Benefits:
  • ✅ 与 local development 高度一致。
  • ✅ Agent 与 environment 紧密耦合。
Trade-offs:
  • 🔴 API keys 必须存在于 sandbox 内(security risk)。
  • 🔴 Updates 需要 rebuild images。
  • 🔴 需要 communication infrastructure(WebSocket 或 HTTP layer)。
若要在 sandbox 中运行 agent,请构建 image 并在其中 install deepagents。
FROM python:3.11
RUN pip install deepagents-code
然后在 sandbox 内运行 agent。 若要使用 sandbox 内的 agent,你必须添加 additional infrastructure,用于处理 application 和 sandbox 内 agent 之间的 communication。

Sandbox as tool pattern

Agent 在你的 machine 或 server 上运行。当它需要 execute code 时,会调用 sandbox tools(例如 executeread_filewrite_file),这些 tools 会调用 provider APIs,在 remote sandbox 中运行 operations。 Benefits:
  • ✅ 无需 rebuilding images 即可即时 update agent code。
  • ✅ Agent state 和 execution 之间有更清晰的 separation。
    • API keys 保留在 sandbox 外。
    • Sandbox failures 不会丢失 agent state。
    • 可以选择在多个 sandboxes 中 parallel 运行 tasks。
  • ✅ 只为 execution time 付费。
Trade-offs:
  • 🔴 每次 execution call 都有 network latency。
Example
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;
}
本文档中的 examples 使用 sandbox as tool pattern。 当 provider 的 SDK 处理 communication layer,并且你希望 production mirror local development 时,选择 agent in sandbox pattern。 当你需要快速迭代 agent logic、将 API keys 保留在 sandbox 外,或偏好 cleaner separation of concerns 时,选择 sandbox as tool pattern。

How sandboxes work

Isolation boundaries

所有 sandbox providers 都会保护 host system,避免受到 agent filesystem 和 shell operations 影响。Agent 无法读取你的 local files、访问 machine 上的 environment variables,或干扰其他 processes。但是,仅靠 sandboxes 不能 防范:
  • Context injection:控制 agent input 一部分的 attacker 可以指示它在 sandbox 内运行 arbitrary commands。Sandbox 是 isolated,但 agent 在其中拥有 full control。
  • Network exfiltration:除非 block network access,否则被 context-injected 的 agent 可以通过 HTTP 或 DNS 将 data 发送到 sandbox 外。某些 providers 支持 blocking network access(例如 Modal 上的 blockNetwork: true)。
有关如何 handle secrets 并 mitigate these risks,请参阅 security considerations

The execute method

Sandbox backends 的 architecture 很简单:provider 必须实现的唯一 method 是 execute(),它运行 shell command 并返回 output。其他每个 filesystem operation(readwriteeditlsglobgrep)都由 BaseSandbox base class 构建在 execute() 之上,该 base class 会构造 scripts,并通过 execute() 在 sandbox 内运行它们。 此设计意味着:
  • 添加 new provider 很直接。 实现 execute(),base class 会处理其他所有内容。
  • execute tool 是 conditionally available。 每次 model call 时,harness 都会检查 backend 是否实现 SandboxBackendProtocol。如果没有,该 tool 会被 filter out,agent 永远不会看到它。
当 agent 调用 execute tool 时,它提供 command string,并获取 combined stdout/stderr、exit code,以及 output 过大时的 truncation notice。 你也可以在 application code 中直接调用 backend execute() method。 例如:
4
[Command succeeded with exit code 0]
bash: foobar: command not found
[Command failed with exit code 127]
如果 command 产生很大的 output,result 会自动保存到 file,并指示 agent 使用 read_file 增量访问它。这可以防止 context window overflow。

Two planes of file access

Files 进出 sandbox 有两种不同方式,理解何时使用各自方式很重要: Agent filesystem toolsread_filewrite_fileedit_filelsglobgrepexecute 是 LLM 在 execution 期间调用的 tools。它们通过 sandbox 内的 execute() 执行。Agent 使用它们 read code、write files,并将 run commands 作为 task 的一部分。 File transfer APIs:你的 application code 调用的 uploadFiles()downloadFiles() methods。它们使用 provider 的 native file transfer APIs(不是 shell commands),用于在 host environment 和 sandbox 之间移动 files。使用它们来:
  • Seed the sandbox:在 agent 运行前放入 source code、configuration 或 data
  • Retrieve artifacts:在 agent 完成后取回 generated code、build outputs、reports
  • Pre-populate dependencies:预先放入 agent 将需要的 dependencies

Working with files

Seeding the sandbox

在 agent 运行前使用 uploadFiles() 填充 sandbox。File contents 以 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}`);
  }
}

Retrieving artifacts

Use downloadFiles() to retrieve files from the sandbox after the agent finishes:
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}`);
  }
}
在 sandbox 内部,agent 使用自己的 filesystem tools(read_filewrite_file),而不是 uploadFilesdownloadFiles。这些 methods 用于让你的 application code 跨 host 和 sandbox 的边界移动 files。

Security considerations

Sandboxes 会将 code execution 与 host system 隔离,但它们不能防范 context injection。控制 agent input 一部分的 attacker 可以指示它在 sandbox 内 read files、run commands 或 exfiltrate data。这让 sandbox 内的 credentials 尤其危险。
永远不要把 secrets 放进 sandbox。 注入 sandbox 的 API keys、tokens、database credentials 和其他 secrets(通过 environment variables、mounted files 或 secrets option)可以被 context-injected agent 读取并 exfiltrate。即使是 short-lived 或 scoped credentials 也是如此:如果 agent 可以访问,attacker 也可以访问。

Handling secrets safely

如果你的 agent 需要调用 authenticated APIs 或访问 protected resources,有两个选项:
  1. 将 secrets 保留在 sandbox 外部的 tools 中。 定义在 host environment(不是 sandbox 内)运行的 tools,并在那里处理 authentication。Agent 按 name 调用这些 tools,但永远看不到 credentials。这是推荐方法。
  2. 使用注入 credentials 的 network proxy。 某些 sandbox providers 支持 proxies,它们会拦截 sandbox 发出的 outgoing HTTP requests,并在转发前附加 credentials(例如 Authorization headers)。Agent 永远看不到 secret,它只向 URL 发出 plain requests。此方法尚未在 providers 间广泛可用。
如果必须将 secrets 注入 sandbox(不推荐),请采取以下 precautions:
  • all tool calls 启用 human-in-the-loop approval,而不仅是 sensitive calls
  • Block 或 restrict sandbox 的 network access,以限制 exfiltration paths
  • 使用尽可能窄的 credential scope 和尽可能短的 lifetime
  • 监控 sandbox network traffic,查找 unexpected outbound requests
即使有这些 safeguards,这仍然是不安全的 workaround。足够有创意的 context injection attack 可以绕过 output filtering 和 HITL review。

General best practices

  • 在 application 中使用 sandbox outputs 前先 review
  • 不需要 network access 时 block sandbox network access
  • 使用 middleware filter 或 redact tool outputs 中的 sensitive patterns
  • 将 sandbox 内生成的一切视为 untrusted input