SSF0SSF0
首页
前端
  • Node
  • Go
  • Python
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
  • 开源项目
Timeline
Github
标签
分类
首页
前端
  • Node
  • Go
  • Python
  • MySql
  • Bash
  • Git
  • Docker
  • VuePress
  • CI/CD
  • 服务器
  • 网站
  • 学习资料
  • 软件
  • 开源项目
Timeline
Github
标签
分类
  • Node.js

    • 在 Docker 容器中运行 Node.js Koa 应用的网络配置与常见问题
    • 在 Node.js 后端实现邮箱验证码功能
    • Redis 与 JWT 结合的 Token 验证方案
    • Node.js 后端三层架构中的错误处理最佳实践
    • 在 Koa 中批量设置路由 JWT 校验的最佳实践
    • 前端开发者的 Redis 入门指南
    • AI工具系统架构设计
    • Koa 项目中间件设计技巧与最佳实践
  • Go

    • Go1
    • Go2
  • Python

    • Python 项目 API 代理转发:解决跨平台外网访问难题
  • MySql

    • 数据库连接

AI 工具系统架构设计:基于 OpenAI 的工具注入与调用实现

前言

在现代 AI 应用中,工具调用(Tool Calling)是一个核心功能,它允许 AI 模型调用外部函数来完成特定任务。本文将深入分析一个基于 OpenAI 的工具系统实现,该系统采用了依赖注入、处理器模式等设计模式,提供了完整的工具管理和调用能力。

系统架构概览

核心组件关系图

AI工具系统架构设计

三层架构设计

  1. AI 服务层(OpenAIService): 负责与 OpenAI API 通信和响应处理

  2. 工具管理层(ToolService): 管理工具处理器和调用分发

  3. 工具处理层(ToolHandlers): 实现具体的工具业务逻辑

AI 服务层实现

服务接口设计

/**
 * AI服务接口
 * 定义所有AI服务提供商必须实现的方法
 */
export interface IAIService {
  /**
   * 创建聊天完成
   */
  createChatCompletion(request: IOpenAIRequest): Promise<any>;

  /**
   * 创建流式聊天完成
   */
  createChatCompletionStream(request: IOpenAIRequest): Promise<any>;
}

设计优势:

  • 多态支持:可以轻松切换不同的 AI 服务提供商

  • 接口隔离:客户端只依赖接口,不依赖具体实现

  • 扩展性强:新增 AI 服务商只需实现接口即可

OpenAI 服务实现

export class OpenAIService implements IAIService {
  /**
   * 依赖注入OpenAI客户端
   */
  constructor(private client = openaiClient) {
    logger.info("OpenAI服务已初始化");
  }

  async createChatCompletion(request: IOpenAIRequest & { userId: string }) {
    try {
      // 1. 调用OpenAI API,注入工具定义
      const response = await this.client.chat.completions.create({
        model: request.model,
        messages: request.messages,
        temperature: request.temperature,
        max_tokens: request.max_tokens,
        top_p: request.top_p,
        frequency_penalty: request.frequency_penalty,
        presence_penalty: request.presence_penalty,
        tools: recordTools, // 注入可用工具
      });

      // 2. 检查并处理工具调用
      if (response.choices[0].message?.tool_calls) {
        const toolResults = await toolService.processToolCalls(
          response.choices[0].message.tool_calls,
          { userId: request.userId }
        );

        // 3. 增强响应内容
        const originalMessage = response.choices[0].message;
        const successfulRecords = toolResults.filter((r) => r.success);

        if (successfulRecords.length > 0) {
          const content = originalMessage.content || "";
          const recordInfo =
            "\n\n【系统通知】已将以下内容添加到您的时间轴:\n" +
            successfulRecords.map((r) => `- ${r.content}`).join("\n");

          response.choices[0].message.content = content + recordInfo;
        }
      }

      return response;
    } catch (error) {
      logger.error("OpenAI API请求失败", error);
      throw new Error("与OpenAI通信失败");
    }
  }
}

关键特性分析

1. 工具注入机制

tools: recordTools; // 将工具定义注入到OpenAI请求中

这里的 recordTools 是预定义的工具配置,告诉 OpenAI 可以调用哪些函数。

