Skip to content

工具开发

工具是场景的核心能力,定义了 AI 可以执行的操作。

工具定义

typescript
interface ScenarioToolDefinition {
  /** 工具名称(唯一标识) */
  name: string

  /** 工具定义 */
  definition: {
    name: string
    description: string
    descriptionZh?: string
    parameters: {
      type: string
      properties: Record<string, ToolParameter>
      required?: string[]
    }
  }

  /** 工具执行器 */
  executor: ToolExecutor
}

参数定义

typescript
interface ToolParameter {
  type: 'string' | 'number' | 'boolean' | 'array' | 'object'
  description: string
  descriptionZh?: string
  required?: boolean
  default?: unknown
  enum?: string[]
  items?: ToolParameter  // 用于 array 类型
  properties?: Record<string, ToolParameter>  // 用于 object 类型
}

执行器

typescript
type ToolExecutor = (
  args: Record<string, unknown>,
  context: ToolExecutionContext,
) => Promise<ToolExecutionResult>

interface ToolExecutionContext {
  scenarioId: string
  workspacePath: string
  logger: ScenarioLogger
  publishData: (channel: string, data: unknown) => void
  getSharedData: (key: string) => unknown
  querySql: (query: string) => Promise<ScenarioSqlResult>
}

interface ToolExecutionResult {
  success: boolean
  data?: unknown
  error?: string
}

开发示例

简单工具

typescript
{
  name: 'get_current_time',
  definition: {
    name: 'get_current_time',
    description: '获取当前时间',
    descriptionZh: '获取当前系统时间',
    parameters: {
      type: 'object',
      properties: {
        timezone: {
          type: 'string',
          description: '时区',
          descriptionZh: '时区,如 Asia/Shanghai',
          default: 'Asia/Shanghai',
        },
        format: {
          type: 'string',
          description: '时间格式',
          descriptionZh: '时间格式',
          enum: ['iso', 'readable', 'timestamp'],
          default: 'readable',
        },
      },
    },
  },
  executor: async (args) => {
    const now = new Date()
    const { format } = args

    switch (format) {
      case 'iso':
        return { success: true, data: now.toISOString() }
      case 'timestamp':
        return { success: true, data: now.getTime() }
      default:
        return { success: true, data: now.toLocaleString('zh-CN') }
    }
  },
}

数据库操作工具

typescript
{
  name: 'query_tasks',
  definition: {
    name: 'query_tasks',
    description: '查询任务列表',
    descriptionZh: '查询任务列表',
    parameters: {
      type: 'object',
      properties: {
        status: {
          type: 'string',
          description: '按状态筛选',
          descriptionZh: '按状态筛选',
          enum: ['pending', 'in_progress', 'completed'],
        },
        limit: {
          type: 'number',
          description: '最大结果数',
          descriptionZh: '最大返回数量',
          default: 20,
        },
      },
    },
  },
  executor: async (args, context) => {
    try {
      const { status, limit = 20 } = args
      let query = 'SELECT * FROM tasks'
      const conditions: string[] = []

      if (status) {
        conditions.push(`status = '${status}'`)
      }

      if (conditions.length > 0) {
        query += ' WHERE ' + conditions.join(' AND ')
      }

      query += ` ORDER BY created_at DESC LIMIT ${limit}`

      const result = await context.querySql(query)
      return {
        success: true,
        data: result.data,
        total: result.data.length,
      }
    } catch (error) {
      context.logger.error('查询任务失败', error)
      return {
        success: false,
        error: `查询失败: ${error instanceof Error ? error.message : '未知错误'}`,
      }
    }
  },
}

外部 API 调用工具

typescript
{
  name: 'fetch_news',
  definition: {
    name: 'fetch_news',
    description: '获取最新新闻',
    descriptionZh: '获取最新新闻',
    parameters: {
      type: 'object',
      properties: {
        category: {
          type: 'string',
          description: '新闻分类',
          descriptionZh: '新闻分类',
          enum: ['technology', 'business', 'science', 'health'],
        },
        count: {
          type: 'number',
          description: '新闻数量',
          descriptionZh: '获取数量',
          default: 5,
        },
      },
      required: ['category'],
    },
  },
  executor: async (args, context) => {
    try {
      const { category, count = 5 } = args
      const response = await fetch(
        `https://api.example.com/news?category=${category}&limit=${count}`,
        {
          headers: { 'Authorization': `Bearer ${context.getSharedData('api_key')}` },
        },
      )

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`)
      }

      const data = await response.json()
      return { success: true, data: data.articles }
    } catch (error) {
      context.logger.error('获取新闻失败', error)
      return {
        success: false,
        error: `获取失败: ${error instanceof Error ? error.message : '未知错误'}`,
      }
    }
  },
}

工具注册

工具的 getTools() 返回所有工具定义:

typescript
getTools(): ScenarioToolDefinition[] {
  return [
    tool1,
    tool2,
    tool3,
  ]
}

最佳实践

  1. 命名规范:使用 snake_case,清晰描述功能
  2. 参数校验:在 executor 内部校验参数
  3. 错误处理:始终捕获异常,返回有意义的错误
  4. 日志记录:记录关键操作和错误
  5. 超时控制:长时间操作设置超时
  6. 幂等性:尽量保证操作幂等
  7. 返回结构化数据:便于 AI 理解和处理

AweeClaw AI 应用构建平台