323 lines
11 KiB
Markdown
323 lines
11 KiB
Markdown
|
|
# Phase 6:工具系统重构(Tool System Refactoring)
|
|||
|
|
|
|||
|
|
日期:2026-04-04
|
|||
|
|
状态:待开始
|
|||
|
|
Demo参考:claw-code-main — tools/, StreamingToolExecutor, toolOrchestration
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 阶段目标
|
|||
|
|
|
|||
|
|
建立**分层工具执行架构**,从现有的扁平工具调用进化为具有注册表、编排层、Hook 拦截能力的工具系统。
|
|||
|
|
|
|||
|
|
**与现有系统的区别**:
|
|||
|
|
|
|||
|
|
| 现有 | 目标 |
|
|||
|
|
|------|------|
|
|||
|
|
| Sub-Commander 直接调用 Tools | ToolRegistry → ToolOrchestration → HookExecutor → ToolExecutor → Tools |
|
|||
|
|
| 工具集固定 | 工具注册表支持动态注册 |
|
|||
|
|
| 无流式工具执行 | StreamingToolExecutor 支持流式 |
|
|||
|
|
| 无工具拦截 | PreTool/PostTool Hook 机制 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 架构设计
|
|||
|
|
|
|||
|
|
### 2.1 新的工具执行架构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ Agent / Sub-Commander │
|
|||
|
|
└─────────────────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ ToolOrchestration Layer │
|
|||
|
|
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
|
|||
|
|
│ │ ToolRegistry│ │HookExecutor │ │ StreamingToolExecutor │ │
|
|||
|
|
│ │ (注册表) │ │ (拦截层) │ │ (流式执行器) │ │
|
|||
|
|
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
|
|||
|
|
└─────────────────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ ToolExecutor │
|
|||
|
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|||
|
|
│ │ Built-in │ │ External │ │ MCP │ │ Plugin │ │
|
|||
|
|
│ │ Tools │ │ Tools │ │ Tools │ │ Tools │ │
|
|||
|
|
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
|||
|
|
└─────────────────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.2 核心组件
|
|||
|
|
|
|||
|
|
#### ToolRegistry(工具注册表)
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# backend/app/agents/tools/registry.py
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
class ToolManifest:
|
|||
|
|
"""工具元数据"""
|
|||
|
|
name: str
|
|||
|
|
description: str
|
|||
|
|
category: ToolCategory
|
|||
|
|
parameters: dict # JSON Schema
|
|||
|
|
return_schema: dict
|
|||
|
|
permission_class: PermissionClass # READ/WRITE/EXTERNAL
|
|||
|
|
side_effect_scope: SideEffectScope # NONE/LOCAL_STATE/DB_WRITE/NETWORK
|
|||
|
|
requires_confirmation: bool
|
|||
|
|
is_streaming: bool = False
|
|||
|
|
tags: list[str] = field(default_factory=list)
|
|||
|
|
|
|||
|
|
class ToolRegistry:
|
|||
|
|
"""工具注册表"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self._tools: dict[str, ToolManifest] = {}
|
|||
|
|
self._executors: dict[str, Callable] = {}
|
|||
|
|
self._hooks: dict[str, list[HookConfig]] = defaultdict(list)
|
|||
|
|
|
|||
|
|
def register(
|
|||
|
|
self,
|
|||
|
|
manifest: ToolManifest,
|
|||
|
|
executor: Callable,
|
|||
|
|
hooks: list[HookConfig] | None = None
|
|||
|
|
):
|
|||
|
|
"""注册工具"""
|
|||
|
|
self._tools[manifest.name] = manifest
|
|||
|
|
self._executors[manifest.name] = executor
|
|||
|
|
if hooks:
|
|||
|
|
for hook in hooks:
|
|||
|
|
self._hooks[manifest.name].append(hook)
|
|||
|
|
|
|||
|
|
def get(self, name: str) -> ToolManifest | None:
|
|||
|
|
"""获取工具元数据"""
|
|||
|
|
return self._tools.get(name)
|
|||
|
|
|
|||
|
|
def get_executor(self, name: str) -> Callable | None:
|
|||
|
|
"""获取工具执行器"""
|
|||
|
|
return self._executors.get(name)
|
|||
|
|
|
|||
|
|
def list_by_category(self, category: ToolCategory) -> list[ToolManifest]:
|
|||
|
|
"""按类别列出工具"""
|
|||
|
|
return [t for t in self._tools.values() if t.category == category]
|
|||
|
|
|
|||
|
|
def list_all(self) -> list[ToolManifest]:
|
|||
|
|
"""列出所有工具"""
|
|||
|
|
return list(self._tools.values())
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### HookExecutor(拦截执行器)
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# backend/app/agents/tools/hook_executor.py
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
class HookConfig:
|
|||
|
|
"""Hook 配置"""
|
|||
|
|
name: str
|
|||
|
|
hook_type: HookType # PRE_TOOL_USE / POST_TOOL_USE / TOOL_ERROR / TOOL_SKIP
|
|||
|
|
handler: Callable
|
|||
|
|
filter_names: list[str] | None = None # 只对特定工具生效,None 表示全部
|
|||
|
|
|
|||
|
|
class HookExecutor:
|
|||
|
|
"""工具 Hook 执行器"""
|
|||
|
|
|
|||
|
|
async def pre_execute(self, tool_name: str, arguments: dict) -> HookResult:
|
|||
|
|
"""PreToolUse - 工具执行前拦截"""
|
|||
|
|
hooks = self._get_hooks(tool_name, HookType.PRE_TOOL_USE)
|
|||
|
|
|
|||
|
|
ctx = HookContext(
|
|||
|
|
tool_name=tool_name,
|
|||
|
|
arguments=arguments,
|
|||
|
|
phase=HookPhase.PRE
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
for hook in hooks:
|
|||
|
|
result = await hook.handler(ctx)
|
|||
|
|
if result.action == HookAction.DENY:
|
|||
|
|
return HookResult(
|
|||
|
|
action=HookAction.DENY,
|
|||
|
|
message=result.message,
|
|||
|
|
modified_args=None
|
|||
|
|
)
|
|||
|
|
elif result.action == HookAction.MODIFY:
|
|||
|
|
ctx.arguments = result.modified_args
|
|||
|
|
|
|||
|
|
return HookResult(action=HookAction.ALLOW, modified_args=ctx.arguments)
|
|||
|
|
|
|||
|
|
async def post_execute(
|
|||
|
|
self,
|
|||
|
|
tool_name: str,
|
|||
|
|
arguments: dict,
|
|||
|
|
result: Any
|
|||
|
|
) -> HookResult:
|
|||
|
|
"""PostToolUse - 工具执行后拦截"""
|
|||
|
|
hooks = self._get_hooks(tool_name, HookType.POST_TOOL_USE)
|
|||
|
|
|
|||
|
|
ctx = HookContext(
|
|||
|
|
tool_name=tool_name,
|
|||
|
|
arguments=arguments,
|
|||
|
|
result=result,
|
|||
|
|
phase=HookPhase.POST
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
for hook in hooks:
|
|||
|
|
result = await hook.handler(ctx)
|
|||
|
|
if result.action == HookAction.MODIFY_RESULT:
|
|||
|
|
ctx.result = result.modified_result
|
|||
|
|
|
|||
|
|
return HookResult(action=HookAction.CONTINUE, modified_result=ctx.result)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### StreamingToolExecutor(流式工具执行器)
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# backend/app/agents/tools/streaming_executor.py
|
|||
|
|
|
|||
|
|
class StreamingToolExecutor:
|
|||
|
|
"""流式工具执行器"""
|
|||
|
|
|
|||
|
|
async def execute_streaming(
|
|||
|
|
self,
|
|||
|
|
tool_name: str,
|
|||
|
|
arguments: dict,
|
|||
|
|
callback: Callable[[dict], Awaitable[None]]
|
|||
|
|
) -> Any:
|
|||
|
|
"""执行流式工具"""
|
|||
|
|
manifest = self.registry.get(tool_name)
|
|||
|
|
if not manifest.is_streaming:
|
|||
|
|
raise ValueError(f"Tool {tool_name} does not support streaming")
|
|||
|
|
|
|||
|
|
executor = self.registry.get_executor(tool_name)
|
|||
|
|
|
|||
|
|
# 使用 aiterator 进行流式执行
|
|||
|
|
async for chunk in executor(**arguments):
|
|||
|
|
event = {"type": "chunk", "data": chunk}
|
|||
|
|
await callback(event)
|
|||
|
|
yield chunk
|
|||
|
|
|
|||
|
|
final_event = {"type": "done", "tool": tool_name}
|
|||
|
|
await callback(final_event)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 新增工具集
|
|||
|
|
|
|||
|
|
### 3.1 文件操作工具
|
|||
|
|
|
|||
|
|
| 工具 | 描述 | 权限级别 |
|
|||
|
|
|------|------|---------|
|
|||
|
|
| GlobTool | 按模式匹配文件 | READ |
|
|||
|
|
| GrepTool | 在文件中搜索内容 | READ |
|
|||
|
|
| LintTool | 代码检查 | READ |
|
|||
|
|
| EditTool | 编辑文件 | WRITE |
|
|||
|
|
|
|||
|
|
### 3.2 开发工具
|
|||
|
|
|
|||
|
|
| 工具 | 描述 | 权限级别 |
|
|||
|
|
|------|------|---------|
|
|||
|
|
| LSPTool | Language Server Protocol | READ |
|
|||
|
|
| BashTool | 执行 Bash 命令 | EXTERNAL |
|
|||
|
|
| PowerShellTool | 执行 PowerShell | EXTERNAL |
|
|||
|
|
|
|||
|
|
### 3.3 系统工具
|
|||
|
|
|
|||
|
|
| 工具 | 描述 | 权限级别 |
|
|||
|
|
|------|------|---------|
|
|||
|
|
| ScheduleCronTool | Cron 定时任务 | WRITE |
|
|||
|
|
| ProcessTool | 进程管理 | EXTERNAL |
|
|||
|
|
|
|||
|
|
### 3.4 协作工具
|
|||
|
|
|
|||
|
|
| 工具 | 描述 | 权限级别 |
|
|||
|
|
|------|------|---------|
|
|||
|
|
| TeamAgentTool | 团队 Agent 协作 | EXTERNAL |
|
|||
|
|
| TaskBroadcastTool | 任务广播 | WRITE |
|
|||
|
|
|
|||
|
|
### 3.5 高级工具
|
|||
|
|
|
|||
|
|
| 工具 | 描述 | 权限级别 |
|
|||
|
|
|------|------|---------|
|
|||
|
|
| RemoteTriggerTool | 远程触发 | EXTERNAL |
|
|||
|
|
| MCPClientTool | MCP 客户端 | EXTERNAL |
|
|||
|
|
| AskUserQuestionTool | 向用户提问 | READ |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 文件结构变化
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
backend/app/agents/tools/
|
|||
|
|
├── __init__.py # 现有 - 需重构
|
|||
|
|
├── registry.py # 新增 - 工具注册表
|
|||
|
|
├── manifest.py # 新增 - 工具元数据
|
|||
|
|
├── hook_executor.py # 新增 - Hook 执行器
|
|||
|
|
├── hook_config.py # 新增 - Hook 配置
|
|||
|
|
├── streaming_executor.py # 新增 - 流式执行器
|
|||
|
|
├── base.py # 新增 - 基础工具类
|
|||
|
|
│
|
|||
|
|
├── builtins/ # 新增 - 内置工具
|
|||
|
|
│ ├── __init__.py
|
|||
|
|
│ ├── file_tools.py # Glob, Grep, Edit, Lint
|
|||
|
|
│ ├── system_tools.py # Bash, PowerShell, Cron
|
|||
|
|
│ ├── dev_tools.py # LSP, Git
|
|||
|
|
│ └── collaboration_tools.py # Team, Broadcast
|
|||
|
|
│
|
|||
|
|
├── task.py # 现有 - 保留
|
|||
|
|
├── schedule.py # 现有 - 保留
|
|||
|
|
├── search.py # 现有 - 保留
|
|||
|
|
├── forum.py # 现有 - 保留
|
|||
|
|
└── time_reasoning.py # 现有 - 保留
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 迁移计划
|
|||
|
|
|
|||
|
|
### 阶段 6.1:基础设施(1-2周)
|
|||
|
|
- 创建 ToolRegistry 类
|
|||
|
|
- 创建 ToolManifest 数据类
|
|||
|
|
- 迁移现有工具到注册表
|
|||
|
|
|
|||
|
|
### 阶段 6.2:Hook 系统(2-3周)
|
|||
|
|
- 创建 HookExecutor
|
|||
|
|
- 实现 PreTool/PostTool 机制
|
|||
|
|
- 添加内置 Hook(确认危险操作、日志记录)
|
|||
|
|
|
|||
|
|
### 阶段 6.3:流式执行(1-2周)
|
|||
|
|
- 实现 StreamingToolExecutor
|
|||
|
|
- 为支持流式的工具添加 streaming 标志
|
|||
|
|
- 更新 AgentService 集成
|
|||
|
|
|
|||
|
|
### 阶段 6.4:新工具集(2-3周)
|
|||
|
|
- 实现新增的工具类
|
|||
|
|
- 添加完整的工具文档
|
|||
|
|
- 单元测试覆盖
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 验收标准
|
|||
|
|
|
|||
|
|
| 检查点 | 标准 |
|
|||
|
|
|--------|------|
|
|||
|
|
| 工具注册 | 所有现有工具已在 Registry 中注册 |
|
|||
|
|
| Hook 执行 | PreTool/PostTool Hook 能正确拦截 |
|
|||
|
|
| 流式执行 | 标记为 streaming 的工具可流式返回 |
|
|||
|
|
| 新工具 | 新增工具集中每个工具可正常执行 |
|
|||
|
|
| 向后兼容 | 现有 Sub-Commander 工具调用不受影响 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. Demo 借鉴
|
|||
|
|
|
|||
|
|
| claw-code 实现 | Jarvis 对应 |
|
|||
|
|
|----------------|------------|
|
|||
|
|
| `src/tools/` | `backend/app/agents/tools/` |
|
|||
|
|
| `StreamingToolExecutor.ts` | `streaming_executor.py` |
|
|||
|
|
| `toolExecution.ts` | `hook_executor.py` |
|
|||
|
|
| `toolHooks.ts` | `hook_config.py` |
|
|||
|
|
| `ToolManifest` | `manifest.py` |
|