2. 工具调用检测

if (response.choices[0].message?.tool_calls) {
  // 检测到工具调用,进行处理
}

OpenAI 会在需要时返回 tool_calls 数组,包含需要执行的工具信息。

3. 响应增强

系统会在 AI 的原始回复后添加工具执行结果的通知,提升用户体验。

工具管理层设计

ToolService 核心架构

export class ToolService {
  private handlers: IToolHandler[] = [];

  constructor() {
    // 注册所有工具处理器
    this.handlers.push(new RecordToolHandler());
    // 支持动态添加更多处理器
  }

  async processToolCalls(toolCalls: any[], context: any): Promise<any[]> {
    const results = [];

    for (const toolCall of toolCalls) {
      const toolName = toolCall.function.name;
      const handler = this.handlers.find((h) => h.canHandle(toolName));

      if (handler) {
        const result = await handler.handleToolCall(toolCall, context);
        results.push(result);
      } else {
        results.push({
          success: false,
          message: `未找到工具 ${toolName} 的处理器`,
        });
      }
    }

    return results;
  }
}

设计模式分析

1. 策略模式(Strategy Pattern)

每个工具处理器实现相同的接口,可以动态选择处理策略:

export interface IToolHandler {
  handleToolCall(toolCall: any, context: any): Promise<any>;
  canHandle(toolName: string): boolean;
}

2. 责任链模式(Chain of Responsibility)

通过 find() 方法查找能处理特定工具的处理器,实现了责任链的变种。

3. 工厂模式(Factory Pattern)

ToolService 充当工具处理器的工厂,根据工具名称创建对应的处理实例。

OpenAI 工具调用参数详解

tool_calls 数据结构

当 OpenAI 检测到需要调用工具时,会在响应中返回如下结构:

// OpenAI 返回的 tool_calls 示例
{
  choices: [
    {
      message: {
        tool_calls: [
          {
            index: 0,
            id: "call_abc123",
            type: "function",
            function: {
              name: "record",
              arguments: '{"content": "用户今天学习了AI工具调用"}',
            },
          },
        ],
      },
    },
  ];
}

参数字段说明

字段类型说明
indexnumber工具调用在数组中的索引
idstring唯一标识符,用于跟踪调用
typestring调用类型,通常为 "function"
function.namestring要调用的函数名称
function.argumentsstringJSON 字符串格式的函数参数

参数解析流程

async handleToolCall(toolCall: any, context: any): Promise<any> {
  try {
    // 1. 解析JSON参数
    const args = JSON.parse(toolCall.function.arguments);

    // 2. 参数验证
    if (!args.content) {
      return {
        success: false,
        message: "记录缺少内容参数",
      };
    }

    // 3. 获取上下文信息
    const userId = context.userId;

    // 4. 执行业务逻辑
    const result = await TimeLineService.addTimeline({
      userId: parseInt(userId),
      content: args.content,
      createdAt: new Date(),
      updatedAt: new Date(),
    });

    // 5. 返回执行结果
    return {
      success: true,
      message: "记录已添加到时间轴",
      content: args.content,
    };
  } catch (err) {
    logger.error("处理record工具调用失败", err);
    return {
      success: false,
      message: "添加时间轴记录失败",
    };
  }
}

工具处理器实现

处理器接口设计

export interface IToolHandler {
  /**
   * 处理工具调用
   * @param toolCall OpenAI返回的工具调用对象
   * @param context 执行上下文(用户ID等)
   * @returns 处理结果
   */
  handleToolCall(toolCall: any, context: any): Promise<any>;

  /**
   * 判断是否能处理指定工具
   * @param toolName 工具名称
   * @returns 是否支持处理
   */
  canHandle(toolName: string): boolean;
}

RecordToolHandler 实现解析

export class RecordToolHandler implements IToolHandler {
  canHandle(toolName: string): boolean {
    return toolName === "record";
  }

