Skip to content

🛠️ 聊天工具模块

聊天工具模块允许前端应用向后端 AI 应用传递工具定义,并在对话过程中动态调用这些工具。这为 AI 助手提供了强大的扩展能力,使其能够执行各种自定义操作。

📋 概述

工具模块的核心功能:

  • 工具定义: 在前端定义可供 AI 使用的工具
  • 工具传递: 将工具定义传递给后端 AI 应用
  • 动态调用: AI 在对话中根据需要调用相应工具
  • 结果处理: 处理工具执行结果并继续对话

🚀 快速开始

基础工具定义

ts
import { scp } from '@your-org/scp-sdk';

// 定义一个简单的计算器工具
const calculatorTool = {
  name: 'calculator',
  description: '执行基本的数学计算',
  parameters: {
    type: 'object',
    properties: {
      expression: {
        type: 'string',
        description: '要计算的数学表达式,例如: "2 + 3 * 4"'
      }
    },
    required: ['expression']
  },
  handler: async (params: { expression: string }) => {
    try {
      // 安全的数学表达式计算
      const result = eval(params.expression);
      return {
        success: true,
        result: result,
        message: `计算结果: ${params.expression} = ${result}`
      };
    } catch (error) {
      return {
        success: false,
        error: '无效的数学表达式',
        message: '请提供有效的数学表达式'
      };
    }
  }
};

// 注册工具到聊天模块
scp.chat.registerTool(calculatorTool);

🔧 工具定义规范

工具结构

每个工具必须包含以下属性:

ts
interface ChatTool {
  name: string;                    // 工具名称(唯一标识)
  description: string;             // 工具描述(AI 用于理解工具用途)
  parameters: JSONSchema;          // 参数模式定义
  handler: ToolHandler;            // 工具执行函数
  category?: string;               // 工具分类(可选)
  version?: string;                // 工具版本(可选)
}

interface ToolHandler {
  (params: any): Promise<ToolResult> | ToolResult;
}

interface ToolResult {
  success: boolean;
  result?: any;
  error?: string;
  message?: string;
  data?: any;
}

参数模式定义

使用 JSON Schema 定义工具参数:

ts
// 简单参数
const simpleParameters = {
  type: 'object',
  properties: {
    message: {
      type: 'string',
      description: '要发送的消息内容'
    }
  },
  required: ['message']
};

// 复杂参数
const complexParameters = {
  type: 'object',
  properties: {
    user: {
      type: 'object',
      properties: {
        id: { type: 'string' },
        name: { type: 'string' },
        email: { type: 'string', format: 'email' }
      },
      required: ['id', 'name']
    },
    options: {
      type: 'object',
      properties: {
        priority: { 
          type: 'string', 
          enum: ['low', 'medium', 'high'],
          default: 'medium'
        },
        tags: {
          type: 'array',
          items: { type: 'string' }
        }
      }
    }
  },
  required: ['user']
};

🛠️ 常用工具示例

1. 文件操作工具

ts
const fileOperationTool = {
  name: 'file_operations',
  description: '执行文件相关操作,如读取、写入、删除文件',
  parameters: {
    type: 'object',
    properties: {
      operation: {
        type: 'string',
        enum: ['read', 'write', 'delete', 'list'],
        description: '要执行的操作类型'
      },
      path: {
        type: 'string',
        description: '文件或目录路径'
      },
      content: {
        type: 'string',
        description: '写入文件时的内容(仅在 operation 为 write 时需要)'
      }
    },
    required: ['operation', 'path']
  },
  handler: async (params) => {
    const { operation, path, content } = params;
    
    try {
      switch (operation) {
        case 'read':
          const fileContent = await readFile(path);
          return {
            success: true,
            result: fileContent,
            message: `成功读取文件: ${path}`
          };
          
        case 'write':
          await writeFile(path, content);
          return {
            success: true,
            message: `成功写入文件: ${path}`
          };
          
        case 'delete':
          await deleteFile(path);
          return {
            success: true,
            message: `成功删除文件: ${path}`
          };
          
        case 'list':
          const files = await listFiles(path);
          return {
            success: true,
            result: files,
            message: `目录 ${path} 包含 ${files.length} 个文件`
          };
          
        default:
          return {
            success: false,
            error: '不支持的操作类型'
          };
      }
    } catch (error) {
      return {
        success: false,
        error: error.message,
        message: `文件操作失败: ${error.message}`
      };
    }
  }
};

