DeerFlow 工具系统:装配、调用与延迟加载

Skill 可以说「用 web_search 再 write_file」,没有工具的话这些词只是空话。用户让 agent「搜今天 AI 新闻并存成 Markdown」时,真正发生的是:调搜索后端、在沙箱写文件、再用 present_files 交给前端。Tools 是 agent 对外交互的通道,在 config.yaml 声明,按场景装配。

工具分类示意

内置工具tools.pyBUILTIN_TOOLS 里起步:present_files(把产物展示给前端)、ask_clarification(向用户澄清)。模型 supports_vision 时再挂 view_image。配置打开技能演化则加 skill_manage_tool;打开子代理则挂上 taskSUBAGENT_TOOLS。它们跟具体搜索后端无关,但几乎每个 agent 都需要。

沙箱工具负责动手:bashread_filewrite_filestr_replaceglobgrep。配置里用 group(如 bashfile:read)和 use: 指向实现。细节在沙箱章,这里只要知道它们跑在隔离环境里,不直接碰宿主机。

社区工具放在 community/,典型是 web_search / web_fetch。同一工具名可对应 Tavily、Brave、DuckDuckGo、Serper、Exa、Firecrawl、Jina、SearXNG、InfoQuest 等后端;改配置一行 use: 即可切换,agent 始终只看见 web_search。各后端还可从 get_tool_config("web_search").model_extramax_results 一类参数。接口不变、实现可换,这是可插拔的要点。

MCP 工具经 Model Context Protocol 接入外部服务(数据库、内部 API 等)。initialize_mcp_tools 懒加载并缓存;extensions_config 变更会使缓存失效。工具特别多时(例如三十个),提示词只列 deferred 名字列表,需要时用 tool_search 拉取完整 schema。查询支持 select:A,B、关键词,以及 +slack send(名字须含某词再按剩余词排序)。命中后用 Command 更新 promoted(含 catalog_hash 与 names),之后这些工具才真正可调。

装配线:get_available_tools

总装配大致六步:从配置读工具清单,可按 groups 过滤 → resolve_variable(cfg.use, BaseTool) 动态导入 → 若当前是 LocalSandbox 且不允许 host bash,则滤掉宿主机 bash(重要安全线)→ 按条件并入内置工具 → 合并已启用 MCP(tag_mcp_tooldeerflow_mcp 标签)与 ACP → 按名字去重。优先级大致是配置加载 > 内置 > MCP > ACP。重名会让 LLM 收到歧义函数 schema,这是 issue #1803 一类问题的根因。子代理或技能若声明白名单,通常先装齐再过滤;groups=["web"] 可批量只要联网类工具。

1
2
3
4
tools:
- name: web_search
group: web
use: deerflow.community.tavily.tools:web_search_tool

调用循环与错误处理

模型输出 {name, args, id} 形式的 tool call,框架按名找到工具并 ainvoke。社区搜索工具会调外部 API,把结果规范成 JSON 字符串返回(ensure_ascii=False 保留中文,少浪费 token。默认 dumps 会把中文变成 \uXXXX)。结果包成 ToolMessage 喂回模型,进入「想 → 调工具 → 看结果 → 再想」循环。纯异步工具会通过 _ensure_sync_invocable_tool 挂同步包装,方便 LangGraph Server、Studio、同步测试共用一套工具。

ToolErrorHandlingMiddleware 把异常转成带错误信息的 ToolMessage,agent 可以改参数、换工具或向用户说明,整轮不必因此崩溃。工具失败应可恢复。

present_files 与 ask_clarification

present_files 解决的是:沙箱里生成了 /mnt/user-data/outputs/report.md,前端如何安全地知道「可以展示」。如果让模型直接吐路径字符串,前端无法判断路径是否落在可展示目录、是否安全。DeerFlow 用专用工具把路径规范到 /mnt/user-data/outputs/...,并用 relative_to(outputs_dir) 强制落在 outputs 内,否则抛错。返回 Command,同时更新 artifacts(reducer 去重)和成功消息:工具既能做事,也能改状态。

ask_clarification 本体几乎是空壳(return_direct=True,返回占位文案)。真正逻辑在 ClarificationMiddleware.wrap_tool_call:识别工具名后拦截,把 question / clarification_type / options 做成友好消息并中断等待。若工具直接返回一句话,模型往往会继续往下跑,用户来不及答。这里工具只声明意图,中间件负责中断:一个管「问什么」,一个管「怎么停住等答」。

信息不够或方案有多条时,澄清工具比硬猜更合适;报告、图片等产物则应走 present_files,让前端拿到规范化后的 artifacts 列表。

面向 LLM 的小约定

工具输出最终是给模型看的,所以社区工具普遍返回字符串;JSON 结构清晰,人也读得懂。ensure_ascii=False 保留中文原文,少浪费 token。工具名必须唯一,否则 schema 歧义会让调用失败。分组字段则方便批量裁剪工具集:子代理只要 web,或技能声明 allowed-tools 后再过滤,都不必在代码里逐个点名。

一条「搜新闻 + 存 Markdown」在链路上通常是:web_searchwrite_file(沙箱)→ present_files。agent 想一步、做一步;动手落在沙箱,展示走内置工具。

DeerFlow 工具系统:装配、调用与延迟加载

https://simonsu.net/2026/09/15/deerflow-08-tools/

Author

simonisacoder

Posted on

2026-09-15

Licensed under

Comments