DeerFlow 沙箱执行环境实现分析
DeerFlow的沙箱系统采用抽象接口+多实现的设计模式,提供两种执行模式:本地文件系统模式和Docker容器隔离模式,通过统一的接口对外提供服务。
Sandbox (接口) → 定义沙箱基本操作:execute_command、read_file、write_file、list_dir、update_fileSandboxProvider (接口) → 定义沙箱生命周期管理:acquire(获取)、get(查询)、release(释放)两种实现模式
Section titled “两种实现模式”1. 本地模式 (LocalSandbox)
Section titled “1. 本地模式 (LocalSandbox)”- 适用场景:开发环境、低安全要求场景
- 实现原理:
- 单例模式,所有线程共享同一个沙箱实例
- 通过路径映射机制实现逻辑隔离:
- 虚拟路径:Agent 看到的统一路径
/mnt/user-data/{workspace,uploads,outputs}、/mnt/skills - 实际路径:物理上存储在
backend/.deer-flow/threads/{thread_id}/user-data/...和项目根目录的skills/
- 虚拟路径:Agent 看到的统一路径
- 命令执行时自动转换路径:
- 输入:将命令中的虚拟路径替换为实际本地路径,优先匹配最长前缀避免歧义
- 输出:将执行结果中的本地路径替换回虚拟路径,对Agent完全透明
- Shell自动检测:优先使用zsh,其次bash,最后sh,保证跨平台兼容性
- 特点:轻量、无额外依赖、启动快,但隔离性较弱
2. Docker隔离模式 (AioSandbox)
Section titled “2. Docker隔离模式 (AioSandbox)”- 适用场景:生产环境、高安全要求场景
- 核心特性:
- 两种后端:
- 本地Docker后端:直接管理本地Docker容器生命周期
- 远程K8s后端:通过Provisioner服务动态创建K8s Pod作为沙箱
- 暖池机制:释放的沙箱容器不会立即销毁,放入暖池等待复用,避免冷启动开销
- 空闲超时管理:默认10分钟无活动自动销毁容器,节省资源
- 并发控制:默认最大3个并发沙箱容器,超过时采用LRU策略销毁最旧的暖池容器;并发限制为软限制,活跃沙箱不会被强制销毁
- 跨进程一致性:通过线程ID生成确定性沙箱ID,支持多进程/多Pod环境下的沙箱发现
- 跨进程锁机制:通过文件锁防止多个进程同时为同一个线程创建沙箱导致的冲突
- 两种后端:
- 安全特性:
- 每个线程独立容器,完全隔离,进程、文件系统、网络都互相隔离
- 工作目录、上传目录、输出目录独立挂载,每个线程只能访问自己的数据
- 技能目录只读挂载,防止Agent修改系统技能
- ACP工作区只读挂载,仅允许Agent读取ACP代理的执行结果
- 支持自定义环境变量和额外挂载配置
生命周期管理
Section titled “生命周期管理”沙箱的生命周期由SandboxMiddleware中间件统一管理:
- 会话开始时调用
provider.acquire(thread_id)获取沙箱 - 会话过程中通过
provider.get(sandbox_id)获取沙箱实例执行操作 - 会话结束时调用
provider.release(sandbox_id)释放沙箱(Docker模式下放入暖池)
沙箱功能被封装为统一的工具集提供给Agent使用:
bash:执行命令,自动处理路径转换和错误ls:目录列表,返回tree格式read_file:读取文件内容,支持行范围write_file:写入/追加文件,自动创建目录str_replace:字符串替换,支持批量替换
在config.yaml中通过sandbox.use字段指定沙箱实现:
# 本地模式sandbox: use: deerflow.sandbox.local.local_sandbox_provider:LocalSandboxProvider
# Docker模式sandbox: use: deerflow.community.aio_sandbox:AioSandboxProvider image: enterprise-public-cn-beijing.cr.volces.com/vefaas-public/all-in-one-sandbox:latest idle_timeout: 600 replicas: 3这种设计使得沙箱实现可插拔,未来可以轻松扩展支持其他隔离技术(如Kata Containers、WASM等)而不影响上层业务逻辑。