2. API 调用工具

ts
const apiCallTool = {
  name: 'api_request',
  description: '发起 HTTP API 请求',
  parameters: {
    type: 'object',
    properties: {
      url: {
        type: 'string',
        format: 'uri',
        description: 'API 请求的 URL'
      },
      method: {
        type: 'string',
        enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
        default: 'GET',
        description: 'HTTP 请求方法'
      },
      headers: {
        type: 'object',
        description: '请求头'
      },
      body: {
        type: 'object',
        description: '请求体数据'
      }
    },
    required: ['url']
  },
  handler: async (params) => {
    const { url, method = 'GET', headers = {}, body } = params;
    
    try {
      const response = await fetch(url, {
        method,
        headers: {
          'Content-Type': 'application/json',
          ...headers
        },
        body: body ? JSON.stringify(body) : undefined
      });
      
      const data = await response.json();
      
      return {
        success: response.ok,
        result: data,
        message: `API 请求${response.ok ? '成功' : '失败'}: ${response.status}`
      };
    } catch (error) {
      return {
        success: false,
        error: error.message,
        message: `API 请求失败: ${error.message}`
      };
    }
  }
};

3. 数据库查询工具

ts
const databaseTool = {
  name: 'database_query',
  description: '执行数据库查询操作',
  parameters: {
    type: 'object',
    properties: {
      query: {
        type: 'string',
        description: 'SQL 查询语句'
      },
      params: {
        type: 'array',
        items: { type: 'string' },
        description: '查询参数'
      }
    },
    required: ['query']
  },
  handler: async (params) => {
    const { query, params: queryParams = [] } = params;
    
    try {
      // 这里应该使用你的数据库连接
      const result = await executeQuery(query, queryParams);
      
      return {
        success: true,
        result: result,
        message: `查询成功,返回 ${result.length} 条记录`
      };
    } catch (error) {
      return {
        success: false,
        error: error.message,
        message: `数据库查询失败: ${error.message}`
      };
    }
  }
};

🔄 前端到后端工具传递

1. 工具注册与传递

ts
// 前端工具注册
class ChatToolManager {
  private tools: Map<string, ChatTool> = new Map();
  
  // 注册工具
  registerTool(tool: ChatTool) {
    this.tools.set(tool.name, tool);
    
    // 将工具定义发送给后端
    this.sendToolDefinitionToBackend(tool);
  }
  
  // 向后端发送工具定义
  private async sendToolDefinitionToBackend(tool: ChatTool) {
    const toolDefinition = {
      name: tool.name,
      description: tool.description,
      parameters: tool.parameters,
      category: tool.category,
      version: tool.version
    };
    
    try {
      await scp.api.post('/chat/tools/register', {
        tool: toolDefinition
      });
      
      console.log(`工具 ${tool.name} 已注册到后端`);
    } catch (error) {
      console.error(`工具注册失败: ${error.message}`);
    }
  }
  
  // 执行工具调用
  async executeTool(toolName: string, params: any): Promise<ToolResult> {
    const tool = this.tools.get(toolName);
    
    if (!tool) {
      return {
        success: false,
        error: `工具 ${toolName} 未找到`
      };
    }
    
    try {
      const result = await tool.handler(params);
      return result;
    } catch (error) {
      return {
        success: false,
        error: error.message,
        message: `工具执行失败: ${error.message}`
      };
    }
  }
}

// 全局工具管理器实例
const toolManager = new ChatToolManager();

// SCP 聊天模块扩展
scp.chat.registerTool = (tool: ChatTool) => {
  toolManager.registerTool(tool);
};

scp.chat.executeTool = (toolName: string, params: any) => {
  return toolManager.executeTool(toolName, params);
};

2. 聊天会话中的工具集成

ts
// 启动聊天会话时传递工具列表
const startChatSession = async () => {
  const sessionConfig = {
    sessionId: generateSessionId(),
    userId: getCurrentUserId(),
    // 传递可用工具列表
    availableTools: Array.from(toolManager.tools.keys()),
    // 工具执行回调
    onToolCall: async (toolName: string, params: any) => {
      const result = await toolManager.executeTool(toolName, params);
      return result;
    }
  };
  
  const session = await scp.chat.createSession(sessionConfig);
  return session;
};

