前面几篇文章介绍了 Deep Agents 的 Planning、Tools、Filesystem 和 Backend。通过这些机制,Agent 已经能够规划任务、管理文件,并在多个步骤之间维护工作状态。

但对于 Coding Agent、数据分析 Agent 等应用,仅有这些能力还不够。Agent 不仅需要编写代码,还需要实际运行程序、执行测试,并根据结果继续工作。

Deep Agents 通过 Shell、execute 和 Sandbox 支持这类能力。

这三个概念分别对应命令执行机制、框架调用接口和实际运行环境。理解它们之间的关系,是构建具备自主执行能力的 Agent 的重要基础。

一、工具调用的能力边界

在普通 Agent 中,执行能力通常来自预先定义好的 Tools。

例如,我们可以定义一个 calculate() 工具,让 Agent 完成计算;或者定义一个 query_database() 工具,让它查询数据库。

这种方式有一个明显特点:Agent 能做什么,取决于我们提前提供了哪些工具。

假设需要完成下面的任务:

读取一个 CSV 文件,统计各月份的销售额,找出增长最快的月份,并生成分析报告。

为此,可能需要提供 CSV 解析、数据过滤、统计计算和报告生成等多个工具。

如果后续增加其他相关功能或更复杂的功能,还需要提供其他工具。

另一种方式是让 Agent 自行编写 Python 脚本,通过运行环境执行代码,再读取执行结果。

这样,Agent 不必依赖大量针对具体业务编写的工具。只要运行环境具备相应能力,就可以组合已有的程序、库和命令完成任务。

这也是 Shell 对 Deep Agents 的主要价值。

不过,Shell 并不会替代所有 Tools。两者解决的是不同类型的问题。

对于数据库写入、支付、订单操作等业务行为,显式定义的工具通常更容易控制参数、权限以及安全验证。

Shell 更适合代码执行、文件处理、自动化测试,以及需要结合操作系统工具的任务。

二、文件操作与命令执行

前一篇介绍 Backend 时,已经区分了 StateBackend、FilesystemBackend 等不同实现。

这里需要进一步明确:文件可读写,并不意味着命令可以执行。

Deep Agents 默认使用 StateBackend。它可以为 Agent 提供文件管理能力,但不会因此获得操作系统的 Shell。

FilesystemBackend 可以操作真实文件,同样不提供通用命令执行能力。

例如,Agent 可以通过 write_file 创建一个 analysis.py 文件,但不能仅凭文件操作工具运行:

代码片段Bash
python analysis.py

要完成这一步,Backend 还需要支持命令执行接口。

Deep Agents 的 Backend 类型

Deep Agents 通过统一的 Backend 接口支持不同的存储和执行环境,主要区别在于文件存储方式及是否支持命令执行。

Backend主要特点Shell 执行
StateBackend默认实现,文件保存在 Agent State 中否
FilesystemBackend读写本地真实文件否
StoreBackend基于 LangGraph Store,支持跨线程存储否
ContextHubBackend基于 LangSmith Context Hub,支持版本化管理否
CompositeBackend按路径组合、路由不同 Backend取决于默认 Backend
LocalShellBackend本地文件操作与命令执行,无系统隔离是
LangSmithSandboxLangSmith 托管的隔离执行环境是
第三方 Sandbox BackendE2B、Daytona、Modal、Vercel 等执行环境是

其中,StateBackend、FilesystemBackend 和 StoreBackend 主要解决文件存储问题;LocalShellBackend 和 Sandbox Backend 则进一步提供 Shell 执行能力。

CompositeBackend 比较特殊:文件操作按路径路由,而命令执行始终交给默认 Backend。

需要注意,Backend 支持命令执行,不代表具备安全隔离。 LocalShellBackend 直接运行本地命令,而 Sandbox Backend 通常依赖独立的隔离环境。

Shell、Execute 与 Sandbox

这三个概念容易混淆,但职责不同。

可以把它们理解为:execute 是命令入口,Shell 是命令执行器,Sandbox 是运行命令的工作环境。

例如,Agent 需要运行脚本:

代码片段Bash
python analysis.py

Agent 并不直接执行这条命令,而是调用 execute 工具。框架通过 Backend 将命令交给 Shell,由 Shell 启动 Python 进程,并将执行结果返回给 Agent。

整个过程如下:

