跳转到内容

Deer-Flow 的沙箱执行与虚拟路径系统

Deer-Flow 的沙箱执行与虚拟路径系统

学习目标

  • 理解 Deer-Flow 的 Sandbox Provider 接口和生命周期
  • 掌握虚拟路径翻译机制和双层防御
  • 学会配置 Local、Docker、Kubernetes 三种沙箱模式

前置知识

本章涉及沙箱执行的通用原理,建议先阅读:

下文假设你已理解上述概念,直接聚焦 Deer-Flow 的具体实现。


项目实践

Sandbox 抽象接口

Deer-Flow 定义了统一的 Sandbox 抽象接口:

  • execute_command:执行 shell 命令
  • read_file:读取文件内容
  • write_file:写入文件
  • list_dir:目录列表

所有操作通过 SandboxProvider.acquire(thread_id) 获取沙箱实例,完成后 release

两种 Provider 实现

Provider隔离方式沙箱 ID 格式Bash 支持
LocalSandboxProvider目录隔离local:{thread_id}默认禁用
AioSandboxProviderDocker 容器docker:{container_id}启用

LocalSandboxProvider

  • 使用 LRU 缓存(默认 256 条目)管理 per-thread 沙箱实例
  • threading.Lock 保护并发访问
  • 每线程目录:backend/.deer-flow/users/{user_id}/threads/{thread_id}/user-data/{workspace,uploads,outputs}
  • Host bash 默认禁用,因为目录隔离不是安全边界

AioSandboxProvider

  • Docker 容器级别的隔离
  • Shell 命令在容器内执行
  • 支持 Kubernetes provisioner 模式(通过 provisioner_url 配置)
  • 异步沙箱生命周期(创建、发现、跨进程锁、就绪轮询、释放)

虚拟路径系统

Agent 看到的是虚拟路径,而非物理路径:

Agent 视角 → 物理路径
/mnt/user-data/workspace/ → backend/.deer-flow/users/{uid}/threads/{tid}/user-data/workspace/
/mnt/user-data/uploads/ → backend/.deer-flow/users/{uid}/threads/{tid}/user-data/uploads/
/mnt/user-data/outputs/ → backend/.deer-flow/users/{uid}/threads/{tid}/user-data/outputs/
/mnt/skills/public/ → deer-flow/skills/public/

双层防御

  1. LocalSandboxProviderPathMapping 在 acquire 时建立映射
  2. tools.pyreplace_virtual_path() 作为防御性路径验证层

AIO 容器通过 volume mount 将相同虚拟路径挂载到容器内,所以两种实现统一接受 /mnt/user-data/... 路径。


问题与规避

Local 模式的安全风险

Local 沙箱仅有目录隔离,Agent 的 bash 命令可以操作宿主机。

Deer-Flow 的规避:Local 模式默认禁用 bash,仅启用文件读写工具。如需启用,必须在配置中显式开启。

沙箱配置热重载的限制

sandbox.use 字段(Provider 类路径)在进程启动时缓存为单例,修改后需要重启才能生效。


设计取舍

统一虚拟路径 vs 物理路径直露

Deer-Flow 选择:统一虚拟路径。

理由:Agent 代码和系统提示中不暴露宿主机的目录结构,提高了可移植性和安全性。


参考来源

  • Deer-Flow CLAUDE.md — Sandbox System 章节
  • packages/harness/deerflow/sandbox/ — 沙箱源码