Skip to content

Manager 模式

为什么需要 Manager

在 AI 小鲸 v2.0 的架构中,我们引入了 Manager 模式来解决组件层日益增长的复杂性问题。Manager 模式的核心理念是:

  • 关注点分离:将业务逻辑从 Vue 组件中抽离,组件只负责渲染,Manager 负责业务编排
  • 可测试性:Manager 是纯 TypeScript 类,不依赖 Vue 运行时,可以轻松编写单元测试
  • 可扩展性:通过依赖注入和面向接口编程,新增功能只需添加新的 Manager,无需修改已有代码

Manager 总览

v2.0 内置了 6 个核心 Manager,各司其职:

Manager职责依赖
ComponentManagerUI 状态管理 + 事件协调中心
ChatBusinessManager消息发送、停止生成、流式处理agentModulesessionModule
SessionBusinessManager会话的创建、读取、更新、删除sessionModulemessageModuleagentModule
ShortcutManager快捷指令的注册与管理agentModule
UIStateManager选择模式、编辑模式等 UI 状态
ShareBusinessManager分享流程编排messageModulesessionModule

职责说明

  • ComponentManager 是整个 Manager 体系的协调中心,负责管理组件级别的 UI 状态(如加载态、错误态),同时作为内部事件总线,协调各 Manager 之间的通信。
  • ChatBusinessManager 封装了与 AI 对话相关的所有业务逻辑,包括消息发送、流式响应处理、停止生成等操作。
  • SessionBusinessManager 管理会话的完整生命周期,包括会话列表加载、新建会话、切换会话、删除会话等。
  • ShortcutManager 负责快捷指令的注册、查询和执行,支持自定义指令扩展。
  • UIStateManager 管理与用户交互相关的 UI 状态,如消息选择模式、文本编辑模式等。
  • ShareBusinessManager 编排消息分享的完整流程,包括选择消息、生成分享链接、复制内容等。

Manager 创建模式

所有 Manager 都通过依赖注入的方式创建,在组件初始化时由 useChatBootstrap 或手动方式完成实例化:

typescript
import { ComponentManager, ChatBusinessManager, SessionBusinessManager } from '@blueking/ai-blueking';

// 1. 创建无依赖的基础 Manager
const componentManager = new ComponentManager();

// 2. 创建依赖底层模块的业务 Manager
const chatManager = new ChatBusinessManager(
  chatHelper.agent,    // agentModule - 提供 AI 代理交互能力
  chatHelper.session,  // sessionModule - 提供会话上下文
  chatbotInit          // 初始化配置
);

// 3. 创建需要多个模块的 Manager
const sessionManager = new SessionBusinessManager(
  chatHelper.session,  // sessionModule
  chatHelper.message,  // messageModule
  chatHelper.agent,    // agentModule
  {
    enableChatSession: true  // 启用多会话管理
  }
);

依赖关系图

Manager 依赖关系图

自定义 Manager 扩展

当内置 Manager 无法满足需求时,你可以创建自定义 Manager 并注册到体系中。

步骤一:定义自定义 Manager

typescript
import { BaseManager } from '@blueking/ai-blueking';

export class AnalyticsManager extends BaseManager {
  private trackingId: string;

  constructor(trackingId: string) {
    super();
    this.trackingId = trackingId;
  }

  // 追踪消息发送事件
  trackMessageSent(content: string) {
    console.log(`[${this.trackingId}] 消息已发送: ${content.substring(0, 50)}...`);
    // 上报到分析平台
  }

  // 追踪会话切换事件
  trackSessionSwitch(sessionCode: string) {
    console.log(`[${this.trackingId}] 会话切换: ${sessionCode}`);
  }

  dispose() {
    // 清理资源
  }
}

步骤二:注册到 ComponentManager

typescript
const analyticsManager = new AnalyticsManager('my-app-001');

// 注册到 ComponentManager,使其参与事件协调
componentManager.register('analytics', analyticsManager);

// 在事件中使用
componentManager.on('send-message', (content: string) => {
  analyticsManager.trackMessageSent(content);
});

componentManager.on('session-switch', (code: string) => {
  analyticsManager.trackSessionSwitch(code);
});

步骤三:在组件中使用

typescript
// 通过 provide/inject 在组件树中共享
provide('analyticsManager', analyticsManager);

// 子组件中获取
const analytics = inject<AnalyticsManager>('analyticsManager');

副作用处理原则

Manager 模式的一个核心原则是:所有副作用都由 Manager 处理,组件保持纯渲染

什么是副作用?

  • API 调用(发送消息、加载会话列表等)
  • 状态变更(修改全局状态、更新缓存等)
  • 浏览器 API 调用(localStorage、clipboard 等)
  • 定时器和订阅管理

正确做法

typescript
// ✅ 组件只负责渲染和用户交互转发
const ChatInput = defineComponent({
  setup() {
    const chatManager = inject<ChatBusinessManager>('chatManager');

    const handleSend = (content: string) => {
      // 将用户操作委托给 Manager
      chatManager.sendMessage(content);
    };

    return { handleSend };
  },
});

// ✅ Manager 处理所有副作用
class ChatBusinessManager {
  async sendMessage(content: string) {
    // 副作用:更新状态
    this.setLoading(true);
    try {
      // 副作用:API 调用
      await this.agentModule.chat(content, this.sessionCode);
      // 副作用:触发事件
      this.emit('message-sent', content);
    } catch (error) {
      // 副作用:错误处理
      this.handleError(error);
    } finally {
      this.setLoading(false);
    }
  }
}

错误做法

typescript
// ❌ 不要在组件中直接处理副作用
const ChatInput = defineComponent({
  setup() {
    const handleSend = async (content: string) => {
      // 错误:组件内直接发起 API 调用
      const response = await fetch('/api/chat', {
        method: 'POST',
        body: JSON.stringify({ content }),
      });
      // 错误:组件内直接操作 DOM / 全局状态
      document.title = '新消息...';
    };

    return { handleSend };
  },
});

遵循这一原则,可以确保组件的可复用性和可测试性,同时让业务逻辑的维护和调试变得更加简单。

All Rights Reserved. 腾讯蓝鲸 版权所有