Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
P0-1: after_tool_call 中间件从未被调用 - 流式模式(run_streaming)和非流式模式(run)均添加 middleware_chain.run_after_tool_call() - ToolErrorMiddleware 错误计数恢复逻辑现在生效 - ToolOutputGuardMiddleware 敏感信息检测现在生效 P0-2: stream_errored 跳过所有工具执行 - 新增 completed_tool_ids 跟踪哪些工具已收到完整 ToolUseEnd - 流式错误时区分完整工具和不完整工具 - 完整工具照常执行(产物创建等不受影响) - 不完整工具发送取消 ToolEnd 事件(前端不再卡"执行中") - 工具执行后若 stream_errored,break outer 阻止无效 LLM 循环 参考文档: - docs/references/zclaw-toolcall-issues.md (10项问题分析) - docs/references/deerflow-toolcall-reference.md (DeerFlow工具调用完整参考)
213 lines
7.7 KiB
Markdown
213 lines
7.7 KiB
Markdown
# 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` |
|