代码片段Text
Agent
  │
  ▼
execute(提交命令)
  │
  ▼
Backend(转发命令)
  │
  ▼
Shell(执行命令)
  │
  ▼
返回输出与退出码

Sandbox 决定这条命令在哪里运行,以及受到哪些隔离限制。例如,使用 LocalShellBackend 时,命令直接在本机执行;使用远程 Sandbox Backend 时,命令则在隔离的远程环境中执行。

三、执行接口的内部机制

Deep Agents 使用 SandboxBackendProtocol 描述支持命令执行的 Backend。

这个协议扩展了基础文件操作协议 BackendProtocol,增加了 execute()、aexecute() 等命令执行接口。

其核心调用形式如下:

代码片段Python
result = backend.execute(
    "python analysis.py",
    timeout=60,
)
 
print(result.output)
print(result.exit_code)
print(result.truncated)

这里展示的是应用程序直接调用 Backend 的方式。Agent 通过 execute 工具执行命令时,也会使用相应的 Backend 接口。

返回结果中有三个重要信息。

  • output:命令执行的输出,包含标准输出和错误输出。
  • exit_code:进程退出码。
  • truncated:输出内容是否经过截断。

通常,退出码为 0 表示进程正常完成,非零值表示出现错误。不过,进程正常退出并不等于结果一定正确。

例如,Python 脚本可能成功执行,但由于计算逻辑错误,生成了不准确的数据。

另外,不能简单地用工具消息的成功状态判断命令是否成功。即使 Shell 进程返回非零退出码,工具调用本身也可能正常完成,并将错误信息交还给 Agent。

真正判断命令执行结果时,应检查 exit_code。

Deep Agents 的 FilesystemMiddleware 负责向模型提供文件操作工具,并根据 Backend 的能力决定是否提供可用的 execute。

对于实现了 SandboxBackendProtocol 的 Backend,Agent 可以通过 execute 运行命令;不支持该协议的 Backend 则无法执行 Shell 命令。

也就是说,execute 并不是所有 Deep Agent 默认拥有的能力。

本地命令执行

Deep Agents 内置了 LocalShellBackend,适合在受控开发环境中使用。

代码片段Python
from pathlib import Path
 
from deepagents import create_deep_agent
from deepagents.backends import LocalShellBackend
 
backend = LocalShellBackend(
    root_dir=Path("./workspace").resolve(),
    virtual_mode=True,
    timeout=60,
)
 
agent = create_deep_agent(
    model="openai:gpt-5.5",
    backend=backend,
)

配置完成后,Agent 就可以通过 execute 调用本地 Shell。

LocalShellBackend 继承自 FilesystemBackend,同时实现 SandboxBackendProtocol,因此兼具文件操作和命令执行能力。

但这里有一个必须明确的细节。

root_dir 是文件操作的根目录,也是 Shell 命令的工作目录。virtual_mode=True 主要约束文件工具的路径解析,并不能限制 Shell 访问工作目录以外的文件。

LocalShellBackend 实际通过本地进程执行命令,不提供真正的系统隔离。

因此,它适合可信、受控的个人开发环境,不适合直接用于公开的多用户应用。

四、隔离工作空间的结构

真正需要自主执行代码的 Agent,通常应该使用 Sandbox。

Sandbox 可以理解为一个独立的运行工作空间,内部具备文件系统、进程环境和必要的软件依赖。

Agent 在其中创建文件、安装依赖、执行命令或生成结果,而不需要直接操作宿主机的工作环境。

从运行结构来看,可以将其划分为四层:

代码片段Text
用户任务
   │
   ▼
Deep Agent
   │ 规划任务、调用工具
   ▼
FilesystemMiddleware
   │ read_file / write_file / execute
   ▼
Sandbox Backend
   │ 文件接口、命令执行接口
   ▼
Sandbox Runtime
   │
   ├── Filesystem
   ├── Shell / Processes
   ├── Python / Node.js
   ├── Dependencies
   └── Generated Artifacts

这里的 Sandbox Runtime 是真正运行程序的地方。

例如,Agent 决定运行 pytest,框架将命令传给 Sandbox Backend,后者通过运行环境执行测试,再把输出和退出码返回给 Agent。

Agent 根据测试结果判断是否需要继续修改代码。

需要注意,Sandbox 不一定由 Deep Agents 自身创建。