3. WebSocket 工具调用处理

ts
// WebSocket 消息处理
scp.chat.onMessage((message) => {
  if (message.type === 'tool_call') {
    const { toolName, params, callId } = message.data;
    
    // 执行工具调用
    toolManager.executeTool(toolName, params)
      .then(result => {
        // 将结果发送回后端
        scp.chat.sendMessage({
          type: 'tool_result',
          data: {
            callId,
            result
          }
        });
      })
      .catch(error => {
        // 发送错误结果
        scp.chat.sendMessage({
          type: 'tool_result',
          data: {
            callId,
            result: {
              success: false,
              error: error.message
            }
          }
        });
      });
  }
});

💬 对话中的工具使用

1. AI 工具调用流程

mermaid
sequenceDiagram
    participant User as 用户
    participant Frontend as 前端应用
    participant Backend as 后端 AI
    participant Tool as 工具处理器
    
    User->>Frontend: 发送消息
    Frontend->>Backend: 转发消息 + 可用工具列表
    Backend->>Backend: AI 分析是否需要使用工具
    Backend->>Frontend: 发送工具调用请求
    Frontend->>Tool: 执行工具
    Tool->>Frontend: 返回执行结果
    Frontend->>Backend: 发送工具执行结果
    Backend->>Frontend: 基于工具结果生成回复
    Frontend->>User: 显示 AI 回复

2. 工具调用示例对话

ts
// 用户消息: "帮我计算 15 * 23 + 7 的结果"

// AI 分析后决定使用计算器工具
const toolCall = {
  type: 'tool_call',
  data: {
    toolName: 'calculator',
    params: {
      expression: '15 * 23 + 7'
    },
    callId: 'call_123456'
  }
};

// 前端执行工具并返回结果
const toolResult = {
  type: 'tool_result',
  data: {
    callId: 'call_123456',
    result: {
      success: true,
      result: 352,
      message: '计算结果: 15 * 23 + 7 = 352'
    }
  }
};

// AI 基于工具结果生成最终回复
const aiResponse = {
  type: 'message',
  data: {
    content: '根据计算,15 × 23 + 7 = 352。计算过程是:先算乘法 15 × 23 = 345,然后加上 7,最终结果是 352。',
    toolCalls: [
      {
        toolName: 'calculator',
        params: { expression: '15 * 23 + 7' },
        result: 352
      }
    ]
  }
};

3. 多工具协作

ts
// 复杂场景:AI 需要查询数据库然后发送邮件
// 用户消息: "给所有 VIP 用户发送促销邮件"

// 第一步:查询 VIP 用户
const step1 = {
  type: 'tool_call',
  data: {
    toolName: 'database_query',
    params: {
      query: 'SELECT email, name FROM users WHERE user_type = ?',
      params: ['VIP']
    },
    callId: 'call_001'
  }
};

// 第二步:基于查询结果发送邮件
const step2 = {
  type: 'tool_call',
  data: {
    toolName: 'send_email',
    params: {
      recipients: ['user1@example.com', 'user2@example.com'], // 从第一步获取
      subject: '专属VIP促销活动',
      template: 'vip_promotion',
      data: {
        promotionCode: 'VIP2024',
        discount: '30%'
      }
    },
    callId: 'call_002'
  }
};

🎯 高级特性

1. 工具权限控制

ts
interface ToolPermission {
  userId?: string;
  roles?: string[];
  permissions?: string[];
  restrictions?: {
    maxCallsPerHour?: number;
    allowedParams?: string[];
    deniedParams?: string[];
  };
}

const restrictedTool = {
  name: 'admin_operations',
  description: '管理员操作工具',
  permissions: {
    roles: ['admin', 'super_admin'],
    restrictions: {
      maxCallsPerHour: 10
    }
  },
  parameters: {
    type: 'object',
    properties: {
      operation: {
        type: 'string',
        enum: ['delete_user', 'modify_permissions', 'system_backup']
      }
    }
  },
  handler: async (params, context) => {
    // 检查权限
    if (!context.user.roles.includes('admin')) {
      return {
        success: false,
        error: '权限不足',
        message: '此操作需要管理员权限'
      };
    }
    
    // 执行操作
    // ...
  }
};

2. 工具链式调用

