Skip to content
LangSmith 文档版本 跟随上游 源快照 a954dd4d 更新于 2026-10-18

为 Managed Deep Agents 添加沙箱

为一个托管 deep agent 配置一个隔离的文件系统和 shell。

沙箱为托管 deep agent 提供一个隔离的文件系统和 shell,用于处理文件、运行代码和执行命令。

NOTE

Managed Deep Agents 处于公开 beta 阶段,仅在 US 区域的 LangSmith Cloud 上可用。

把沙箱声明放在 sandbox/ 下。只有当你想预配一个快照时,才添加 sandbox/setup.sh:

text
my-agent/
  agent.py
  sandbox/
    __init__.py
    setup.sh   # optional

有关完整项目布局,请参阅项目结构。

配置沙箱

当 agent 需要写文件、运行代码或执行 shell 命令时,使用沙箱。

mda init 会搭建一个沙箱声明。Managed Deep Agents 仅在 sandbox/ 目录存在时启用沙箱。

mda init 不会创建 setup.sh。如果快照应当安装包、克隆一个树或以其他方式更改镜像,请你自己添加那个文件。

Managed Deep Agents 为此后端使用 LangSmith 沙箱。复用始终是每个持久线程一个沙箱。

用 define_sandbox 声明沙箱:

python
from managed_deepagents import define_sandbox

sandbox = define_sandbox(
    idle_ttl_seconds=600,
    default_timeout=600,
)
选项默认值描述
idle_ttl_seconds600沙箱及其内容被删除之前的不活动秒数。删除不可恢复。
default_timeout600每条命令允许的秒数。

配置沙箱代理

沙箱代理会向匹配的出站请求注入标头,并控制沙箱能到达哪些目的地。代理在沙箱之外运行,因此沙箱代码可以调用经过身份验证的 API 而无需处理凭据。

例如,要从沙箱调用 OpenAI API,把 OPENAI_API_KEY 存入你的 LangSmith 工作区机密,并配置此代理规则:

python
from managed_deepagents import define_sandbox

sandbox = define_sandbox(
    proxy_config={
        "rules": [
            {
                "name": "openai-api",
                "match_hosts": ["api.openai.com"],
                "headers": [
                    {
                        "name": "Authorization",
                        "type": "workspace_secret",
                        "value": "Bearer {OPENAI_API_KEY}",
                    },
                ],
            },
        ],
    },
)

有关配置选项和网络限制,参阅沙箱身份验证代理。

在代理标头中使用连接

在沙箱中使用连接来为 CLI 命令和 API 请求进行身份验证。

例如,要以当前用户身份从沙箱调用 GitHub API,先创建 github 连接,然后配置代理:

python
from managed_deepagents import bearer, connections, define_sandbox

github = connections.get("github", {"type": "user"})

sandbox = define_sandbox(
    proxy_config={
        "rules": [
            {
                "name": "github-api",
                "match_hosts": ["api.github.com"],
                "headers": [{"name": "Authorization", "value": bearer(github)}],
            },
        ],
        "access_control": {"allow_list": ["api.github.com"]},
    },
)

将一个连接引用用作标头值,或用 bearer(ref) 或 basic(username, ref) 格式化它。对于连接值,省略标头的 type。Managed Deep Agents 会把它设为 opaque。

预配快照

如果 sandbox/setup.sh 存在,mda deploy 和 mda dev 会运行该脚本一次,并把结果环境保存为一个快照。那次运行产生的修改,例如克隆的仓库和安装的包,会持久保存在快照中。新线程克隆那个快照,而非运行 setup.sh。在 setup.sh 更改之前快照会被复用,一旦更改它就重新构建。

该脚本以 bash -e 运行。非零退出会使快照以及那次部署或 mda dev 会话失败。LangSmith 不会把线上部署更新到失败的快照。任何先前成功的快照会继续服务。

bash
#!/usr/bin/env bash
set -euo pipefail

apt-get update && apt-get install -y jq
mkdir -p /workspace

项目 .env 中被 deploy 转发的值,在 setup.sh 运行时作为环境变量可用,例如用于克隆私有仓库的令牌。克隆快照的线程沙箱不会继承那些变量。在 setup.sh 运行时不要把机密写入文件系统;磁盘上的任何东西都是每个线程镜像的一部分。

编辑 setup.sh 并重新部署,不会清除线上线程上的 /workspace。那些沙箱保留它们已有的文件。新线程会克隆新快照。

选择烘焙基座

若没有烘焙基座,LangSmith 的默认沙箱模板是起点。要从别的东西开始,请恰好设置以下之一:

选项用途
snapshot_nameLangSmith 快照名称。允许带标签。
snapshot_idLangSmith 快照 id。
docker_image已发布的 Docker 镜像。
python
from managed_deepagents import define_sandbox

sandbox = define_sandbox(
    idle_ttl_seconds=600,
    docker_image="python:3.12-slim",
)

对于私有镜像,传入镜像和一个 registry。Managed Deep Agents 会在烘焙时创建或更新一个部署自有的 Host 注册表。只有变量名会被编译;凭据值不会进入构建或快照。