它可以由 Docker、虚拟机或云端执行平台提供。Deep Agents 通过对应的 Backend 接入执行环境。

不同运行方式的区别主要在于执行位置及隔离边界。

运行方式命令执行位置隔离能力
本机 LocalShellBackend本地操作系统无系统级隔离
Docker 内的 LocalShellBackendDocker 容器内部容器级隔离
远程 Sandbox Backend远程 Sandbox取决于服务提供方的隔离实现

这里的 Docker 方案,是将 Agent 程序和 LocalShellBackend 一起放入容器运行,并不是让本机 Agent 自动获得一个远程 Sandbox Backend。

五、实际任务示例

下面通过一个简单的数据分析任务,串联整个过程。

目标是让 Agent 读取销售数据,编写 Python 脚本完成计算,执行脚本,并生成 Markdown 报告。

为了降低复现成本,这里使用 LocalShellBackend,不依赖额外的云端 Sandbox 服务。

准备运行环境

首先安装依赖:

代码片段Bash
pip install -U deepagents langchain-openai

配置 OPENAI_API_KEY 环境变量,并确保本地可以通过 python 命令运行 Python。

本例使用 Python 标准库处理 CSV,不需要安装 Pandas 等数据分析库。

特别说明:下面示例仅用于可信、受控的开发环境。运行前应确认程序所在机器没有不应被 Agent 访问的敏感文件或权限。

创建执行工作空间

首先准备一个工作目录,将测试数据写入其中。

代码片段Python
from pathlib import Path
import os
 
from deepagents import create_deep_agent
from deepagents.backends import LocalShellBackend
 
workspace = Path("./workspace").resolve()
workspace.mkdir(parents=True, exist_ok=True)
 
# 写入测试数据
(workspace / "sales.csv").write_text(
    "date,amount\n"
    "2026-10-01,100\n"
    "2026-10-02,120\n"
    "2026-10-03,90\n"
    "2026-10-04,150\n",
    encoding="utf-8",
)
 
backend = LocalShellBackend(
    root_dir=workspace,
    virtual_mode=True,
    timeout=60,
    env={"PATH": os.environ.get("PATH", "")},
)

这里有两个细节值得注意。

第一个是 virtual_mode=True。

启用虚拟路径后,Agent 通过 read_file 访问 /sales.csv,实际对应的是本地 workspace/sales.csv 文件。

第二个是 Shell 的工作目录。

execute 调用的 Shell 会以 workspace 作为当前工作目录。因此,执行脚本时使用:

代码片段Bash
python analysis.py

而不是:

代码片段Bash
python /analysis.py

因为文件工具的虚拟路径与操作系统的真实路径并不是同一个概念。

此外,env 显式指定了传递给 Shell 的环境变量。LocalShellBackend 默认不会继承父进程的全部环境变量,这有助于减少直接暴露给子进程的配置,但不能作为完整的安全隔离措施。

创建并运行 Agent

接下来,将 Backend 传入 create_deep_agent()。

代码片段Python
agent = create_deep_agent(
    model="openai:gpt-5.5",
    backend=backend,
    system_prompt=(
        "你是一名 Python 数据分析工程师。"
        "使用工作空间中的文件完成任务。"
        "文件操作工具使用 / 开头的虚拟路径。"
        "Shell 命令在工作空间目录中执行。"
        "请先读取 /sales.csv,"
        "再编写 /analysis.py,"
        "使用 python analysis.py 执行计算。"
        "仅使用 Python 标准库。"
        "最终报告保存为 /report.md。"
        "必须根据实际执行结果生成报告。"
        "不得将未经运行验证的结果描述为已验证。"
    ),
)
 
result = agent.invoke(
    {
        "messages": [{
            "role": "user",
            "content": (
                "分析 sales.csv 中的销售数据。"
                "计算总销售额、日均销售额和最高单日销售额。"
                "生成 Python 脚本并实际运行。"
                "检查执行结果后生成 Markdown 报告。"
            ),
        }]
    },
    config={"recursion_limit": 40},
)
 
print(result["messages"][-1].content)

在这个示例中,Agent 可以自主决定如何组织 Python 代码,以及何时调用 execute。

典型的执行过程如下:

代码片段Text
读取 /sales.csv
       │
       ▼
生成 /analysis.py
       │
       ▼
execute("python analysis.py")
       │
       ▼