ts
const workflowTool = {
  name: 'data_analysis_workflow',
  description: '数据分析工作流',
  parameters: {
    type: 'object',
    properties: {
      dataSource: { type: 'string' },
      analysisType: { type: 'string' }
    }
  },
  handler: async (params) => {
    const workflow = [
      { tool: 'data_fetch', params: { source: params.dataSource } },
      { tool: 'data_clean', params: { method: 'standard' } },
      { tool: 'data_analyze', params: { type: params.analysisType } },
      { tool: 'generate_report', params: { format: 'pdf' } }
    ];
    
    let results = [];
    let previousResult = null;
    
    for (const step of workflow) {
      const result = await scp.chat.executeTool(step.tool, {
        ...step.params,
        previousResult
      });
      
      if (!result.success) {
        return {
          success: false,
          error: `工作流在步骤 ${step.tool} 失败`,
          partialResults: results
        };
      }
      
      results.push(result);
      previousResult = result.result;
    }
    
    return {
      success: true,
      result: results,
      message: '数据分析工作流执行完成'
    };
  }
};

3. 实时工具状态

ts
// 长时间运行的工具支持进度回调
const longRunningTool = {
  name: 'batch_process',
  description: '批量处理工具',
  parameters: {
    type: 'object',
    properties: {
      items: {
        type: 'array',
        items: { type: 'string' }
      }
    }
  },
  handler: async (params, context) => {
    const { items } = params;
    const total = items.length;
    let processed = 0;
    
    // 发送初始状态
    context.sendProgress({
      status: 'running',
      progress: 0,
      message: `开始处理 ${total} 个项目`
    });
    
    const results = [];
    
    for (const item of items) {
      // 处理单个项目
      const result = await processItem(item);
      results.push(result);
      processed++;
      
      // 发送进度更新
      context.sendProgress({
        status: 'running',
        progress: (processed / total) * 100,
        message: `已处理 ${processed}/${total} 个项目`
      });
    }
    
    // 发送完成状态
    context.sendProgress({
      status: 'completed',
      progress: 100,
      message: '批量处理完成'
    });
    
    return {
      success: true,
      result: results,
      message: `成功处理 ${processed} 个项目`
    };
  }
};

📚 最佳实践

1. 工具设计原则

ts
// ✅ 好的工具设计
const goodTool = {
  name: 'user_search',
  description: '根据条件搜索用户。支持按姓名、邮箱、用户类型等条件查询用户信息。',
  parameters: {
    type: 'object',
    properties: {
      query: {
        type: 'string',
        description: '搜索关键词,可以是姓名或邮箱的一部分'
      },
      userType: {
        type: 'string',
        enum: ['regular', 'vip', 'admin'],
        description: '用户类型筛选'
      },
      limit: {
        type: 'integer',
        minimum: 1,
        maximum: 100,
        default: 10,
        description: '返回结果数量限制'
      }
    },
    required: ['query']
  },
  handler: async (params) => {
    // 参数验证
    if (!params.query || params.query.trim().length < 2) {
      return {
        success: false,
        error: '搜索关键词至少需要2个字符'
      };
    }
    
    try {
      const users = await searchUsers(params);
      return {
        success: true,
        result: users,
        message: `找到 ${users.length} 个匹配的用户`
      };
    } catch (error) {
      return {
        success: false,
        error: error.message,
        message: '用户搜索失败'
      };
    }
  }
};

// ❌ 不好的工具设计
const badTool = {
  name: 'do_stuff',  // 名称不明确
  description: '做一些事情',  // 描述不清楚
  parameters: {
    type: 'object',
    properties: {
      data: { type: 'any' }  // 参数类型不明确
    }
  },
  handler: async (params) => {

    // 没有错误处理,返回格式不一致
    return someFunction(params.data);
  }
};

2. 错误处理策略

ts
// 统一的错误处理包装器
function withErrorHandling(handler: ToolHandler): ToolHandler {
  return async (params, context) => {
    try {
      const result = await handler(params, context);
      return result;
    } catch (error) {
      console.error('工具执行错误:', error);
      
      return {
        success: false,
        error: error.message,
        message: '工具执行过程中发生错误',
        errorCode: error.code || 'UNKNOWN_ERROR'
      };
    }
  };
}

