跳到主要内容
深度代理通过 lsread_filewrite_fileedit_fileglobgrep 等工具向代理公开文件系统接口。这些工具通过可插拔的后端运行。 本页解释如何选择后端将不同路径路由到不同后端实现自己的虚拟文件系统(例如 S3 或 Postgres)、添加策略钩子以及遵守后端协议

快速入门

这里有一些预构建的文件系统后端,您可以快速将其与深度代理一起使用
内置后端描述
默认agent = create_deep_agent()
状态中瞬时存储。代理的默认文件系统后端存储在 langgraph 状态中。请注意,此文件系统仅对单个线程持久化。
本地文件系统持久性agent = create_deep_agent(backend=FilesystemBackend(root_dir="/Users/nh/Desktop/"))
这使深度代理能够访问您的本地机器文件系统。您可以指定代理有权访问的根目录。请注意,任何提供的 root_dir 都必须是绝对路径。
持久存储(LangGraph 存储)agent = create_deep_agent(backend=lambda rt: StoreBackend(rt))
这使代理能够访问跨线程持久化的长期存储。这非常适合存储长期记忆或适用于代理多次执行的指令。
复合默认瞬时,/memories/ 持久化。复合后端具有最大的灵活性。您可以指定文件系统中不同的路由指向不同的后端。请参阅下面的复合路由,获取即时粘贴示例。

内置后端

StateBackend(瞬时)

# By default we provide a StateBackend
agent = create_deep_agent()

# Under the hood, it looks like
from deepagents.backends import StateBackend

agent = create_deep_agent(
    backend=(lambda rt: StateBackend(rt))   # Note that the tools access State through the runtime.state
)
工作原理
  • 在当前线程的 LangGraph 代理状态中存储文件。
  • 通过检查点在同一线程的多个代理回合中持久化。
最适合
  • 代理用于写入中间结果的草稿板。
  • 自动清除大型工具输出,代理可以逐段读回。

FilesystemBackend(本地磁盘)

from deepagents.backends import FilesystemBackend

agent = create_deep_agent(
    backend=FilesystemBackend(root_dir="/Users/nh/Desktop/")
)
工作原理
  • 在可配置的 root_dir 下读/写真实文件。
  • 注意:root_dir 必须是绝对路径。
  • 您可以选择设置 virtual_mode=True 以在 root_dir 下沙盒化和规范化路径。
  • 使用安全的路径解析,尽可能防止不安全的符号链接遍历,可以使用 ripgrep 进行快速 grep
最适合
  • 您机器上的本地项目
  • CI 沙盒
  • 挂载的持久卷

StoreBackend(LangGraph 存储)

from deepagents.backends import StoreBackend

agent = create_deep_agent(
    backend=(lambda rt: StoreBackend(rt))   # Note that the tools access Store through the runtime.store
)
工作原理
  • 将文件存储在运行时提供的 LangGraph BaseStore 中,从而实现跨线程持久存储。
最适合
  • 当您已经运行配置好的 LangGraph 存储时(例如,Redis、Postgres 或 BaseStore 后面的云实现)。
  • 当您通过 LangSmith 部署部署代理时(会自动为您的代理配置存储)。

CompositeBackend(路由器)

from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from deepagents.backends.composite import build_composite_state_backend

composite_backend = lambda rt: CompositeBackend(
    default=StateBackend(rt)
    routes={
        "/memories/": StoreBackend(rt),
        "/docs/": CustomBackend()
    }
)

agent = create_deep_agent(backend=composite_backend)
工作原理
  • 根据路径前缀将文件操作路由到不同的后端。
  • 在列表和搜索结果中保留原始路径前缀。
最适合
  • 当您希望为代理提供瞬时和跨线程存储时,CompositeBackend 允许您同时提供 StateBackend 和 StoreBackend
  • 当您有多个信息源希望作为单个文件系统的一部分提供给代理时。
    • 例如,您在某个存储中将长期记忆存储在 /memories/ 下,并且您还有一个自定义后端,其文档可在 /docs/ 访问。

指定后端

  • 将后端传递给 create_deep_agent(backend=...)。文件系统中间件将它用于所有工具。
  • 您可以传递
    • 一个实现 BackendProtocol 的实例(例如,FilesystemBackend(root_dir=".")),或者
    • 一个工厂 BackendFactory = Callable[[ToolRuntime], BackendProtocol](适用于需要 StateBackendStoreBackend 等运行时的后端)。
  • 如果省略,默认值为 lambda rt: StateBackend(rt)

路由到不同的后端

