# DeerFlow 工具调用系统参考文档 > 调研 DeerFlow 的工具调用完整流程,为 ZCLAW 工具调用问题排查提供参考。 > 分析日期:2026-04-24 --- ## 一、端到端数据流 ``` 用户消息 → FastAPI Gateway (/api/threads/{id}/runs/stream) → services.start_run() → asyncio.create_task(run_agent(...)) → LangGraph Agent Graph (create_agent) → LLM Model (ChatOpenAI / Claude) → AIMessage (含 tool_calls 列表) → 14 层 Middleware 链处理 → ToolNode (LangGraph 内置, 按 tool_call.name 路由) → ToolMessage (执行结果) → 再次调用 LLM (带着 ToolMessage 继续) → StreamBridge.publish() → asyncio.Queue → SSE → 前端 useStream hook → React 组件渲染 ``` ## 二、工具注册与执行 ### 2.1 注册入口 **文件**: `G:/deerflow/backend/packages/harness/deerflow/tools/tools.py` — `get_available_tools()` 工具来自四个来源: | 来源 | 加载方式 | 示例 | |------|----------|------| | Config 工具 | YAML 配置 + 反射导入 (`module:variable`) | `deerflow.sandbox.tools:bash_tool` | | Builtin 工具 | 硬编码导入 | `present_file_tool`, `ask_clarification_tool` | | MCP 工具 | `MultiServerMCPClient` 从 MCP 服务器缓存获取 | 第三方 MCP 工具 | | ACP 工具 | `build_invoke_acp_agent_tool()` 动态构建 | 外部 agent 调用 | ### 2.2 Sandbox 工具清单 **文件**: `G:/deerflow/backend/packages/harness/deerflow/sandbox/tools.py` | 工具名 | 功能 | |--------|------| | `bash` | 沙箱中执行命令 | | `ls` | 列出目录 | | `read_file` | 读取文件 | | `write_file` | 写入文件(触发产物面板自动打开) | | `str_replace` | 字符串替换(触发产物面板自动打开) | ### 2.3 Builtin 工具 **文件**: `G:/deerflow/backend/packages/harness/deerflow/tools/builtins/` | 工具 | 功能 | |------|------| | `ask_clarification` | 向用户提问澄清(中断执行等待回复) | | `present_file` | 展示文件给用户(触发产物卡片) | | `setup_agent` | 自定义 agent 创建 | | `task_tool` | 子 agent 任务委派 | | `view_image` | 图片查看(仅视觉模型) | | `tool_search` | 延迟工具搜索(MCP 工具按需暴露) | ## 三、中间件链(14 层) **文件**: `G:/deerflow/backend/packages/harness/deerflow/agents/lead_agent/agent.py` — `_build_middlewares()` 与工具调用相关的关键中间件: ### 3.1 DanglingToolCallMiddleware **文件**: `dangling_tool_call_middleware.py` 在 `wrap_model_call` 中检测消息历史中缺失 ToolMessage 的 AIMessage,自动注入占位 ToolMessage: ```python ToolMessage( content="[Tool call was interrupted and did not return a result.]", tool_call_id=tc_id, name=tc.get("name", "unknown"), status="error", ) ``` ### 3.2 ToolErrorHandlingMiddleware **文件**: `tool_error_handling_middleware.py` 在 `wrap_tool_call` 中捕获工具执行异常,转换为错误 ToolMessage 而非让整个 run 崩溃。 ### 3.3 LoopDetectionMiddleware **文件**: `loop_detection_middleware.py` 在 `after_model` 中检测重复工具调用: - 阈值 3 次 → 注入警告 HumanMessage - 阈值 5 次 → 直接清空 tool_calls,强制 LLM 产出文本回答 ### 3.4 DeferredToolFilterMiddleware **文件**: `deferred_tool_filter_middleware.py` 在 `wrap_model_call` 中过滤延迟注册的 MCP 工具 schema,仅在 LLM 通过 `tool_search` 发现后才暴露。 ### 3.5 ClarificationMiddleware 拦截 `ask_clarification` 工具调用,中断执行等待用户回复。 ### 3.6 SubagentLimitMiddleware 截断过多的并行子 agent 调用。 ## 四、工具结果回传 ### 4.1 格式 LangChain 的 `ToolMessage`,包含: - `content`: 执行结果文本 - `tool_call_id`: 匹配 AIMessage 中的 tool_call ID - `name`: 工具名称 - `status`: `"error"` 或省略 ### 4.2 特殊工具 `present_file_tool` 返回 `Command` 而非纯字符串,同时更新 `artifacts` 和 `messages` 两个 state channel。 ## 五、前端工具调用展示 ### 5.1 消息分组 **文件**: `G:/deerflow/frontend/src/core/messages/utils.ts` — `groupMessages()` | 分组类型 | 触发条件 | 展示 | |----------|----------|------| | `assistant:processing` | AI 消息含 tool_calls 或 reasoning | MessageGroup (折叠) | | `assistant` | AI 消息有文本无 tool_calls | MessageListItem (气泡) | | `assistant:present-files` | 含 present_files tool call | ArtifactFileList | | `assistant:clarification` | ask_clarification 结果 | MarkdownContent | | `assistant:subagent` | 含 task tool call | SubtaskCard | ### 5.2 工具状态推断 前端**没有显式状态机**。通过消息序列推断: - AI 消息含 tool_calls 但无对应 ToolMessage → 正在执行 - ToolMessage 出现 → 执行完成 - `assistant:processing` 组由 `ChainOfThought` 折叠组件包裹 ### 5.3 工具调用 UI **文件**: `message-group.tsx` 第 186-423 行 按工具名渲染不同图标和内容: - `bash` → 终端图标 + 命令代码块 - `read_file`/`write_file`/`str_replace` → 文件图标 + 路径链接(点击打开产物面板) - `web_search` → 搜索图标 + 结果链接 - 默认 → 扳手图标 + 工具名 ## 六、流式处理中的工具调用 ### 6.1 架构 ``` agent.astream(stream_mode=["values"]) → StreamBridge (asyncio.Queue per run, maxsize=256) → sse_consumer() → SSE frames → 前端 ``` ### 6.2 关键特征 - 工具调用**不中断**流。LangGraph 自动在 agent_node 和 tool_node 之间路由 - 每次状态变更产出完整的 `values` 快照,前端通过 `seen_ids` 去重 - 15 秒心跳包保持 SSE 连接 ### 6.3 前端看到的事件序列 1. `values` 事件: 含 `tool_calls` 的 AIMessage 2. `values` 事件: ToolMessage(工具结果) 3. `values` 事件: LLM 基于工具结果的最终回答 整个过程连续,不中断 SSE 连接。 ## 七、与 ZCLAW 对比(工具调用) | 维度 | DeerFlow | ZCLAW | |------|----------|-------| | 框架 | LangGraph (graph-based) | 自研 loop_runner (循环) | | 工具生命周期 | LangGraph ToolNode 自动管理 | 手动 ToolRegistry + loop_runner | | after_tool_call 中间件 | ✅ wrap_tool_call 钩子完整 | ❌ 流式和非流式模式均未调用 | | 并行工具执行 | LangGraph 自动处理 | 非流式有 JoinSet,流式全串行 | | 悬挂修复 | DanglingToolCallMiddleware | DanglingToolMiddleware (有) | | 错误恢复 | ToolErrorHandlingMiddleware (异常→ToolMessage) | ToolErrorMiddleware (计数器) | | 循环检测 | LoopDetectionMiddleware (3次警告/5次强停) | LoopGuardMiddleware (有) | | 前端状态 | 消息序列推断 | 显式 ToolCallStep 状态机 | | MCP 工具 | 延迟注册 + tool_search 按需暴露 | 全量注册 | ## 八、关键文件索引 | 功能 | DeerFlow 文件 | |------|-------------| | Agent 工厂 | `backend/packages/harness/deerflow/agents/lead_agent/agent.py` | | 中间件组装 | `backend/packages/harness/deerflow/agents/factory.py` | | 工具注册 | `backend/packages/harness/deerflow/tools/tools.py` | | Sandbox 工具 | `backend/packages/harness/deerflow/sandbox/tools.py` | | Builtin 工具 | `backend/packages/harness/deerflow/tools/builtins/` | | 错误处理中间件 | `agents/middlewares/tool_error_handling_middleware.py` | | 悬挂修复中间件 | `agents/middlewares/dangling_tool_call_middleware.py` | | 循环检测中间件 | `agents/middlewares/loop_detection_middleware.py` | | 延迟过滤中间件 | `agents/middlewares/deferred_tool_filter_middleware.py` | | 流式 Bridge | `runtime/stream_bridge/memory.py` | | 前端消息分组 | `frontend/src/core/messages/utils.ts` | | 前端工具调用组件 | `frontend/src/components/workspace/messages/message-group.tsx` |