什么是Backend?

Backend是DeepAgents框架中的一个核心抽象,它定义了Agent如何与文件系统进行交互。通过Backend,Agent可以:

  • 列出文件和目录ls_info
  • 读取文件内容read
  • 写入新文件write
  • 搜索文件内容grep_raw
  • 通配符匹配文件glob_info
  • 编辑现有文件edit

Backend的核心价值在于安全性灵活性:它可以将Agent的文件操作限制在特定目录内,防止越权访问,同时支持多种存储介质(本地文件系统、内存、云存储等)。

回到顶部

Backend的使用场景

  1. 代码生成与编辑:让Agent在沙盒环境中编写和修改代码
  2. 数据分析:Agent读取、处理和生成数据文件
  3. 文档处理:自动化文档创建和内容更新
  4. 配置管理:动态生成和修改配置文件

回到顶部

DeepAgents支持的Backend类型

DeepAgents框架提供了多种Backend实现,满足不同场景的需求:

1. FilesystemBackend - 本地文件系统

  • 功能:直接操作本地磁盘文件
  • 特点:持久化存储,支持virtual_mode安全隔离
  • 适用:需要文件持久化、与其他系统共享文件的场景

2. LocalShellBackend - 本地Shell执行

  • 功能:文件操作 + 本地Shell命令执行
  • 特点:支持运行脚本、调用系统工具(git、docker等)
  • 适用:需要编译代码、运行脚本、执行复杂命令的场景

3. SandboxBackend - 远程沙箱环境

  • 功能:在隔离的沙箱环境中执行命令和操作文件
  • 特点:完全隔离的执行环境,支持云端沙箱(如OpenSandbox、Daytona)
  • 子类实现
    • OpenSandboxBackend:基于OpenSandbox的开源沙箱方案
    • DaytonaBackend:基于Daytona的云沙箱方案
  • 适用:需要高安全性隔离、运行不可信代码、云端执行场景

4. 自定义Backend - 完全灵活

  • 功能:通过实现BackendProtocol接口自定义存储逻辑
  • 特点:可以对接任何存储介质(内存、数据库、云存储等)
  • 示例DictBackend(内存存储)、RedisBackend(Redis存储)等
  • 适用:特殊需求、测试环境、自定义存储逻辑

Backend类型对比

Backend类型 文件操作 命令执行 持久化 安全隔离 典型场景
FilesystemBackend 中等(virtual_mode) 本地文件处理
LocalShellBackend ✅(本地) 中等(virtual_mode) 本地脚本执行
SandboxBackend ✅(沙箱) 可选 高(完全隔离) 云端安全执行
自定义Backend 自定义 自定义 自定义 自定义 特殊需求

回到顶部

四个渐进式示例

示例一:无Backend的基础Agent

最简单的Agent配置不使用Backend,仅依赖工具调用完成任务:

from deepagents import create_deep_agent
from langgraph.checkpoint.memory import InMemorySaver

# 创建内存检查点保存器
checkpointer = InMemorySaver()

# 创建基础Agent
agent = create_deep_agent(
    model=llm,
    tools=[web_search],
    #checkpointer=checkpointer,
    system_prompt='你是一个助手,请根据用户输入的指令,进行相应的操作。'
)

特点

  • 适合仅需调用外部API(如Web搜索)的场景
  • 无法进行文件操作
  • 配置简单,启动快速

示例二:FilesystemBackend - 文件系统沙盒

当需要Agent操作文件时,FilesystemBackend是最常用的选择:

import os
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from langgraph.checkpoint.memory import InMemorySaver

checkpointer = InMemorySaver()

# 创建Agent工作目录
temp_workspace = "./agent_workspace"
os.makedirs(temp_workspace, exist_ok=True)

agent = create_deep_agent(
    model=llm,
    tools=[web_search],
    checkpointer=checkpointer,
    backend=FilesystemBackend(
        root_dir=temp_workspace,
        virtual_mode=True,  # 防止Agent通过`../../`跳出根目录
    ),
    system_prompt='你是一个助手,请根据用户输入的指令,进行相应的操作。'
)

