版本: v2.0 更新时间: 2025-10-10 状态: ✅ 已完成并优化
Blade 工具系统基于统一、简洁、类型安全的设计原则,提供强大而灵活的工具扩展能力。
- ✅ 统一接口: 所有工具(内置/MCP/自定义)使用相同的
Tool接口 - ✅ 类型安全: 端到端 TypeScript 类型推断,基于 Zod Schema
- ✅ 简洁 API: 通过
createTool函数创建工具,无需复杂继承 - ✅ MCP 集成: 自动转换 MCP 工具为标准 Tool
- ✅ 模块化: 清晰的目录结构,职责分明
src/tools/
├── core/ # 核心工具系统
│ ├── createTool.ts # 统一的工具创建 API ⭐
│ ├── ToolInvocation.ts # 工具调用抽象
│ └── index.ts # 核心导出
│
├── types/ # 类型定义(统一位置) ⭐
│ ├── ToolTypes.ts # 工具类型(Tool、ToolConfig、ToolDescription)
│ ├── ExecutionTypes.ts # 执行上下文类型
│ └── index.ts # 类型统一导出
│
├── validation/ # 验证系统
│ ├── zodToJson.ts # Zod → JSON Schema 转换
│ ├── errorFormatter.ts # 错误格式化
│ └── index.ts # 验证导出
│
├── registry/ # 工具注册系统
│ ├── ToolRegistry.ts # 主注册表
│ ├── ToolResolver.ts # 工具解析器
│ └── index.ts # 注册系统导出
│
├── builtin/ # 内置工具(13个)
│ ├── file/ # 文件操作(4个)
│ │ ├── read.ts # 读取文件
│ │ ├── write.ts # 写入文件
│ │ ├── edit.ts # 编辑文件
│ │ └── multi-edit.ts # 批量编辑
│ ├── search/ # 搜索工具(3个)
│ │ ├── glob.ts # 文件模式匹配
│ │ ├── grep.ts # 内容搜索
│ │ └── find.ts # 文件查找
│ ├── shell/ # Shell 命令(3个)
│ │ ├── bash.ts # Bash 命令
│ │ ├── shell.ts # 通用 Shell
│ │ └── script.ts # 脚本执行
│ ├── web/ # 网络工具(2个)
│ │ ├── web-fetch.ts # 网页抓取
│ │ └── api-call.ts # API 调用
│ ├── task/ # 任务管理(1个)
│ │ └── task.ts # 任务代理
│ └── index.ts # 内置工具导出
│
└── index.ts # 工具系统统一导出
类型系统优化 ✅
- 所有类型定义统一在
types/文件夹 - 迁移到标准
@types/json-schema: 使用社区标准类型定义 - 删除重复定义:
core/types.ts(110行)、McpTypes.ts(70行) - 删除自定义
JSONSchema7接口(22行),使用标准定义 - 解决了
ValidationError/ValidationResult重复定义问题 - 修复了
output/displayMessage字段名称问题
代码精简 ✅
- 删除未使用代码:
ToolDiscovery.ts(201行) - 删除冗余类型定义:
convertZodToJsonSchema函数(61行) - 净删除:442行重复/未使用代码
- 新增:74行辅助函数 + 30行类型守卫
- 总净减少:338行代码
依赖优化 ✅
- 新增:
@types/json-schema@7.0.15(devDependency, ~3KB) - 零运行时影响: 类型定义编译后完全消失
- 与生态对齐:兼容 Ajv、json-schema-to-typescript 等库
export interface Tool<TParams = unknown> {
// 基本信息
readonly name: string;
readonly displayName: string;
readonly kind: ToolKind;
readonly description: ToolDescription;
readonly version: string;
readonly category?: string;
readonly tags: string[];
// 方法
getFunctionDeclaration(): FunctionDeclaration;
getMetadata(): Record<string, unknown>;
build(params: TParams): ToolInvocation<TParams>;
execute(params: TParams, signal?: AbortSignal): Promise<ToolResult>;
}export interface ToolConfig<TSchema = unknown, TParams = unknown> {
name: string;
displayName: string;
kind: ToolKind;
schema: TSchema; // Zod Schema
description: ToolDescription;
requiresConfirmation?: boolean | ConfirmationCallback<TParams>;
execute: (params: TParams, context: ExecutionContext) => Promise<ToolResult>;
version?: string;
category?: string;
tags?: string[];
}export interface ToolResult {
success: boolean;
llmContent: string | object; // 传递给 LLM 的内容
displayContent: string; // 显示给用户的内容
error?: ToolError;
metadata?: Record<string, unknown>;
}import { createTool } from '@/tools/core';
import { ToolKind } from '@/tools/types';
import { z } from 'zod';
export const helloTool = createTool({
name: 'hello',
displayName: 'Hello World',
kind: ToolKind.ReadOnly,
schema: z.object({
name: z.string().describe('要打招呼的名字'),
}),
description: {
short: '打招呼的示例工具',
important: ['这是一个演示工具']
},
async execute(params, context) {
return {
success: true,
llmContent: `Hello, ${params.name}!`,
displayContent: `✅ Hello, ${params.name}!`,
};
}
});import { createMcpTool } from '@/mcp/createMcpTool';
// MCP 工具自动转换为标准 Tool
export function createMcpTool(
mcpClient: McpClient,
serverName: string,
toolDef: McpToolDefinition
) {
// 1. JSON Schema → Zod Schema 自动转换
const zodSchema = convertJsonSchemaToZod(toolDef.inputSchema);
// 2. 使用 createTool 创建标准工具
return createTool({
name: `mcp__${serverName}__${toolDef.name}`,
displayName: `${serverName}: ${toolDef.name}`,
kind: ToolKind.External,
schema: zodSchema,
description: {
short: toolDef.description || `MCP 工具: ${toolDef.name}`,
important: [`来自 MCP 服务器: ${serverName}`]
},
requiresConfirmation: true,
async execute(params, context) {
const result = await mcpClient.callTool(toolDef.name, params);
return convertMcpResult(result);
}
});
}import { ToolRegistry } from '@/tools/registry';
import { getBuiltinTools } from '@/tools/builtin';
// 创建注册表
const registry = new ToolRegistry();
// 注册内置工具
const builtinTools = await getBuiltinTools();
builtinTools.forEach(tool => registry.register(tool));
// 注册 MCP 工具
const mcpTools = await mcpRegistry.getAvailableTools();
mcpTools.forEach(tool => registry.registerMcpTool(tool));
// 获取所有工具
const allTools = registry.getAll(); // Tool[]
// 获取 LLM 函数声明
const declarations = registry.getFunctionDeclarations();| 文件 | 说明 | 主要类型 |
|---|---|---|
ToolTypes.ts |
核心工具类型 | Tool, ToolConfig, ToolDescription, ToolKind, ToolResult, FunctionDeclaration |
ExecutionTypes.ts |
执行上下文类型 | ExecutionContext |
@types/json-schema |
JSON Schema 标准类型 | JSONSchema7, JSONSchema7Definition |
// 从统一入口导入工具类型
import type {
Tool,
ToolConfig,
ToolResult,
ExecutionContext,
} from '@/tools/types';
// JSON Schema 类型需要直接从标准包导入
import type { JSONSchema7 } from 'json-schema';为什么使用标准类型?
- ✅ 社区标准,广泛兼容
- ✅ 完整的 JSON Schema Draft-07 支持
- ✅ 官方维护,自动跟进规范更新
- ✅ 零运行时开销(编译后消失)
两种类型:
import type { JSONSchema7, JSONSchema7Definition } from 'json-schema';
// JSONSchema7 - 完整的 schema 对象
const schema: JSONSchema7 = {
type: 'object',
properties: {
name: { type: 'string' }
}
};
// JSONSchema7Definition - 可以是 boolean (JSON Schema 规范允许)
const def1: JSONSchema7Definition = schema; // 对象
const def2: JSONSchema7Definition = true; // true = 接受任何值
const def3: JSONSchema7Definition = false; // false = 拒绝任何值类型守卫示例:
// 处理 properties 可能是 boolean 的情况
if (schema.properties) {
for (const [key, value] of Object.entries(schema.properties)) {
if (typeof value === 'object' && value !== null) {
// 安全地使用 value as JSONSchema7
processSchema(value as JSONSchema7);
}
}
}- 使用小写字母和下划线:
read_file、multi_edit - MCP 工具使用前缀:
mcp__server__tool
description: {
short: '简短描述(1行)',
long: '详细说明(可选)',
usageNotes: [
'使用说明1',
'使用说明2'
],
important: [
'重要提示1',
'重要提示2'
]
}return {
success: true,
llmContent: data, // 给 LLM 的结构化数据
displayContent: message, // 给用户的友好消息
metadata: { // 元数据(可选)
timestamp: Date.now(),
// ...
}
};每个工具应包含 formatDisplayMessage 辅助函数:
function formatDisplayMessage(
path: string,
metadata: Record<string, unknown>
): string {
// 构建用户友好的消息
return `✅ 操作成功: ${path}`;
}- 完善工具单元测试
- 添加工具性能监控
- 实现工具执行管道
- 支持更多 MCP 服务器
- 实现工具权限系统
- 添加工具缓存机制
- 构建工具市场
- 提供工具开发 SDK
- 建立工具生态系统