  async handleToolCall(toolCall: any, context: any): Promise<any> {
    try {
      // 参数解析
      const args = JSON.parse(toolCall.function.arguments);

      // 业务逻辑执行
      const timeline = await TimeLineService.addTimeline({
        userId: parseInt(context.userId),
        content: args.content,
        createdAt: new Date(),
        updatedAt: new Date(),
      });

      // 成功响应
      return {
        success: true,
        message: "记录已添加到时间轴",
        content: args.content,
      };
    } catch (err) {
      // 错误处理
      return {
        success: false,
        message: "添加时间轴记录失败",
      };
    }
  }
}

完整执行流程

1. 工具调用时序图

AI工具系统架构设计

2. 详细执行步骤

  1. 用户发送消息:用户向 AI 发送包含可能需要工具调用的消息

  2. AI 分析需求:OpenAI 分析消息内容,判断是否需要调用工具

  3. 返回工具调用:如需要,OpenAI 返回 tool_calls 数组

  4. 工具服务处理:ToolService 遍历所有工具调用

  5. 查找处理器:根据工具名称查找对应的处理器

  6. 执行工具逻辑:处理器执行具体的业务逻辑

  7. 收集结果:汇总所有工具执行结果

  8. 响应增强:在 AI 回复中添加工具执行通知

  9. 返回用户:将增强后的响应返回给用户

扩展新工具的标准流程

1. 创建工具处理器

export class NewToolHandler implements IToolHandler {
  canHandle(toolName: string): boolean {
    return toolName === "new_tool";
  }

  async handleToolCall(toolCall: any, context: any): Promise<any> {
    try {
      const args = JSON.parse(toolCall.function.arguments);

      // 实现具体业务逻辑
      const result = await SomeService.processNewTool(args, context);

      return {
        success: true,
        message: "新工具执行成功",
        data: result,
      };
    } catch (error) {
      return {
        success: false,
        message: "新工具执行失败",
      };
    }
  }
}

2. 注册工具处理器

constructor() {
  this.handlers.push(new RecordToolHandler());
  this.handlers.push(new NewToolHandler()); // 添加新的处理器
}

3. 定义工具配置

export const newTools = [
  {
    type: "function",
    function: {
      name: "new_tool",
      description: "新工具的描述",
      parameters: {
        type: "object",
        properties: {
          param1: {
            type: "string",
            description: "参数1的描述",
          },
        },
        required: ["param1"],
      },
    },
  },
];

错误处理与监控

1. 多层错误处理

// OpenAI Service 层
try {
  const response = await this.client.chat.completions.create(params);
} catch (error) {
  logger.error("OpenAI API请求失败", error);
  throw new Error("与OpenAI通信失败");
}

// Tool Service 层
if (handler) {
  const result = await handler.handleToolCall(toolCall, context);
} else {
  results.push({
    success: false,
    message: `未找到工具 ${toolName} 的处理器`,
  });
}

// Handler 层
try {
  // 业务逻辑
} catch (err) {
  logger.error("处理工具调用失败", err);
  return { success: false, message: "执行失败" };
}

2. 日志监控

系统在关键节点都加入了详细的日志记录:

  • 工具调用开始:记录工具名称和参数

  • 执行结果:记录成功/失败状态

  • 错误详情:记录具体错误信息和堆栈

总结

这个 AI 工具系统的设计具有以下优势:

架构优势

  1. 松耦合设计:各层之间通过接口交互,降低耦合度

  2. 高可扩展性:新增工具只需实现接口并注册

  3. 统一管理:工具调用统一由 ToolService 管理

  4. 错误隔离:单个工具失败不影响其他工具

技术亮点

  1. 依赖注入:便于测试和替换实现

  2. 策略模式:灵活的工具处理策略

  3. 完善的错误处理:多层错误处理和日志记录

  4. 响应增强:提升用户体验的智能通知

应用场景

  • 企业 AI 助手:需要调用内部系统 API

  • 个人助理应用:集成日程、笔记等功能

  • 客服机器人:调用订单、库存等业务系统

  • 内容管理平台:自动化内容处理和发布

这种架构为构建功能丰富的 AI 应用提供了坚实的基础,既保证了系统的稳定性,又具备了良好的扩展能力。

最后更新时间:
贡献者: 何风顺
上一页
前端开发者的 Redis 入门指南
下一页
Koa 项目中间件设计技巧与最佳实践