// 使用错误处理包装器
const safeApiTool = {
  name: 'safe_api_call',
  description: '安全的 API 调用工具',
  parameters: { /* ... */ },
  handler: withErrorHandling(async (params) => {
    // 可能抛出异常的代码
    const response = await fetch(params.url);
    const data = await response.json();
    
    return {
      success: true,
      result: data
    };
  })
};

3. 性能优化

ts
// 工具结果缓存
class ToolCache {
  private cache = new Map<string, { result: any; timestamp: number; ttl: number }>();
  
  getCacheKey(toolName: string, params: any): string {
    return `${toolName}:${JSON.stringify(params)}`;
  }
  
  get(toolName: string, params: any): any | null {
    const key = this.getCacheKey(toolName, params);
    const cached = this.cache.get(key);
    
    if (!cached) return null;
    
    if (Date.now() - cached.timestamp > cached.ttl) {
      this.cache.delete(key);
      return null;
    }
    
    return cached.result;
  }
  
  set(toolName: string, params: any, result: any, ttl: number = 300000) {
    const key = this.getCacheKey(toolName, params);
    this.cache.set(key, {
      result,
      timestamp: Date.now(),
      ttl
    });
  }
}

const toolCache = new ToolCache();

// 带缓存的工具包装器
function withCache(handler: ToolHandler, cacheTTL: number = 300000): ToolHandler {
  return async (params, context) => {
    const toolName = context.toolName;
    
    // 尝试从缓存获取
    const cached = toolCache.get(toolName, params);
    if (cached) {
      return {
        success: true,
        result: cached,
        message: '从缓存返回结果',
        cached: true
      };
    }
    
    // 执行工具
    const result = await handler(params, context);
    
    // 缓存成功结果
    if (result.success) {
      toolCache.set(toolName, params, result.result, cacheTTL);
    }
    
    return result;
  };
}

4. 工具测试

ts
// 工具测试框架
class ToolTester {
  async testTool(tool: ChatTool, testCases: Array<{
    name: string;
    params: any;
    expected: Partial<ToolResult>;
  }>) {
    const results = [];
    
    for (const testCase of testCases) {
      try {
        const result = await tool.handler(testCase.params);
        
        const passed = this.validateResult(result, testCase.expected);
        
        results.push({
          name: testCase.name,
          passed,
          result,
          expected: testCase.expected
        });
      } catch (error) {
        results.push({
          name: testCase.name,
          passed: false,
          error: error.message
        });
      }
    }
    
    return results;
  }
  
  private validateResult(actual: ToolResult, expected: Partial<ToolResult>): boolean {
    for (const [key, value] of Object.entries(expected)) {
      if (actual[key] !== value) {
        return false;
      }
    }
    return true;
  }
}

// 测试示例
const tester = new ToolTester();

const testResults = await tester.testTool(calculatorTool, [
  {
    name: '基本加法',
    params: { expression: '2 + 3' },
    expected: { success: true, result: 5 }
  },
  {
    name: '复杂表达式',
    params: { expression: '(10 + 5) * 2' },
    expected: { success: true, result: 30 }
  },
  {
    name: '无效表达式',
    params: { expression: 'invalid' },
    expected: { success: false }
  }
]);

🐛 常见问题与解决方案

Q1: 工具调用超时怎么办?

A: 实现超时处理机制:

ts
function withTimeout(handler: ToolHandler, timeoutMs: number = 30000): ToolHandler {
  return async (params, context) => {
    return Promise.race([
      handler(params, context),
      new Promise<ToolResult>((_, reject) => {
        setTimeout(() => {
          reject(new Error(`工具执行超时 (${timeoutMs}ms)`));
        }, timeoutMs);
      })
    ]);
  };
}

Q2: 如何处理工具权限验证?

A: 在工具处理器中添加权限检查:

ts
const secureHandler = async (params, context) => {
  // 权限检查
  if (!context.user.hasPermission('tool:execute')) {
    return {
      success: false,
      error: 'PERMISSION_DENIED',
      message: '没有执行此工具的权限'
    };
  }
  
  // 执行工具逻辑
  // ...
};

Q3: 工具参数验证失败?

A: 使用 JSON Schema 验证器:

ts
import Ajv from 'ajv';

const ajv = new Ajv();