获取 output / exit_code
       │
       ▼
检查计算结果
       │
       ▼
生成 /report.md

对于给定数据,正确的计算结果应为:

指标结果
总销售额460
日均销售额115
最高单日销售额150

这些数值来自输入数据的直接计算。实际 Agent 是否完成对应步骤,需要以执行记录和生成的文件为准。

检查执行产物

由于使用的是本地工作空间,应用程序不需要通过 download_files() 下载结果。

我们可以直接读取生成的文件。

继续在上面的代码后添加:

代码片段Python
script_path = workspace / "analysis.py"
report_path = workspace / "report.md"
 
if not script_path.is_file():
    raise RuntimeError("Agent 未生成分析脚本")
 
if not report_path.is_file():
    raise RuntimeError("Agent 未生成分析报告")
 
# 再次执行脚本
check = backend.execute(
    "python analysis.py",
    timeout=60,
)
 
print("exit_code:", check.exit_code)
print("output:", check.output)
 
if check.exit_code != 0:
    raise RuntimeError("分析脚本执行失败")
 
print(report_path.read_text(encoding="utf-8"))

这里增加了一次由应用程序主动发起的命令执行。

Agent 在执行过程中可以调用 execute,应用程序也可以直接调用 backend.execute()。

两者使用同一个 Backend,但调用主体不同。

Agent 的工具调用是模型自主决策的一部分;应用程序直接调用 Backend,则可以用于执行确定性的验证逻辑,不需要模型再次参与。

到这里,一个基本的数据分析 Agent 就已经可以运行。

它不仅能读取数据和编写代码,还可以实际执行程序,再根据执行结果生成报告。

文件与执行环境的关系

通过这个例子,还可以看到两个容易忽略的设计细节。

第一个是文件操作与命令执行需要使用同一工作空间。

Agent 使用 write_file 生成脚本,随后通过 execute 执行。如果两个接口指向不同的环境,就可能出现文件已经创建,但命令无法找到文件的问题。

第二个是任务完成不等于产物已经持久化。

在本地示例中,报告保存在 workspace/report.md。

在 Docker 中,使用 Bind Mount 或 Volume 可以让文件在容器删除后继续保留。

而对于远程 Sandbox,通常需要通过文件传输接口或外部对象存储,将产物保存到业务系统中。

这些方式虽然不同,但 Deep Agents 面向 Agent 的文件操作和命令执行接口保持相对统一。

这正是 Backend 抽象的重要价值:Agent 不需要关心底层具体使用哪种运行环境,只需要围绕文件、命令和执行反馈完成任务。

六、执行结果的可靠判断

Shell 能让 Agent 执行代码,但命令运行成功不代表任务完成。

实际开发中,应关注三个方面:

  1. 执行验证:不能只依赖 Agent 的最终回答,还应检查 exit_code、错误输出和生成的文件。对于关键任务,需要通过独立测试或断言验证结果。

  2. 错误处理:Agent 应根据执行反馈修正问题,而不是盲目重试。例如,依赖缺失需要调整环境,测试失败则需要检查代码逻辑。

  3. 输出控制:构建和测试日志可能占用大量 Token。LocalShellBackend 可通过 max_output_bytes 限制输出大小,也可以将完整日志保存到文件,让 Agent 按需读取。

核心原则是:以实际执行结果验证任务完成情况,同时控制反馈进入模型上下文的成本。

七、工程实践的设计取舍

并不是所有 Agent 都需要 Shell。

对于固定 API 调用、数据库操作和结构化业务流程,明确定义的 Tools 更容易维护和控制。

而运行测试、构建项目、执行脚本等任务,则更适合使用 Shell,减少对专用工具的依赖。

在实际部署中,我们还需关注三个边界。

权限边界:Sandbox 应遵循最小权限原则,避免直接访问宿主机凭据、生产数据库和内部网络,敏感密钥应按需授权。

资源边界:除了命令超时,还应限制 CPU、内存、磁盘和网络资源,防止异常任务影响系统稳定性。

操作边界:删除文件、访问外部服务、发布代码等高风险操作,可以引入 Human-in-the-loop 审批,但审批不能代替环境隔离。

从架构上看,Deep Agents 通过 Backend 将文件操作与命令执行整合到同一工作空间,使 Agent 能够连续完成文件生成、代码执行、结果检查和后续修正。