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} | 默认禁用 |
| AioSandboxProvider | Docker 容器 | 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/双层防御:
LocalSandboxProvider的PathMapping在 acquire 时建立映射tools.py的replace_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/— 沙箱源码