ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

DeerFlow 的 grep 与 glob 工具:为 Coding Agent 构建受控的文件系统检索层

DeerFlow 的 grep 与 glob 工具:为 Coding Agent 构建受控的文件系统检索层 DeerFlow 的 grep 与 glob 工具为 Coding Agent 构建受控的文件系统检索层【免费下载链接】deer-flowAn open-source long-horizon SuperAgent harness that researches, codes, and creates. With the help of sandboxes, memories, tools, skill, subagents and message gateway, it handles different levels of tasks that could take minutes to hours.项目地址: https://gitcode.com/GitHub_Trending/de/deer-flow本文基于 DeerFlow 仓库中的 RFC 文档 rfc-grep-glob-tools.md并结合该 RFC 在仓库中已落地的实现源码系统讲解 DeerFlow 为什么要在 sandbox 工具层新增glob按路径模式找文件与grep按内容模式找位置两个 built-in 只读检索工具、它们的设计边界参数语义、路径权限、结果硬限制、底层 Python 实现细节忽略规则、二进制跳过、截断提示以及如何在配置中启用和调优。读完后你将理解 Agent 化文件检索工具区别于 shell 命令包装 的核心取舍并能完整复现 DeerFlow 中glob - grep - read_file - str_replace的仓库探索工作流。问题起点ls / read_file 还不够RFC 的出发点很明确如果 DeerFlow 想更接近 Claude Code 这类 coding agent 的实际工作流仅有ls/read_file/write_file/str_replace/bash还不够。模型在进入修改前通常还需要两类能力glob快速按路径模式找文件例如 所有*.tsx的 page 文件grep快速按内容模式找候选位置例如 某个 symbol / 文案 / 配置键在哪里出现。RFC 列举了当时的典型痛点模型想找特定后缀文件时只能反复ls多层目录或者退回bash find模型想找某个符号出现位置时只能逐文件read_file或者退回bash grep/rg一旦退回bash工具调用就失去结构化输出结果也更难做裁剪、分页、审计和跨 sandbox 一致化对没有开启 host bash 的本地模式bash甚至可能不可用此时缺少足够强的只读检索能力。因此结论是DeerFlow 缺的不是 再多一个 shell 命令而是文件系统检索层。这两类工具的价值不是 功能上 bash 也能做而是能以更低 token 成本、更强约束、更稳定的输出格式替代模型频繁走bash find/bash grep/rg的习惯。目标与非目标RFC 给出的Goals为 agent 提供稳定的路径搜索和内容搜索能力减少对bash的依赖特别是在仓库探索阶段保持与现有 sandbox 安全模型一致输出格式结构化便于模型后续串联read_file/str_replace让本地 sandbox、容器 sandbox、未来 MCP 文件系统工具都能遵守同一语义。Non-Goals同样重要它划定了边界不做通用 shell 兼容层不暴露完整 grep/find/rg CLI 语法不在第一版支持二进制检索、复杂 PCRE 特性、上下文窗口高亮渲染等重功能不把它做成 任意磁盘搜索仍然只允许在 DeerFlow 已授权的路径内执行。直接收益可以概括为五点更低的模型负担不用拼find/grep/xargs/quoting 细节、更稳定的跨环境行为本地、Docker、AIO sandbox 不必依赖容器里是否装了rg、更强的安全与审计调用参数天然就是 搜索什么、在哪搜、最多返回多少、更好的 token 效率返回命中摘要而非整段文件以及对tool_search友好高频基础工具值得保留为 built-in。工具定义glob 与 grep 的参数与返回格式RFC 建议增加两个 built-in sandbox tools放在 sandbox/tools.py。仓库中这两个工具已经实现定义见 glob_tool 与 grep_tool。glob 工具用途按路径模式查找文件或目录。当前实现的签名与 RFC 建议的 schema 基本一致tool(glob, parse_docstringTrue) def glob_tool( runtime: Runtime, pattern: str, path: str, description: str , include_dirs: bool False, max_results: int _DEFAULT_GLOB_MAX_RESULTS, # 200 ) - str: Find files or directories that match a glob pattern under a root directory.参数语义参数说明patternglob 模式相对于根路径匹配例如**/*.py、src/**/test_*.tspath搜索根目录必须是绝对路径description与现有工具保持一致的 UI 展示说明include_dirs是否返回目录默认Falsemax_results最大返回条数默认 200防止一次性打爆上下文返回格式由_format_glob_results生成见 tools.pyFound 3 paths under /mnt/user-data/workspace 1. /mnt/user-data/workspace/backend/app.py 2. /mnt/user-data/workspace/backend/tests/test_app.py 3. /mnt/user-data/workspace/scripts/build.py结果为空时返回No files matched under root命中超过上限时首行会追加(showing first N)并附一句Results truncated. Narrow the path or pattern to see fewer matches.的截断提示。grep 工具用途按内容模式搜索文件返回命中位置摘要。当前实现tool(grep, parse_docstringTrue) def grep_tool( runtime: Runtime, pattern: str, path: str, description: str , glob: str | None None, literal: bool False, case_sensitive: bool False, max_results: int _DEFAULT_GREP_MAX_RESULTS, # 100 ) - str: Search for matching lines inside a text file or files under a root directory.参数语义参数说明pattern搜索词或 Python 正则path搜索目标可以是单个文件或根目录必须是绝对路径glob可选路径过滤例如**/*.py用于缩小扫描范围literal为True时按普通字符串匹配不解释为正则内部用re.escape转义case_sensitive是否大小写敏感默认False即默认re.IGNORECASEmax_results最大返回命中行数不是文件数默认 100返回格式_format_grep_resultsFound 4 matches under /mnt/user-data/workspace /mnt/user-data/workspace/backend/config.py:12: TOOL_GROUPS [...] /mnt/user-data/workspace/backend/config.py:48: def load_tool_config(...): /mnt/user-data/workspace/backend/tools.py:91: tool_groups /mnt/user-data/workspace/backend/tests/test_config.py:22: assert tool_groups in data第一版只返回文件路径 行号 命中行摘要不返回上下文块避免结果过大模型需要上下文时再调用read_file(path, start_line, end_line)。截断时同样输出Results truncated. Narrow the path or add a glob filter.提示。设计原则为什么不做 shell wrapper这是 RFC 中最有分歧也最关键的一条决策。不建议把grep实现为subprocess.run(grep ...)也不建议在容器里直接拼find/rg命令。原因会引入 shell quoting 和注入面会依赖不同 sandbox 镜像是否安装了同一套命令Windows / macOS / Linux 行为不一致很难稳定控制输出条数与格式。正确方向是glob使用 Python 标准库路径遍历grep使用 Python 逐文件扫描输出由 DeerFlow 自己格式化。如果未来为了性能要优先调用rg也应该封装在 provider 内部并保证外部语义不变而不是把 CLI 暴露给模型。从源码结构看这个原则得到了完整贯彻核心检索逻辑放在独立的 search.py 中只依赖os.walk、re、fnmatch、PurePosixPath等标准库没有任何子进程调用。实现解析search.py 中的检索内核search.py 是两个工具的共享内核包含四个关键部件。1. 统一的忽略规则集RFC 要求glob的默认忽略项尽量与ls对齐并 抽一个共享 ignore 集。实现中这是一个 50 项的IGNORE_PATTERNS列表覆盖版本控制目录.git、.svn、.hg、.bzr依赖与虚拟环境node_modules、.venv、venv、site-packages构建产物dist、build、target、out、.next、.nuxt、.output、.turbo缓存与临时文件__pycache__、.pytest_cache、.mypy_cache、.ruff_cache、*.log、*.tmp、*.bak、*.swp等。值得注意的性能细节should_ignore_name在目录树遍历时每个条目都要执行一次因此实现把纯字面量名称预编译成frozensetO(1) 查找只把含*?[的少数通配模式合并成一条正则避免每个文件名做约 50 次fnmatch调用。os.path.normcase同时保持了与fnmatch一致的大小写行为POSIX 敏感、Windows 折叠。2. glob 匹配find_glob_matchesfind_glob_matches(root, pattern, *, include_dirs, max_results)的行为根目录不存在抛FileNotFoundError不是目录抛NotADirectoryError对应 RFC 输入根目录不存在/根路径不是目录返回清晰错误用os.walk遍历且通过原地改写dirs[:]把忽略目录从遍历中直接剪掉模式匹配相对路径path_matches用PurePosixPath.match并额外兼容**/前缀模式命中数达到max_results时立即返回并通过第二个返回值truncatedTrue告知调用方结果被截断——这正是 RFC 大结果集会被截断并明确提示 验收标准的落点。3. grep 匹配find_grep_matchesfind_grep_matches与GrepMatch数据类path/line_number/line三元组与 RFC 建议的抽象层签名一致实现了以下行为逐条对应 RFC 的 Detailed Behavior默认只扫描文本文件is_binary_file检查前 8KB 内是否含\0字节命中即跳过超过max_file_size默认DEFAULT_MAX_FILE_SIZE_BYTES 1_000_000即 RFC 建议的 1MB 上限的文件直接跳过literalTrue时先re.escape否则把pattern当 Pythonre编译编译失败会抛re.error由工具层捕获并返回Error: Invalid regex pattern: ...对应 regex 编译失败时返回参数错误case_sensitiveFalse时加re.IGNORECASE跳过符号链接并要求 resolve 后的文件仍位于 root 之下防越权读取用encodingutf-8, errorsreplace保证脏字节不会中断扫描单行超过line_summary_length * 10即 2000 字符的行直接跳过注释里写明这是为了防止对 minified / 无换行文件的 ReDoS每行命中后经truncate_line截断到 200 字符DEFAULT_LINE_SUMMARY_LENGTH对应 RFC 单行摘要最大长度 200 字符按文件路径、行号的自然遍历顺序输出保持稳定排序。4. 从工具到 Sandbox 抽象RFC 中 Option B 已落地RFC 给出两个实现选项Option A直接在sandbox/tools.py实现第一版与 Option B先扩展Sandbox抽象新增glob/grep抽象方法结论是 第一版建议走 Option A等工具价值验证后再下沉到Sandbox抽象层。从当前仓库看项目走完了两步Sandbox ABC 现在包含glob与grep两个抽象方法各 sandbox provider 可以各自实现/优化工具层调用sandbox.glob(...)/sandbox.grep(...)各环境本地、容器、远程遵守同一语义。这正对应 RFC 的目标之一 让本地 sandbox、容器 sandbox、未来 MCP 文件系统工具都能遵守同一语义。安全模型沿用路径权限与输出脱敏RFC 原则 B 要求两个工具复用ls/read_file的路径校验逻辑它们属于file:read不是 bash 的替代越权入口。在 tools.py 中可以确认这条调用链禁用技能拦截先检查_is_disabled_skill_path被禁用的 skill 目录直接返回错误沙箱初始化ensure_sandbox_initialized(runtime)ensure_thread_directories_exist(runtime)路径解析与权限校验仅本地 sandbox 分支_resolve_local_read_path(path, thread_data)内部调用validate_local_tool_path(path, thread_data, read_onlyTrue)随后区分两类路径——skills / ACP workspace / 自定义挂载路径交给 sandbox 的 PathMapping 解析其余 user-data 虚拟路径走_resolve_and_validate_user_data_path解析。这保证了 thread workspace / uploads / outputs 虚拟路径、/mnt/skills/...、/mnt/acp-workspace/...均被支持越权路径与 path traversal 被拒绝输出脱敏结果回来后用mask_local_paths_in_output把宿主真实路径反掩回虚拟路径glob 对每条 match、grep 对每条GrepMatch.path保证 输出不泄露宿主机真实路径 的验收标准结果级过滤即使 root 本身合法遍历过程中遇到的已禁用 skill 路径仍会被_drop_disabled_skill_paths逐条剔除错误脱敏_sanitize_error会把异常信息中解析出的宿主路径掩码回虚拟路径再返回避免错误消息成为路径泄露通道。两个工具还各自捕获了FileNotFoundError/NotADirectoryError/PermissionErrorgrep 额外捕获re.error统一转成Error: ...文本返回模型可以据此自纠参数。异步侧则通过给glob_tool/grep_tool挂coroutine_glob_tool_async/_grep_tool_async适配 LangGraph 的异步调用同步函数体不变。结果硬限制默认值、上限与配置覆写RFC 原则 C 规定 没有硬限制的 glob/grep 很容易炸上下文建议第一版glob.max_results默认 200、最大 1000grep.max_results默认 100、最大 500单行摘要 200 字符跳过二进制与超大文件命中超阈值时返回 已展示条数 被截断事实 缩小范围建议。实现与这些数值完全对应见 tools.py_DEFAULT_GLOB_MAX_RESULTS 200 _MAX_GLOB_MAX_RESULTS 1000 _DEFAULT_GREP_MAX_RESULTS 100 _MAX_GREP_MAX_RESULTS 500截断提示文案也符合 RFC 的示例风格已展示 N 条 建议缩小 path/pattern/glob。还有一个超出 RFC 文本、但在代码中确认的机制_resolve_max_results会读取config.example.yaml中该工具配置的max_results键_get_tool_config_int并与模型请求的max_results取min。也就是说配置里写死的上限是全局天花板——即使模型在调用时传入更大的max_results也会被钳制回配置值非法值0回退默认值。这为运维侧限流提供了单一控制点。启用与配置file:read 工具组RFC 的 Suggested Config 与仓库根目录的 config.example.yaml 实际内容一致tools: - name: glob group: file:read use: deerflow.sandbox.tools:glob_tool max_results: 200 - name: grep group: file:read use: deerflow.sandbox.tools:grep_tool max_results: 100要点两个工具归属file:read组与ls/read_file同权限等级是只读检索工具而非 bash 的越权入口max_results键会被_resolve_max_results读入作为该工具返回上限的全局天花板glob 天花板 1000、grep 天花板 500超出部分会被 clampuse指向deerflow.sandbox.tools下的具体 tool 对象与仓库中注册位置一一对应。推荐工作流与 Prompt 引导RFC 明确了四个工具的互补关系推荐模型工作流为glob找候选文件grep找候选位置read_file读局部上下文str_replace/write_file执行修改。边界清晰的好处是利于在系统提示中教模型形成稳定习惯。RFC 同时强调引入这两个工具时必须同步更新系统提示——查找文件名模式时优先glob查找代码符号、配置项、文案时优先grep只有工具不足以完成目标时才退回bash否则模型仍会习惯性先调bash。风险、备选方案与验收标准RFC 讨论过的风险与缓解原文四节与bash能力重叠——是事实但不是问题ls和read_file也能被bash替代仍保留因为结构化工具更适合 agent性能——大仓库上纯 Pythongrep可能比rg慢缓解结果上限 文件大小上限1MB、强制 root path、glob过滤缩小扫描范围、必要时在 provider 内部做rg优化但保持同一 schema。当前实现还额外加了 超长行跳过 防 ReDoS忽略规则不一致——ls能看到而glob看不到的路径会让模型困惑缓解统一 ignore 集即 search.py 中那份共享列表并在文档中明确 默认跳过常见依赖和构建目录正则方言过复杂——第一版只支持 Pythonre并提供literalTrue简单模式。Alternatives Considered全部被否定理由值得记录完全依赖bash会让 DeerFlow 在代码探索体验上持续落后且削弱无 bash / 受限 bash 场景能力只加glob不加grep只解决 找文件 没解决 找位置模型最终仍退回bash grep只加grep不加globgrep缺少路径模式过滤时扫描范围经常过大glob是它的天然前置直接接入 MCP filesystem serverMCP 可作为补充但glob/grep作为基础 coding tool 最好是 built-in才能在默认安装中稳定可用。Acceptance CriteriaRFC 原文config.example.yaml中可默认启用glob与grep两个工具归属file:read组本地 sandbox 下严格遵守现有路径权限输出不泄露宿主机真实路径大结果集会被截断并明确提示模型可以通过glob - grep - read_file - str_replace完成典型改码流在禁用 host bash 的本地模式下仓库探索能力明显提升。对应的回归测试覆盖见 test_sandbox_search_tools.py针对路径校验、虚拟路径映射、结果截断与二进制跳过等场景做验证。小结三条被坚守的边界RFC 的最终推荐是 可以加而且应该加但明确卡住三个边界这也正是当前实现可核对到的事实grep/glob必须是built-in 的只读结构化工具——归属file:read组复用validate_local_tool_path(read_onlyTrue)权限模型第一版不做 shell wrapper不把 CLI 方言直接暴露给模型——检索内核纯标准库实现于search.py先在sandbox/tools.py验证价值再下沉到Sandboxprovider 抽象——当前仓库已完成这一步SandboxABC 中同时存在glob/grep抽象方法各 provider 共享同一对外语义。按这个方向DeerFlow 在 coding / repo exploration 场景下的可用性得到提升且风险可控检索行为可审计、可限流、跨环境一致并且与既有文件工具形成清晰的探索—定位—阅读—修改闭环。【免费下载链接】deer-flowAn open-source long-horizon SuperAgent harness that researches, codes, and creates. With the help of sandboxes, memories, tools, skill, subagents and message gateway, it handles different levels of tasks that could take minutes to hours.项目地址: https://gitcode.com/GitHub_Trending/de/deer-flow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表