Skip to content

DeerFlow 沙箱执行环境实现分析

DeerFlow的沙箱系统采用抽象接口+多实现的设计模式,提供两种执行模式:本地文件系统模式和Docker容器隔离模式,通过统一的接口对外提供服务。

Sandbox (接口) → 定义沙箱基本操作:execute_command、read_file、write_file、list_dir、update_file
SandboxProvider (接口) → 定义沙箱生命周期管理:acquire(获取)、get(查询)、release(释放)
  • 适用场景:开发环境、低安全要求场景
  • 实现原理
    • 单例模式,所有线程共享同一个沙箱实例
    • 通过路径映射机制实现逻辑隔离:
      • 虚拟路径:Agent 看到的统一路径 /mnt/user-data/{workspace,uploads,outputs}/mnt/skills
      • 实际路径:物理上存储在 backend/.deer-flow/threads/{thread_id}/user-data/... 和项目根目录的 skills/
    • 命令执行时自动转换路径:
      • 输入:将命令中的虚拟路径替换为实际本地路径,优先匹配最长前缀避免歧义
      • 输出:将执行结果中的本地路径替换回虚拟路径,对Agent完全透明
    • Shell自动检测:优先使用zsh,其次bash,最后sh,保证跨平台兼容性
  • 特点:轻量、无额外依赖、启动快,但隔离性较弱
  • 适用场景:生产环境、高安全要求场景
  • 核心特性
    • 两种后端
      • 本地Docker后端:直接管理本地Docker容器生命周期
      • 远程K8s后端:通过Provisioner服务动态创建K8s Pod作为沙箱
    • 暖池机制:释放的沙箱容器不会立即销毁,放入暖池等待复用,避免冷启动开销
    • 空闲超时管理:默认10分钟无活动自动销毁容器,节省资源
    • 并发控制:默认最大3个并发沙箱容器,超过时采用LRU策略销毁最旧的暖池容器;并发限制为软限制,活跃沙箱不会被强制销毁
    • 跨进程一致性:通过线程ID生成确定性沙箱ID,支持多进程/多Pod环境下的沙箱发现
    • 跨进程锁机制:通过文件锁防止多个进程同时为同一个线程创建沙箱导致的冲突
  • 安全特性
    • 每个线程独立容器,完全隔离,进程、文件系统、网络都互相隔离
    • 工作目录、上传目录、输出目录独立挂载,每个线程只能访问自己的数据
    • 技能目录只读挂载,防止Agent修改系统技能
    • ACP工作区只读挂载,仅允许Agent读取ACP代理的执行结果
    • 支持自定义环境变量和额外挂载配置

沙箱的生命周期由SandboxMiddleware中间件统一管理:

  1. 会话开始时调用provider.acquire(thread_id)获取沙箱
  2. 会话过程中通过provider.get(sandbox_id)获取沙箱实例执行操作
  3. 会话结束时调用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等)而不影响上层业务逻辑。