跳转到主要内容
将TypeScript/JavaScript函数转换为AI可访问的工具,自动生成模式并保持类型安全。这是创建自定义工具最直接的方式。

简单函数

基础函数工具

从简单函数创建工具:
import { tool } from '@ag-kit/tools';
import { z } from 'zod';

const addNumbersTool = tool(
  async ({ a, b }) => {
    return ToolResult({
      success: true,
      data: { result: a + b }
    });
  },
  {
    name: 'add_numbers',
    description: 'Add two numbers together',
    schema: z.object({
      a: z.number().describe('First number'),
      b: z.number().describe('Second number')
    })
  }
);

文本处理工具

创建文本处理工具:
const textProcessTool = tool(
  async ({ text, operation, options = {} }) => {
    let processedText = text;

    if (options.trim) {
      processedText = processedText.trim();
    }

    if (options.removeSpaces) {
      processedText = processedText.replace(/\s+/g, '');
    }

    let result;
    switch (operation) {
      case 'uppercase':
        result = processedText.toUpperCase();
        break;
      case 'lowercase':
        result = processedText.toLowerCase();
        break;
      case 'reverse':
        result = processedText.split('').reverse().join('');
        break;
      case 'word_count':
        result = processedText.split(/\s+/).length;
        break;
    }

    return ToolResult({
      success: true,
      data: {
        original: text,
        processed: result,
        operation
      }
    });
  },
  {
    name: 'process_text',
    description: 'Process text with various operations',
    schema: z.object({
      text: z.string().describe('Input text'),
      operation: z.enum(['uppercase', 'lowercase', 'reverse', 'word_count']),
      options: z.object({
        trim: z.boolean().default(true),
        removeSpaces: z.boolean().default(false)
      }).optional()
    })
  }
);

异步操作

HTTP请求工具

创建发起HTTP请求的工具:
const httpRequestTool = tool({
  name: 'http_request',
  description: 'Make HTTP requests to external APIs',
  schema: z.object({
    url: z.string().url(),
    method: z.enum(['GET', 'POST', 'PUT', 'DELETE']).default('GET'),
    headers: z.record(z.string()).optional(),
    body: z.any().optional(),
    timeout: z.number().default(30000)
  }),
  invoke: async ({ url, method, headers, body, timeout }) => {
    try {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), timeout);

      const response = await fetch(url, {
        method,
        headers: {
          'Content-Type': 'application/json',
          ...headers
        },
        body: body ? JSON.stringify(body) : undefined,
        signal: controller.signal
      });

      clearTimeout(timeoutId);

      if (!response.ok) {
        return ToolResult({
          success: false,
          error: `HTTP ${response.status}: ${response.statusText}`,
          error_type: 'network'
        });
      }

      const data = await response.json();

      return ToolResult({
        success: true,
        data: {
          status: response.status,
          headers: Object.fromEntries(response.headers.entries()),
          body: data
        }
      });
    } catch (error) {
      if (error.name === 'AbortError') {
        return ToolResult({
          success: false,
          error: 'Request timeout',
          error_type: 'network'
        });
      }

      return ToolResult({
        success: false,
        error: error.message,
        error_type: 'execution'
      });
    }
  }
});

复杂参数

验证与转换

