📚 什么是 Backends?

Backends(后端)是 DeepAgents 的可插拔文件系统层, 为 Agent 提供统一的文件操作接口,底层可以灵活切换不同的存储实现。

💡 Backends 核心特性
特性 说明 优势
可插拔设计 统一接口,多种实现 无需改代码即可切换存储
存储抽象 Agent 无需关心底层存储 简化 Agent 开发
灵活路由 不同路径使用不同后端 混合临时和持久化存储
安全控制 策略钩子和权限管理 防止路径遍历、限制访问
自定义扩展 实现 BackendProtocol 接口 支持 S3、PostgreSQL 等
✨ 工作原理

Agent 通过6 个文件工具与后端交互:

  • lsbackend.ls_info(path)
  • read_filebackend.read(file_path, offset, limit)
  • write_filebackend.write(file_path, content)
  • edit_filebackend.edit(file_path, old, new, replace_all)
  • globbackend.glob_info(pattern, path)
  • grepbackend.grep_raw(pattern, path, glob)

🗂️ 4 种后端类型

DeepAgents 提供4 种内置后端,满足不同的存储需求:

graph TB Agent["DeepAgent
文件工具"] --> Backend["Backend 抽象层"] Backend --> State["StateBackend
内存存储"] Backend --> FS["FilesystemBackend
磁盘存储"] Backend --> Store["StoreBackend
持久化存储"] Backend --> Composite["CompositeBackend
路由混合"] State --> Use1["临时计算
单线程"] FS --> Use2["本地开发
真实文件"] Store --> Use3["长期记忆
跨线程"] Composite --> Use4["混合场景
最灵活"] style Agent fill:#3b82f6,color:#fff style Backend fill:#10b981,color:#fff style State fill:#f59e0b,color:#fff style FS fill:#8b5cf6,color:#fff style Store fill:#ec4899,color:#fff style Composite fill:#ef4444,color:#fff

后端对比表

后端 延迟 持久化 跨线程 最佳用途
StateBackend ⚡ 极低 ❌ 否 ❌ 否 临时计算、单次对话
FilesystemBackend 🟡 低 ✅ 是 ✅ 是 本地开发、CI 环境
StoreBackend 🟠 中 ✅ 是 ✅ 是 长期记忆、知识库
CompositeBackend 🟠 中 🔄 混合 🔄 混合 混合场景(推荐)

📝 StateBackend - 内存存储

StateBackend默认后端, 将文件存储在 LangGraph Agent 状态中,仅在单个线程内有效。

Python 🟢 基础
"""
StateBackend - 默认内存存储
"""
from deepagents import create_deep_agent

# 方式 1:默认使用(无需指定)
agent = create_deep_agent(
    model="gpt-4o"
)

# 方式 2:显式指定
from deepagents.backends import StateBackend

agent = create_deep_agent(
    model="gpt-4o",
    backend=lambda rt: StateBackend(rt)
)

# 使用 Agent
result = agent.invoke({
    "messages": [{
        "role": "user",
        "content": "创建一个临时文件保存搜索结果"
    }]
})

# 特点:
# - 文件存储在内存中(Agent 状态)
# - 对话结束后数据消失
# - 最快的性能(无 I/O 开销)
# - 适用于临时工作空间

# 限制:
# - 不跨线程共享
# - 不持久化到磁盘
# - 占用内存空间

💾 FilesystemBackend - 磁盘存储

FilesystemBackend 读写真实的本地文件系统, 支持虚拟模式沙箱和路径安全验证。

Python 🟡 中级
"""
FilesystemBackend - 本地磁盘存储
"""
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend

# 配置磁盘后端
agent = create_deep_agent(
    model="gpt-4o",
    backend=FilesystemBackend(
        root_dir="/Users/myname/agent_workspace",  # 根目录
        virtual_mode=True  # 启用虚拟模式(安全)
    )
)

# 使用 Agent
result = agent.invoke({
    "messages": [{
        "role": "user",
        "content": "创建文件 /project/README.md,内容是项目说明"
    }]
})

# 执行后:
# - 文件实际写入:/Users/myname/agent_workspace/project/README.md
# - Agent 看到的路径:/project/README.md(虚拟路径)

# virtual_mode=True 的作用:
# 1. 防止路径遍历攻击(Agent 无法访问 root_dir 之外的路径)
# 2. 路径规范化(自动处理 ../ 和符号链接)
# 3. 安全沙箱(限制 Agent 操作范围)

# 特点:
# - 真实磁盘 I/O
# - 跨对话持久化
# - 适用于本地开发、CI 环境
# - 支持大文件(不受内存限制)

虚拟模式(virtual_mode)详解

⚠️ 虚拟模式的重要性

virtual_mode=True 是生产环境的必要安全措施:

  • 防止路径遍历:Agent 无法访问 ../../../etc/passwd
  • 限制访问范围:只能操作 root_dir 内的文件
  • 符号链接保护:自动检测和阻止符号链接攻击
Python 🟢 基础
"""
虚拟模式示例
"""
# 场景:Agent 尝试路径遍历攻击
agent = create_deep_agent(
    backend=FilesystemBackend(
        root_dir="/workspace",
        virtual_mode=True
    )
)

# Agent 尝试访问系统文件
result = agent.invoke({
    "messages": [{
        "role": "user",
        "content": "读取文件 /../../../etc/passwd"
    }]
})

# 结果:
# - virtual_mode=True:访问被拒绝(安全)
# - virtual_mode=False:可能访问成功(危险)

🗄️ StoreBackend - 持久化存储

StoreBackend 使用 LangGraph 的 BaseStore, 支持跨线程持久化,可连接 Redis、PostgreSQL 等数据库。

Python 🟡 中级
"""
StoreBackend - 持久化存储
"""
from deepagents import create_deep_agent
from deepagents.backends import StoreBackend
from langgraph.store.memory import InMemoryStore

# 创建持久化 Store
store = InMemoryStore()  # 可替换为 RedisStore、PostgresStore

# 配置 StoreBackend
agent = create_deep_agent(
    model="gpt-4o",
    backend=lambda rt: StoreBackend(rt),
    store=store  # 传递 store 实例
)

# 使用 Agent
result = agent.invoke({
    "messages": [{
        "role": "user",
        "content": "保存用户偏好到 /memories/user_preferences.json"
    }]
})

# 特点:
# - 跨对话持久化
# - 跨线程共享数据
# - 支持数据库后端(Redis、PostgreSQL)
# - 适用于长期记忆、知识库

# 使用场景:
# - 用户配置和偏好
# - FAQ 知识库
# - 历史对话记录
# - 共享的参考数据

使用 PostgreSQL Store

Python 🔴 高级
"""
StoreBackend - PostgreSQL 持久化
"""
from deepagents import create_deep_agent
from deepagents.backends import StoreBackend
from langgraph.store.postgres import PostgresStore

# 连接 PostgreSQL
store = PostgresStore(
    connection_string="postgresql://user:pass@localhost:5432/deepagents"
)

agent = create_deep_agent(
    model="gpt-4o",
    backend=lambda rt: StoreBackend(rt),
    store=store
)

# 优势:
# - 真正的持久化(数据库级别)
# - 跨实例共享(多个 Agent 实例访问同一数据)
# - 支持大规模数据
# - 生产环境推荐

🔀 CompositeBackend - 路由混合

CompositeBackend最灵活的方案, 根据路径前缀将请求路由到不同的后端。

graph LR Agent["Agent 文件操作"] --> Composite["CompositeBackend
路由器"] Composite -->|"/tmp/"| State["StateBackend
临时数据"] Composite -->|"/knowledge/"| Store["StoreBackend
知识库"] Composite -->|"/workspace/"| FS["FilesystemBackend
工作区"] Composite -->|"其他"| Default["StateBackend
默认"] State --> Result1["内存"] Store --> Result2["数据库"] FS --> Result3["磁盘"] Default --> Result4["内存"] style Composite fill:#f59e0b,color:#fff style State fill:#3b82f6,color:#fff style Store fill:#8b5cf6,color:#fff style FS fill:#10b981,color:#fff
Python 🔴 高级 - 推荐
"""
CompositeBackend - 混合路由策略
"""
from deepagents import create_deep_agent
from deepagents.backends import (
    CompositeBackend,
    StateBackend,
    StoreBackend,
    FilesystemBackend
)
from langgraph.store.memory import InMemoryStore

# 创建 Store
store = InMemoryStore()

# 定义路由规则
composite_backend = lambda rt: CompositeBackend(
    default=StateBackend(rt),  # 默认使用内存
    routes={
        "/tmp/": StateBackend(rt),              # 临时数据 → 内存
        "/knowledge/": StoreBackend(rt),        # 知识库 → 持久化
        "/workspace/": FilesystemBackend(       # 工作区 → 磁盘
            root_dir="/Users/myname/workspace",
            virtual_mode=True
        ),
    }
)

# 创建 Agent
agent = create_deep_agent(
    model="gpt-4o",
    backend=composite_backend,
    store=store
)

# 使用示例:

# 1. 临时计算结果 → 内存
agent.invoke({
    "messages": [{
        "role": "user",
        "content": "保存搜索结果到 /tmp/search.txt"
    }]
})  # 使用 StateBackend(内存)

# 2. 知识库数据 → 持久化
agent.invoke({
    "messages": [{
        "role": "user",
        "content": "保存 FAQ 到 /knowledge/faq.json"
    }]
})  # 使用 StoreBackend(数据库)

# 3. 工作区文件 → 磁盘
agent.invoke({
    "messages": [{
        "role": "user",
        "content": "创建项目文件 /workspace/main.py"
    }]
})  # 使用 FilesystemBackend(磁盘)

# 4. 其他路径 → 默认内存
agent.invoke({
    "messages": [{
        "role": "user",
        "content": "保存临时数据到 /data/temp.txt"
    }]
})  # 使用默认 StateBackend(内存)

路由规则

✨ 路由匹配规则
  • 最长前缀匹配/memories/projects/ 优先于 /memories/
  • 精确匹配:路径必须以 / 结尾
  • 默认后端:未匹配的路径使用 default
Python 🟡 中级
"""
复杂路由规则示例
"""
composite = lambda rt: CompositeBackend(
    default=StateBackend(rt),
    routes={
        "/memories/": FilesystemBackend(
            root_dir="/deepagents/myagent",
            virtual_mode=True
        ),
        "/memories/projects/": StoreBackend(rt),  # 更具体的前缀
    }
)

# 路由结果:
# - /memories/projects/code.py → StoreBackend(更长前缀优先)
# - /memories/notes.txt → FilesystemBackend
# - /tmp/data.txt → StateBackend(默认)

🔨 自定义后端实现

可以通过实现BackendProtocol 接口创建自定义后端, 支持 S3、MongoDB、Redis 等任意存储系统。

Python 🔴 高级 - 完整示例
"""
自定义后端 - S3Backend 示例
"""
from typing import Protocol
from deepagents.backends import (
    BackendProtocol,
    LsResult,
    ReadResult,
    WriteResult,
    EditResult,
    GrepResult,
    GlobResult
)
import boto3

class S3Backend(BackendProtocol):
    """S3 存储后端"""

    def __init__(self, bucket_name: str, prefix: str = ""):
        self.s3 = boto3.client("s3")
        self.bucket = bucket_name
        self.prefix = prefix

    def ls_info(self, path: str) -> LsResult:
        """列出 S3 对象"""
        try:
            response = self.s3.list_objects_v2(
                Bucket=self.bucket,
                Prefix=self._normalize_path(path),
                Delimiter="/"
            )

            files = []
            for obj in response.get("Contents", []):
                files.append({
                    "name": obj["Key"].split("/")[-1],
                    "size": obj["Size"],
                    "modified": obj["LastModified"].isoformat()
                })

            return LsResult(files=files, files_update=None)
        except Exception as e:
            return LsResult(error=f"S3 列表失败: {str(e)}")

    def read(self, file_path: str, offset: int = 0,
             limit: int | None = None) -> ReadResult:
        """从 S3 读取文件"""
        try:
            key = self._normalize_path(file_path)
            response = self.s3.get_object(Bucket=self.bucket, Key=key)
            content = response["Body"].read().decode("utf-8")

            # 应用 offset 和 limit
            lines = content.splitlines()
            if offset or limit:
                lines = lines[offset:offset + limit if limit else None]

            return ReadResult(
                content="\n".join(lines),
                files_update=None
            )
        except Exception as e:
            return ReadResult(error=f"S3 读取失败: {str(e)}")

    def write(self, file_path: str, content: str) -> WriteResult:
        """写入 S3 对象"""
        try:
            key = self._normalize_path(file_path)
            self.s3.put_object(
                Bucket=self.bucket,
                Key=key,
                Body=content.encode("utf-8")
            )
            return WriteResult(
                success=f"已写入 S3: s3://{self.bucket}/{key}",
                files_update=None
            )
        except Exception as e:
            return WriteResult(error=f"S3 写入失败: {str(e)}")

    def edit(self, file_path: str, old_string: str,
             new_string: str, replace_all: bool = False) -> EditResult:
        """编辑 S3 对象"""
        # 1. 读取内容
        read_result = self.read(file_path)
        if read_result.error:
            return EditResult(error=read_result.error)

        # 2. 执行替换
        content = read_result.content
        if replace_all:
            new_content = content.replace(old_string, new_string)
        else:
            new_content = content.replace(old_string, new_string, 1)

        # 3. 写回
        write_result = self.write(file_path, new_content)
        if write_result.error:
            return EditResult(error=write_result.error)

        return EditResult(
            success=f"已编辑 {file_path}",
            files_update=None
        )

    def grep_raw(self, pattern: str, path: str = "/",
                 glob: str | None = None) -> GrepResult:
        """S3 内容搜索(简化实现)"""
        return GrepResult(error="S3Backend 暂不支持 grep")

    def glob_info(self, pattern: str, path: str = "/") -> GlobResult:
        """S3 模式匹配(简化实现)"""
        return GlobResult(error="S3Backend 暂不支持 glob")

    def _normalize_path(self, path: str) -> str:
        """规范化路径"""
        path = path.lstrip("/")
        return f"{self.prefix}/{path}" if self.prefix else path


# 使用自定义后端
agent = create_deep_agent(
    model="gpt-4o",
    backend=S3Backend(
        bucket_name="my-agent-storage",
        prefix="agents/workspace"
    )
)

# Agent 的文件操作会使用 S3
result = agent.invoke({
    "messages": [{
        "role": "user",
        "content": "保存报告到 /reports/summary.md"
    }]
})

# 实际操作:
# - 文件写入 S3: s3://my-agent-storage/agents/workspace/reports/summary.md

🛡️ 策略钩子(安全控制)

通过子类化或包装器模式,可以添加安全策略和权限控制。

方式 1:子类化

Python 🔴 高级
"""
策略钩子 - 子类化方式
"""
from deepagents.backends import FilesystemBackend, WriteResult

class GuardedBackend(FilesystemBackend):
    """带安全策略的文件系统后端"""

    def __init__(self, *, deny_prefixes: list[str], **kwargs):
        super().__init__(**kwargs)
        # 规范化拒绝前缀
        self.deny_prefixes = [
            p if p.endswith("/") else p + "/"
            for p in deny_prefixes
        ]

    def write(self, file_path: str, content: str) -> WriteResult:
        """写入前检查权限"""
        # 检查是否在拒绝列表中
        if any(file_path.startswith(p) for p in self.deny_prefixes):
            return WriteResult(
                error=f"写入被拒绝:{file_path} (受保护路径)"
            )

        # 允许写入
        return super().write(file_path, content)

    def edit(self, file_path: str, old_string: str,
             new_string: str, replace_all: bool = False):
        """编辑前检查权限"""
        if any(file_path.startswith(p) for p in self.deny_prefixes):
            return EditResult(
                error=f"编辑被拒绝:{file_path} (受保护路径)"
            )
        return super().edit(file_path, old_string, new_string, replace_all)


# 使用受保护的后端
agent = create_deep_agent(
    model="gpt-4o",
    backend=GuardedBackend(
        root_dir="/workspace",
        virtual_mode=True,
        deny_prefixes=[
            "/config/",      # 配置文件禁止写入
            "/production/",  # 生产数据禁止修改
        ]
    )
)

# Agent 尝试写入受保护路径
result = agent.invoke({
    "messages": [{
        "role": "user",
        "content": "修改配置文件 /config/settings.json"
    }]
})

# 结果:写入被拒绝(安全策略生效)

方式 2:包装器模式

Python 🔴 高级
"""
策略钩子 - 包装器模式
"""
from deepagents.backends import BackendProtocol, WriteResult

class PolicyWrapper(BackendProtocol):
    """策略包装器"""

    def __init__(self, inner: BackendProtocol,
                 deny_prefixes: list[str] | None = None,
                 max_file_size: int | None = None):
        self.inner = inner
        self.deny_prefixes = [
            p if p.endswith("/") else p + "/"
            for p in (deny_prefixes or [])
        ]
        self.max_file_size = max_file_size

    def write(self, file_path: str, content: str) -> WriteResult:
        """写入策略检查"""
        # 1. 路径检查
        if any(file_path.startswith(p) for p in self.deny_prefixes):
            return WriteResult(error=f"拒绝访问: {file_path}")

        # 2. 大小检查
        if self.max_file_size and len(content) > self.max_file_size:
            return WriteResult(
                error=f"文件过大: {len(content)} 字节 "
                      f"(最大 {self.max_file_size})"
            )

        # 3. 执行实际写入
        return self.inner.write(file_path, content)

    # 委托其他方法到内部后端
    def ls_info(self, path: str):
        return self.inner.ls_info(path)

    def read(self, file_path: str, offset: int = 0, limit: int | None = None):
        return self.inner.read(file_path, offset, limit)

    # ... 其他方法类似


# 使用包装器
base_backend = FilesystemBackend(root_dir="/workspace", virtual_mode=True)

protected_backend = PolicyWrapper(
    inner=base_backend,
    deny_prefixes=["/config/", "/secrets/"],
    max_file_size=10 * 1024 * 1024  # 10MB 限制
)

agent = create_deep_agent(
    model="gpt-4o",
    backend=protected_backend
)

# 优势:
# - 保持后端解耦
# - 便于测试和组合
# - 可以嵌套多个包装器(链式策略)

✨ 最佳实践

1. 后端选择策略

场景 推荐后端 原因
快速原型开发 StateBackend(默认) 无需配置,开箱即用
本地开发调试 FilesystemBackend 可以直接查看文件内容
生产环境 CompositeBackend 灵活路由,混合存储
长期记忆/知识库 StoreBackend + PostgreSQL 跨实例共享,持久化

2. CompositeBackend 配置模式

Python
# ✅ 推荐配置
composite = lambda rt: CompositeBackend(
    default=StateBackend(rt),        # 默认临时存储
    routes={
        "/tmp/": StateBackend(rt),           # 显式临时
        "/knowledge/": StoreBackend(rt),     # 知识库持久化
        "/workspace/": FilesystemBackend(    # 工作区磁盘
            root_dir="/data/workspace",
            virtual_mode=True
        ),
    }
)

3. 安全配置清单

  • FilesystemBackend 始终启用 virtual_mode=True
  • ✅ 使用策略包装器限制访问路径
  • ✅ 设置文件大小限制防止滥用
  • ✅ 定期清理临时文件
  • ✅ 生产环境使用只读权限挂载敏感数据

4. 错误处理原则

💡 错误处理最佳实践
  • 返回错误字符串,不抛出异常
  • 错误消息用户友好,Agent 可以理解
  • 包含足够的上下文,帮助 Agent 重试或调整策略

❓ 常见问题

Q1: 如何在生产环境中选择后端?

推荐使用 CompositeBackend

  • 临时数据 → StateBackend(内存,快速)
  • 知识库 → StoreBackend + PostgreSQL(持久化)
  • 工作区文件 → FilesystemBackend(磁盘,安全)

Q2: StateBackend 的数据会丢失吗?

对话结束后会丢失。但如果使用 LangGraph checkpointer, StateBackend 的数据会随对话状态一起持久化。

Q3: 如何实现跨 Agent 共享数据?

使用 StoreBackend

Python
# 创建共享 Store
shared_store = PostgresStore(connection_string="...")

# Agent 1
agent1 = create_deep_agent(
    backend=lambda rt: StoreBackend(rt),
    store=shared_store
)

# Agent 2(共享同一个 Store)
agent2 = create_deep_agent(
    backend=lambda rt: StoreBackend(rt),
    store=shared_store
)

# Agent 1 写入的数据,Agent 2 可以读取

Q4: FilesystemBackend 的 virtual_mode 有性能影响吗?

几乎无影响。virtual_mode 只是路径规范化和验证, 相比磁盘 I/O,开销可以忽略。强烈建议始终启用

Q5: 可以动态切换后端吗?

不能。后端在 Agent 创建时固定。 如需切换,应创建新的 Agent 实例。

📖 参考资源