在 password_env 中命名密码:

python
from managed_deepagents import define_sandbox

sandbox = define_sandbox(
    docker_image="ghcr.io/acme/agent-base:1",
    registry={
        "url": "ghcr.io",
        "username": "octocat",
        "password_env": "GHCR_TOKEN",
    },
)

把 GHCR_TOKEN 放在项目 .env 或进程环境中。烘焙之后,Managed Deep Agents 不会把那个值转发给正在运行的 Agent Server。

agent 如何使用沙箱

agent 使用内置的文件系统工具,例如 ls、read_file、write_file、edit_file、delete、glob 和 grep,并用 execute 运行 shell 命令。使用指令来指定 agent 应在何处工作以及不得修改什么。

从代码读写沙箱文件

自编工具和中间件通过 runtime.backend 访问沙箱文件系统。当你自己的代码需要一个文件时使用它,而不是提示 agent 替你获取。

NOTE

runtime.backend 需要 managed-deepagents>=0.8.0。

为 runtime 参数添加注解以接收类型化的接口:

python
from langchain.tools import tool
from managed_deepagents import ManagedDeepAgentRuntime

@tool(parse_docstring=True)
def write_report(summary: str, runtime: ManagedDeepAgentRuntime) -> str:
    """Write a summary to the sandbox and return its path.

    Args:
        summary: Report body to store.
    """
    if runtime.backend is None:
        raise RuntimeError("write_report requires a sandbox")
    result = runtime.backend.write("/workspace/report.txt", summary)
    if result.error:
        raise RuntimeError(result.error)
    return "/workspace/report.txt"

每个操作都绑定到处理当前运行的那个线程的沙箱,因此两个线程读取 /workspace/report.txt 时各自看到自己的副本。后端惰性解析,且一个从不触碰它的工具永远不会预配一个沙箱。

可用操作

方法目的
ls(path)列出一个目录。
read(file_path, offset, limit)读取文本,默认 2000 行。
write(file_path, content)写入文本,替换任何现有文件。
edit(file_path, old_string, new_string, replace_all)就地替换一个子串。
delete(file_path)移除一个文件。
grep(pattern, path, glob, max_count)搜索文件内容。
glob(pattern, path)匹配路径。
execute(command, timeout)运行一条 shell 命令。
upload_files(files)从 (path, bytes) 对写入原始字节。
download_files(paths)读取给定路径的原始字节。

每个方法都有一个以 a 为前缀的异步对应物,例如 aread、awrite 和 adownload_files。

参数和返回类型来自 Deep Agents 后端契约。参阅后端。

传输二进制文件

upload_files 和 download_files 传输原始字节,因此它们适合图像、归档,以及任何会被文本操作破坏的其他文件。Download 会为每个请求的路径返回字节:

python
import hashlib

from langchain.tools import tool
from managed_deepagents import ManagedDeepAgentRuntime

@tool(parse_docstring=True)
def checksum_file(file_path: str, runtime: ManagedDeepAgentRuntime) -> str:
    """Return the SHA-256 checksum of a sandbox file.

    Args:
        file_path: Absolute path inside the sandbox.
    """
    if runtime.backend is None:
        raise RuntimeError("checksum_file requires a sandbox")
    result = runtime.backend.download_files([file_path])[0]
    if result.error or result.content is None:
        raise RuntimeError(result.error or "file_not_found")
    return hashlib.sha256(result.content).hexdigest()

Upload 接受路径和内容对,每个文件一对:

python
uploaded = runtime.backend.upload_files([("/workspace/logo.png", payload)])
if uploaded[0].error:
    raise RuntimeError(uploaded[0].error)

每个结果都带有 path 和 error,而下载还带有 content。失败时,error 是 file_not_found、permission_denied、is_directory 或 invalid_path 之一,且下载的 content 为空。检查 error,而不是假定传输成功。

限制

runtime.backend 仅涵盖该沙箱。它没有到 Context Hub 的路由,因此技能、指令和记忆无法通过它访问。

没有沙箱时,runtime.backend 为 None。在每次调用之前对它做判空保护,因为一个项目可以在工具发布之后移除 sandbox/。

delete、upload_files 和 download_files 取决于所安装的后端,并在其未实现时会抛出。根 glob 会返回一个错误而非预配一个沙箱。

禁用沙箱

删除 sandbox/ 目录以选择退出,例如对于一个只需要其提示、记忆和工具的 agent。

对于现有部署,用 mda delete 删除部署也会删除与之关联的托管沙箱、{deployment}--setup-* 配方快照,以及在存在时的部署自有注册表。

部署

Managed Deep Agents 负责沙箱命名、配方烘焙、复用、恢复和清理。每个持久线程获得它自己的沙箱,从当前配方快照克隆而来。有关平台级的生命周期详情,参阅沙箱。

何时使用沙箱

目标使用
在隔离环境中写文件、运行代码或执行 shell 命令沙箱
跨线程存储持久知识记忆
无需文件系统的始终在线行为指令

更多信息请参阅项目结构。


BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。