创建具有复杂验证的工具:
const userManagementTool = tool({
  name: 'manage_user',
  description: '通过验证管理用户账户',
  schema: z.object({
    action: z.enum(['create', 'update', 'delete', 'get']),
    userId: z.string().uuid().optional(),
    userData: z.object({
      email: z.string().email(),
      name: z.string().min(2).max(50),
      age: z.number().min(13).max(120),
      roles: z.array(z.enum(['admin', 'user', 'moderator'])).default(['user']),
      preferences: z.object({
        theme: z.enum(['light', 'dark']).default('light'),
        notifications: z.boolean().default(true),
        language: z.string().length(2).default('en')
      }).optional()
    }).optional()
  }).refine(
    (data) => {
      if (data.action === 'create' && !data.userData) {
        return false;
      }
      if (['update', 'delete', 'get'].includes(data.action) && !data.userId) {
        return false;
      }
      return true;
    },
    {
      message: '创建操作需要userData,更新/删除/获取操作需要userId'
    }
  ),
  invoke: async ({ action, userId, userData }) => {
    try {
      switch (action) {
        case 'create':
          const newUser = {
            id: crypto.randomUUID(),
            ...userData,
            createdAt: new Date().toISOString()
          };
          
          // 模拟数据库保存
          await saveUser(newUser);
          
          return ToolResult({
            success: true,
            data: { user: newUser, message: '用户创建成功' }
          });
          
        case 'update':
          const existingUser = await getUser(userId);
          if (!existingUser) {
            return ToolResult({
              success: false,
              error: '用户未找到',
              error_type: 'execution'
            });
          }
          
          const updatedUser = {
            ...existingUser,
            ...userData,
            updatedAt: new Date().toISOString()
          };
          
          await saveUser(updatedUser);
          
          return ToolResult({
            success: true,
            data: { user: updatedUser, message: '用户更新成功' }
          });
          
        case 'delete':
          await deleteUser(userId);
          return ToolResult({
            success: true,
            data: { message: '用户删除成功' }
          });
          
        case 'get':
          const user = await getUser(userId);
          if (!user) {
            return ToolResult({
              success: false,
              error: '用户未找到',
              error_type: 'execution'
            });
          }
          
          return ToolResult({
            success: true,
            data: { user }
          });
          
        default:
          return ToolResult({
            success: false,
            error: '无效操作',
            error_type: 'validation'
          });
      }
    } catch (error) {
      return ToolResult({
        success: false,
        error: error.message,
        error_type: 'execution'
      });
    }
  }
});

// 模拟数据库函数
async function saveUser(user: any) {
  // 实现代码
}

async function getUser(userId: string) {
  // 实现代码
}

async function deleteUser(userId: string) {
  // 实现代码
}

错误处理

全面的错误处理