关键参数

  • root_dir:指定Agent的工作根目录
  • virtual_mode=True:启用虚拟模式,防止路径穿越攻击(如../../etc/passwd

适用场景

  • 需要持久化存储文件
  • Agent生成的文件需要在磁盘上保留
  • 需要与其他系统共享文件

示例三:LocalShellBackend - 支持命令执行

如果Agent不仅需要操作文件,还需要执行shell命令,LocalShellBackend是更好的选择:

import os
import sys
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend, LocalShellBackend
from langgraph.checkpoint.memory import InMemorySaver

checkpointer = InMemorySaver()

temp_workspace = "./agent_workspace"
os.makedirs(temp_workspace, exist_ok=True)

agent = create_deep_agent(
    model=llm,
    tools=[web_search],
    checkpointer=checkpointer,
    backend=LocalShellBackend(
        root_dir=temp_workspace,
        virtual_mode=True,
        timeout=30,  # 命令执行超时时间(秒)
        max_output_bytes=50000,  # 命令输出最大字节数
        env={
            "PATH": f"{os.path.dirname(sys.executable)};{os.environ.get('PATH', '')}",
        },
    ),
    system_prompt='你是一个助手,请根据用户输入的指令,进行相应的操作。'
)

新增功能

  • 支持执行shell命令(如python script.pyls -la
  • 可配置超时时间和输出限制,防止恶意或低效命令
  • 自定义环境变量,确保命令在正确的环境中执行

适用场景

  • 需要运行脚本或编译代码
  • 需要调用系统工具(如git、docker)
  • 需要执行复杂的数据处理管道

示例四:自定义Backend - DictBackend

DeepAgents的强大之处在于其可扩展性。通过实现BackendProtocol接口,我们可以创建完全自定义的Backend:

from deepagents.backends.protocol import BackendProtocol, WriteResult, EditResult
from deepagents.backends.utils import FileInfo, GrepMatch
from datetime import datetime
import re

class DictBackend(BackendProtocol):
    """将文件存储在内存字典中的自定义后端"""
    
    def __init__(self):
        self.files = {}  # 路径 -> 内容
        self.metadata = {}  # 路径 -> 元数据
    
    def ls_info(self, path: str) -> list[FileInfo]:
        """列出文件和目录信息"""
        result = []
        seen_dirs = set()
        for file_path in self.files.keys():
            if file_path.startswith(path):
                remaining = file_path[len(path):]
                if '/' in remaining:
                    dir_name = path + remaining.split('/')[0] + '/'
                    if dir_name not in seen_dirs:
                        seen_dirs.add(dir_name)
                        result.append(FileInfo(path=dir_name, is_dir=True))
                else:
                    meta = self.metadata.get(file_path, {})
                    result.append(FileInfo(
                        path=file_path,
                        is_dir=False,
                        size=meta.get('size', 0),
                        modified_at=meta.get('modified_at')
                    ))
        return result
    
    def read(self, file_path: str, offset: int = 0, limit: int = 2000) -> str:
        """读取文件内容,支持分页"""
        if file_path not in self.files:
            return f"Error: File '{file_path}' not found"
        content = self.files[file_path]
        lines = content.splitlines(keepends=True)
        start_line = offset
        end_line = start_line + limit if limit > 0 else len(lines)
        selected_lines = lines[start_line:end_line]
        result = ''.join(f"{start_line + i + 1}: {line}" for i, line in enumerate(selected_lines))
        return result if result else "(end of file)"
    
    def write(self, file_path: str, content: str) -> WriteResult:
        """写入新文件(仅创建,不覆盖)"""
        if file_path in self.files:
            return WriteResult(error=f"File '{file_path}' already exists (create-only).")
        self.files[file_path] = content
        self.metadata[file_path] = {
            'size': len(content),
            'modified_at': datetime.now().isoformat()
        }
        return WriteResult(path=file_path, files_update=None)
    
    def grep_raw(self, pattern: str, path: str | None = None, glob: str | None = None) -> list[GrepMatch] | str:
        """正则表达式搜索文件内容"""
        try:
            re.compile(pattern)
        except re.error as e:
            return f"Invalid regex pattern: {e}"
        matches = []
        for file_path, content in self.files.items():
            for i, line in enumerate(content.splitlines()):
                if re.search(pattern, line):
                    matches.append(GrepMatch(path=file_path, line=i+1, text=line))
        return matches
    
    def glob_info(self, pattern: str, path: str = "/") -> list[FileInfo]:
        """通配符匹配文件"""
        import fnmatch
        all_files = [
            FileInfo(path=p, is_dir=False, size=self.metadata[p]['size'], 
                    modified_at=self.metadata[p]['modified_at']) 
            for p in self.files.keys() if p.startswith(path)
        ]
        matched = [fi for fi in all_files if fnmatch.fnmatch(fi.path, path.rstrip('/') + '/' + pattern)]
        return matched
    
    def edit(self, file_path: str, old_string: str, new_string: str, replace_all: bool = False) -> EditResult:
        """编辑文件内容"""
        if file_path not in self.files:
            return EditResult(error=f"File '{file_path}' not found")
        content = self.files[file_path]
        if replace_all:
            new_content = content.replace(old_string, new_string)
            occurrences = content.count(old_string)
        else:
            if content.count(old_string) != 1:
                return EditResult(error=f"Found {content.count(old_string)} occurrences. For safety, edit requires exactly one match unless replace_all=True.")
            new_content = content.replace(old_string, new_string, 1)
            occurrences = 1
        if new_content == content:
            return EditResult(error=f"String '{old_string}' not found.")
        self.files[file_path] = new_content
        self.metadata[file_path]['size'] = len(new_content)
        self.metadata[file_path]['modified_at'] = datetime.now().isoformat()
        return EditResult(path=file_path, files_update=None, occurrences=occurrences)

使用自定义Backend

from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend, LocalShellBackend
from langgraph.checkpoint.memory import InMemorySaver

from my_backend import DictBackend

checkpointer = InMemorySaver()

agent = create_deep_agent(
    model=llm,
    tools=[web_search],
    checkpointer=checkpointer,
    backend=DictBackend(),
    system_prompt='你是一个助手,请根据用户输入的指令,进行相应的操作。'
)

自定义Backend的优势

  • 完全控制:可以定义任何存储逻辑(数据库、云存储、加密存储等)
  • 安全隔离:Agent操作完全在内存中,不影响真实文件系统
  • 可测试性:便于单元测试和调试
  • 性能优化:针对特定场景优化读写性能

回到顶部

Backend的选择指南

场景 推荐Backend 原因
仅需API调用,无需文件操作 无Backend 简单高效
需要持久化文件存储 FilesystemBackend 直接操作磁盘文件
需要执行shell命令 LocalShellBackend 支持命令执行+文件操作
需要完全隔离或自定义存储 自定义Backend 灵活可控,适合特殊需求

回到顶部

最佳实践

  1. 始终启用virtual_mode:防止路径穿越攻击,确保Agent在沙盒内操作
  2. 设置合理的超时和限制:避免恶意或低效命令消耗过多资源
  3. 使用checkpointer保存状态:支持对话历史恢复和断点续传
  4. 自定义Backend时实现完整接口:确保所有方法都正确实现,避免运行时错误
  5. 记录Backend操作日志:便于调试和审计Agent行为
Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