将命名空间的一部分路由到不同的后端。通常用于持久化 /memories/* 并使其他所有内容保持瞬时。
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend
from deepagents.backends.composite import build_composite_state_backend

composite_backend = lambda rt: CompositeBackend(
    routes={
        "/memories/": FilesystemBackend(root_dir="/deepagents/myagent"),
    },
)

agent = create_deep_agent(backend=composite_backend)
行为
  • /workspace/plan.md → StateBackend(瞬时)
  • /memories/agent.md/deepagents/myagent 下的 FilesystemBackend
  • lsglobgrep 聚合结果并显示原始路径前缀。
备注
  • 较长的前缀获胜(例如,路由 "/memories/projects/" 可以覆盖 "/memories/")。
  • 对于 StoreBackend 路由,确保代理运行时提供存储(runtime.store)。

使用虚拟文件系统

构建自定义后端以将远程或数据库文件系统(例如 S3 或 Postgres)投影到工具命名空间中。 设计准则:
  • 路径是绝对路径(/x/y.txt)。决定如何将它们映射到您的存储键/行。
  • 高效地实现 ls_infoglob_info(在可用时进行服务器端列表,否则进行本地过滤)。
  • 对缺失文件或无效正则表达式模式返回用户可读的错误字符串。
  • 对于外部持久性,在结果中设置 files_update=None;只有状态内后端才应返回 files_update 字典。
S3 样式大纲
from deepagents.backends.protocol import BackendProtocol, WriteResult, EditResult
from deepagents.backends.utils import FileInfo, GrepMatch

class S3Backend(BackendProtocol):
    def __init__(self, bucket: str, prefix: str = ""):
        self.bucket = bucket
        self.prefix = prefix.rstrip("/")

    def _key(self, path: str) -> str:
        return f"{self.prefix}{path}"

    def ls_info(self, path: str) -> list[FileInfo]:
        # List objects under _key(path); build FileInfo entries (path, size, modified_at)
        ...

    def read(self, file_path: str, offset: int = 0, limit: int = 2000) -> str:
        # Fetch object; return numbered content or an error string
        ...

    def grep_raw(self, pattern: str, path: str | None = None, glob: str | None = None) -> list[GrepMatch] | str:
        # Optionally filter server‑side; else list and scan content
        ...

    def glob_info(self, pattern: str, path: str = "/") -> list[FileInfo]:
        # Apply glob relative to path across keys
        ...

    def write(self, file_path: str, content: str) -> WriteResult:
        # Enforce create‑only semantics; return WriteResult(path=file_path, files_update=None)
        ...

    def edit(self, file_path: str, old_string: str, new_string: str, replace_all: bool = False) -> EditResult:
        # Read → replace (respect uniqueness vs replace_all) → write → return occurrences
        ...
Postgres 样式大纲
  • files(path text primary key, content text, created_at timestamptz, modified_at timestamptz)
  • 将工具操作映射到 SQL
    • ls_info 使用 WHERE path LIKE $1 || '%'
    • glob_info 在 SQL 中过滤或获取然后在 Python 中应用 glob
    • grep_raw 可以按扩展名或上次修改时间获取候选行,然后扫描行

添加策略钩子

通过子类化或包装后端来强制执行企业规则。 阻止在选定前缀下的写入/编辑(子类):
from deepagents.backends.filesystem import FilesystemBackend
from deepagents.backends.protocol import WriteResult, EditResult

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"Writes are not allowed under {file_path}")
        return super().write(file_path, content)

    def edit(self, file_path: str, old_string: str, new_string: str, replace_all: bool = False) -> EditResult:
        if any(file_path.startswith(p) for p in self.deny_prefixes):
            return EditResult(error=f"Edits are not allowed under {file_path}")
        return super().edit(file_path, old_string, new_string, replace_all)
通用包装器(适用于任何后端)
from deepagents.backends.protocol import BackendProtocol, WriteResult, EditResult
from deepagents.backends.utils import FileInfo, GrepMatch

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

    def _deny(self, path: str) -> bool:
        return any(path.startswith(p) for p in self.deny_prefixes)

    def ls_info(self, path: str) -> list[FileInfo]:
        return self.inner.ls_info(path)
    def read(self, file_path: str, offset: int = 0, limit: int = 2000) -> str:
        return self.inner.read(file_path, offset=offset, limit=limit)
    def grep_raw(self, pattern: str, path: str | None = None, glob: str | None = None) -> list[GrepMatch] | str:
        return self.inner.grep_raw(pattern, path, glob)
    def glob_info(self, pattern: str, path: str = "/") -> list[FileInfo]:
        return self.inner.glob_info(pattern, path)
    def write(self, file_path: str, content: str) -> WriteResult:
        if self._deny(file_path):
            return WriteResult(error=f"Writes are not allowed under {file_path}")
        return self.inner.write(file_path, content)
    def edit(self, file_path: str, old_string: str, new_string: str, replace_all: bool = False) -> EditResult:
        if self._deny(file_path):
            return EditResult(error=f"Edits are not allowed under {file_path}")
        return self.inner.edit(file_path, old_string, new_string, replace_all)

协议参考

后端必须实现 BackendProtocol 所需端点:
  • ls_info(path: str) -> list[FileInfo]
    • 返回至少包含 path 的条目。如果可用,包含 is_dirsizemodified_at。按 path 排序以实现确定性输出。
  • read(file_path: str, offset: int = 0, limit: int = 2000) -> str
    • 返回带编号的内容。如果文件缺失,返回 "Error: File '/x' not found"
  • grep_raw(pattern: str, path: Optional[str] = None, glob: Optional[str] = None) -> list[GrepMatch] | str
    • 返回结构化匹配项。对于无效的正则表达式,返回一个字符串,如 "Invalid regex pattern: ..."(不要引发异常)。
  • glob_info(pattern: str, path: str = "/") -> list[FileInfo]
    • 将匹配的文件作为 FileInfo 条目返回(如果没有,则返回空列表)。
  • write(file_path: str, content: str) -> WriteResult
    • 仅创建。如果发生冲突,返回 WriteResult(error=...)。成功时,设置 path,对于状态后端设置 files_update={...};外部后端应使用 files_update=None
  • edit(file_path: str, old_string: str, new_string: str, replace_all: bool = False) -> EditResult
    • 除非 replace_all=True,否则强制 old_string 的唯一性。如果未找到,返回错误。成功时包含 occurrences
支持类型
  • WriteResult(error, path, files_update)
  • EditResult(error, path, files_update, occurrences)
  • FileInfo 字段:path(必需),可选 is_dirsizemodified_at
  • GrepMatch 字段:pathlinetext

以编程方式连接这些文档到 Claude、VSCode 等,通过 MCP 获取实时答案。
© . This site is unofficial and not affiliated with LangChain, Inc.