实现健壮的错误处理模式:
const robustApiTool = tool({
  name: 'robust_api_call',
  description: '通过全面的错误处理进行API调用',
  schema: z.object({
    endpoint: z.string().url(),
    retries: z.number().min(0).max(5).default(3),
    backoffMs: z.number().min(100).max(10000).default(1000)
  }),
  invoke: async ({ endpoint, retries, backoffMs }) => {
    let lastError: Error | null = null;
    
    for (let attempt = 0; attempt <= retries; attempt++) {
      try {
        const response = await fetch(endpoint, {
          timeout: 10000,
          headers: {
            'User-Agent': 'AG-Kit Tool/1.0'
          }
        });
        
        if (!response.ok) {
          throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        
        const data = await response.json();
        
        return ToolResult({
          success: true,
          data: {
            result: data,
            attempts: attempt + 1,
            endpoint
          }
        });
        
      } catch (error) {
        lastError = error;
        
        // 特定错误不重试
        if (error.message.includes('404') || error.message.includes('401')) {
          break;
        }
        
        // 重试前等待(指数退避)
        if (attempt < retries) {
          const delay = backoffMs * Math.pow(2, attempt);
          await new Promise(resolve => setTimeout(resolve, delay));
        }
      }
    }
    
    return new ToolResult({
      success: false,
      error: `经过${retries + 1}次尝试后失败: ${lastError?.message}`,
      error_type: 'network',
      executionTime: Date.now()
    });
  }
});

输入净化

对输入进行净化和验证:
const sanitizedInputTool = tool({
  name: 'process_user_input',
  description: '对用户输入进行净化处理',
  schema: z.object({
    userInput: z.string(),
    allowHtml: z.boolean().default(false),
    maxLength: z.number().default(1000)
  }),
  invoke: async ({ userInput, allowHtml, maxLength }) => {
    try {
      // 长度验证
      if (userInput.length > maxLength) {
        return ToolResult({
          success: false,
          error: `输入过长(最多${maxLength}个字符)`,
          error_type: 'validation'
        });
      }
      
      // 净化输入
      let sanitized = userInput.trim();
      
      if (!allowHtml) {
        // 移除HTML标签
        sanitized = sanitized.replace(/<[^>]*>/g, '');
        
        // 转义特殊字符
        sanitized = sanitized
          .replace(/&/g, '&amp;')
          .replace(/</g, '&lt;')
          .replace(/>/g, '&gt;')
          .replace(/"/g, '&quot;')
          .replace(/'/g, '&#x27;');
      }
      
      // 检查可疑模式
      const suspiciousPatterns = [
        /javascript:/i,
        /data:text\/html/i,
        /vbscript:/i,
        /<script/i
      ];
      
      const hasSuspiciousContent = suspiciousPatterns.some(
        pattern => pattern.test(sanitized)
      );
      
      if (hasSuspiciousContent) {
        return ToolResult({
          success: false,
          error: '输入包含可疑内容',
          error_type: 'validation'
        });
      }
      
      return ToolResult({
        success: true,
        data: {
          original: userInput,
          sanitized,
          length: sanitized.length,
          wasModified: userInput !== sanitized
        }
      });
      
    } catch (error) {
      return ToolResult({
        success: false,
        error: error.message,
        error_type: 'execution'
      });
    }
  }
});

集成模式

工具组合

组合多个功能工具:
// 创建独立工具
const validateEmailTool = tool({
  name: 'validate_email',
  description: '验证电子邮件地址格式',
  schema: z.object({
    email: z.string()
  }),
  invoke: async ({ email }) => {
    const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
    return ToolResult({
      success: true,
      data: { email, isValid }
    });
  }
});

const sendEmailTool = tool({
  name: 'send_email',
  description: '发送电子邮件',
  schema: z.object({
    to: z.string().email(),
    subject: z.string(),
    body: z.string()
  }),
  invoke: async ({ to, subject, body }) => {
    // 邮件发送逻辑
    return ToolResult({
      success: true,
      data: { messageId: 'msg_123', sentAt: new Date().toISOString() }
    });
  }
});

// 组合工具
const emailWorkflowTool = tool({
  name: 'email_workflow',
  description: '一次性完成电子邮件验证和发送',
  schema: z.object({
    to: z.string(),
    subject: z.string(),
    body: z.string()
  }),
  invoke: async ({ to, subject, body }) => {
    // 先验证电子邮件
    const validationResult = await validateEmailTool.invoke({ email: to });
    
    if (!validationResult.success || !validationResult.data.isValid) {
      return ToolResult({
        success: false,
        error: '无效的电子邮件地址',
        error_type: 'validation'
      });
    }
    
    // 发送邮件
    const sendResult = await sendEmailTool.invoke({ to, subject, body });
    
    return ToolResult({
      success: sendResult.success,
      data: {
        validation: validationResult.data,
        email: sendResult.data
      },
      error: sendResult.error,
      error_type: sendResult.error_type
    });
  }
});

与Agent配合使用

将功能工具与AG-Kit agent结合使用:
import { Agent, OpenAIProvider } from '@ag-kit/agents';

const agent = new Agent({
  name: 'multi-tool-agent',
  model: new OpenAIProvider({
    apiKey: process.env.OPENAI_API_KEY!,
    defaultModel: 'gpt-4'
  }),
  tools: [
    addNumbersTool,
    textProcessTool,
    httpRequestTool,
    userManagementTool
  ],
  instructions: `您是一个拥有多种工具的有用助手:
- 数学运算
- 文本处理
- HTTP请求
- 用户管理

使用这些工具帮助用户完成任务。`
});

const response = await agent.run({
  input: '计算15加27,然后将结果转换为大写文本'
});

缓存实现

为耗时操作实现缓存:
const cache = new Map();

const cachedApiTool = tool({
  name: 'cached_api_call',
  description: 'API call with caching',
  schema: z.object({
    url: z.string().url(),
    cacheTtl: z.number().default(300000) // 5分钟
  }),
  invoke: async ({ url, cacheTtl }) => {
    const cached = cache.get(url);
    
    if (cached && Date.now() - cached.timestamp < cacheTtl) {
      return ToolResult({
        success: true,
        data: { ...cached.data, fromCache: true }
      });
    }
    
    try {
      const response = await fetch(url);
      const data = await response.json();
      
      cache.set(url, {
        data,
        timestamp: Date.now()
      });
      
      return ToolResult({
        success: true,
        data: { ...data, fromCache: false }
      });
    } catch (error) {
      return ToolResult({
        success: false,
        error: error.message,
        error_type: 'network'
      });
    }
  }
});

后续步骤