function validateParams(params: any, schema: any): { valid: boolean; errors?: string[] } {
  const validate = ajv.compile(schema);
  const valid = validate(params);
  
  if (!valid) {
    return {
      valid: false,
      errors: validate.errors?.map(err => `${err.instancePath} ${err.message}`)
    };
  }
  
  return { valid: true };
}

Q4: 如何调试工具执行?

A: 添加详细的日志记录:

ts
const debugTool = {
  name: 'debug_example',
  handler: async (params, context) => {
    console.log('工具开始执行:', {
      toolName: context.toolName,
      params,
      userId: context.user.id,
      timestamp: new Date().toISOString()
    });
    
    try {
      const result = await actualHandler(params);
      
      console.log('工具执行成功:', {
        toolName: context.toolName,
        result,
        duration: Date.now() - context.startTime
      });
      
      return result;
    } catch (error) {
      console.error('工具执行失败:', {
        
toolName: context.toolName,
        error: error.message,
        stack: error.stack,
        params
      });
      
      throw error;
    }
  }
};

🔗 与其他框架的集成

AG-UI 风格集成

ts
// 参考 AG-UI 的工具定义模式
const agStyleTool = {
  name: 'data_visualization',
  description: '创建数据可视化图表',
  category: 'visualization',
  icon: 'chart-bar',
  parameters: {
    type: 'object',
    properties: {
      data: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            label: { type: 'string' },
            value: { type: 'number' }
          }
        }
      },
      chartType: {
        type: 'string',
        enum: ['bar', 'line', 'pie', 'scatter'],
        default: 'bar'
      },
      title: { type: 'string' },
      theme: {
        type: 'string',
        enum: ['light', 'dark'],
        default: 'light'
      }
    },
    required: ['data']
  },
  handler: async (params) => {
    const chart = await generateChart(params);
    
    return {
      success: true,
      result: {
        chartUrl: chart.url,
        chartId: chart.id,
        metadata: {
          type: params.chartType,
          dataPoints: params.data.length,
          theme: params.theme
        }
      },
      message: `成功创建 ${params.chartType} 图表`,
      // AG-UI 风格的 UI 组件返回
      ui: {
        type: 'chart',
        props: {
          data: params.data,
          type: params.chartType,
          title: params.title,
          theme: params.theme
        }
      }
    };
  }
};

CopilotKit 风格集成

ts
// 参考 CopilotKit 的 Action 模式
const copilotStyleAction = {
  name: 'create_document',
  description: '创建新文档',
  parameters: {
    type: 'object',
    properties: {
      title: {
        type: 'string',
        description: '文档标题'
      },
      content: {
        type: 'string',
        description: '文档内容'
      },
      template: {
        type: 'string',
        enum: ['blank', 'report', 'proposal', 'memo'],
        description: '文档模板'
      }
    },
    required: ['title', 'content']
  },
  handler: async (params, context) => {
    // CopilotKit 风格的状态更新
    context.updateState('document.creating', true);
    
    try {
      const document = await createDocument({
        title: params.title,
        content: params.content,
        template: params.template || 'blank',
        userId: context.user.id
      });
      
      // 更新应用状态
      context.updateState('documents', (prev) => [...prev, document]);
      context.updateState('document.creating', false);
      
      return {
        success: true,
        result: document,
        message: `文档 "${params.title}" 创建成功`,
        // CopilotKit 风格的 UI 更新
        uiUpdates: [
          {
            type: 'navigate',
            path: `/documents/${document.id}`
          },
          {
            type: 'notification',
            message: '文档创建成功',
            type: 'success'
          }
        ]
      };
    } catch (error) {
      context.updateState('document.creating', false);
      throw error;
    }
  }
};

📖 相关文档

🎯 总结

聊天工具模块为 AI 助手提供了强大的扩展能力,通过合理的工具设计和集成,可以让 AI 助手执行各种复杂的操作。关键要点:

  1. 清晰的工具定义: 明确的名称、描述和参数规范
  2. 可靠的错误处理: 统一的错误处理和用户友好的错误信息
  3. 安全的权限控制: 适当的权限验证和访问控制
  4. 高效的性能优化: 缓存、超时处理和资源管理
  5. 完善的测试覆盖: 全面的测试用例和调试工具

通过遵循这些最佳实践,你可以创建出强大、可靠且用户友好的 AI 工具集成系统。

Released under the MIT License.