Skip to main content

概述

AssistantChat 组件是 LangChat 应用中 AI 助手对话界面的核心入口。它采用原子化设计(Atomic Design),具备高度灵活性,支持多种布局模式(simple, conversation, simple-mode)和集成场景(App, Workflow, Share, Draw.io 等)。

目录结构

组件遵循原子化设计原则:
  • atoms/: 基础 UI 构建块(如消息气泡原子组件)
  • molecules/: 分子组件,由原子组合而成(消息列表 MessageList、输入区域 ChatInputArea、简单模型选择器 SimpleModelSelector
  • organisms/: 组织组件,复杂的功能单元(聊天面板 ChatPanel、会话侧边栏 ConversationSidebar
  • templates/: 模板组件,定义页面级布局
    • SimpleChat.vue: 基础简单布局(用于 App/Workflow 调试)
    • ConversationChat.vue: 完整会话布局(带侧边栏历史记录)
    • SimpleLayoutChat.vue: 极简模式布局(带模型选择,用于特定工具场景如 Draw.io)
  • composables/: 共享逻辑和状态管理
    • useChat.ts: 核心聊天逻辑(用于标准和会话模式)
    • useSimpleChat.ts: 简化版聊天逻辑(用于极简模式,直接调用 /aigc/simple
    • useConversations.ts: 会话列表管理

核心组件与布局

1. Templates (布局模板)

  • SimpleChat: 无侧边栏,直接展示聊天面板。适用于应用内部调试或嵌入式简单对话。
  • ConversationChat: 包含左侧会话历史侧边栏。适用于主应用界面、分享页面等需要管理多轮会话的场景。
  • SimpleLayoutChat (New): 极简布局,支持在输入框左下角直接选择推理模型,不需要复杂的助手配置。适用于单一工具场景(如 Text-to-SQL 调试、Draw.io 绘图助手)。

2. State Management (状态管理)

  • ChatService: 统一的服务层,负责根据 Assistant 类型选择正确的 API 端点。
  • Store Integration: 深度集成 useMessagesStoreuseConversationsStore 进行状态持久化。

Data Flow (数据流)

  1. 初始化: AssistantChat 接收 assistant 对象和 layout 配置。
  2. 布局路由: index.vue 根据 layout 属性(auto, conversation, simple, simple-mode)渲染对应的 Template。
  3. 聊天交互:
    • 用户在 ChatInputArea 输入消息。
    • SimpleModelSelector (仅 simple-mode) 允许切换模型。
    • Composable (useChatuseSimpleChat) 处理发送逻辑。
    • 后端流式响应通过 SSE 返回,实时更新 MessageList

使用文档与场景示例

Props 定义

属性类型默认值说明
assistantAssistantRequired助手配置对象,包含 ID、名称、指令等
layout'auto' | 'conversation' | 'simple' | 'simple-mode''auto'布局模式
conversationIdstringundefined指定会话 ID,simplesimple-mode 模式下建议传入
titlestringundefined标题(仅 simple-mode 支持顶部展示)
apiKeystringundefined用于分享页面的 API Key

Layout 场景介绍

1. Conversation Mode (完整会话模式)

适用场景: 标准的 AI 助手应用,需要保存历史会话记录,支持新建会话、切换会话。 特点: 左侧带有会话列表侧边栏。
<template>
  <AssistantChat
    :assistant="assistantConfig"
    layout="conversation"
  />
</template>

2. Simple Mode (简单模式)

适用场景: 应用内的临时调试、或者不需要历史记录管理的嵌入式聊天。 特点: 仅展示聊天窗口,使用助手配置中默认的模型。
<template>
  <AssistantChat
    :assistant="assistantConfig"
    layout="simple"
    conversation-id="debug-session-001"
  />
</template>

3. Simple Mode with Model Selector (极简模式 - 带模型选择)

适用场景: 独立的工具页面(如 Draw.io 插件、Text-to-SQL 生成器),用户可能需要临时切换不同的推理模型来对比效果,但不涉及复杂的助手配置(如知识库、插件等)。 特点:
  • 界面极简。
  • 输入框左下角提供模型选择器
  • 支持传入 title 显示顶部标题。
  • 使用 useSimpleChat 逻辑,直接调用 /aigc/simple 接口。
<template>
  <AssistantChat
    :assistant="{
      id: 'drawio-helper',
      name: 'Draw.io 助手',
      type: 'app',
      instruction: '你是一个画图助手...'
    }"
    layout="simple-mode"
    title="AI 绘图助手"
    conversation-id="drawio-session"
  />
</template>

最佳实践

  1. Draw.io / 工具集成: 使用 simple-mode。由于这些场景通常需要特定的 System Prompt(如生成特定 XML 格式),可以将 Prompt 放在 assistant.instruction 中传入。useSimpleChat 会将其作为 promptText 发送给后端。
  2. 自动布局: 如果不确定使用哪种布局,可以设置 layout="auto"(默认)。组件会根据 assistant.chat.conversation.showHistory 的配置自动决定使用 conversation 还是 simple 布局。
  3. 消息监听与后处理: 在父组件中,可以通过 useMessagesStore 监听消息变化,从而实现对 AI 响应的后处理(例如提取代码块、自动执行操作)。
    // 示例:监听消息并提取 XML
    const messages = computed(() => messagesStore.getMessages(conversationId));
    watch(messages, (newVal) => {
      const lastMsg = newVal[newVal.length - 1];
      if (lastMsg?.role === 'ai' && !lastMsg.loading) {
        // 处理完成的消息...
      }
    });
    

第二部分:Chat 接口调用架构设计

本章节详细描述聊天消息从用户输入到后端 API 调用的完整数据流,以及相关的服务层和状态管理设计。

整体架构图

┌─────────────────────────────────────────────────────────────────────────────┐
│                           AssistantChat 组件层                               │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────────────────┐  │
│  │  ChatInputArea  │  │   MessageList   │  │  ConversationSidebar        │  │
│  │  (用户输入)      │  │   (消息展示)     │  │  (会话管理)                  │  │
│  └────────┬────────┘  └────────▲────────┘  └──────────────▲──────────────┘  │
│           │                    │                          │                  │
└───────────┼────────────────────┼──────────────────────────┼──────────────────┘
            │                    │                          │
            ▼                    │                          │
┌───────────────────────────────────────────────────────────────────────────────┐
│                           Composables 逻辑层                                   │
│  ┌──────────────────────────────────────────────────────────────────────────┐ │
│  │                          useChat.ts / useSimpleChat.ts                   │ │
│  │  - 处理发送消息逻辑                                                        │ │
│  │  - 管理 loading 状态                                                      │ │
│  │  - 处理 SSE 流式响应                                                      │ │
│  │  - 调用 ChatService.sendMessage()                                        │ │
│  └──────────────────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────────────┘


┌───────────────────────────────────────────────────────────────────────────────┐
│                           Services 服务层                                      │
│  ┌─────────────────────────┐  ┌─────────────────────────────────────────────┐ │
│  │    AssistantService     │  │              ChatService                    │ │
│  │  - adaptAppToAssistant  │  │  - sendMessage(assistant, message, options) │ │
│  │  - 将 AigcApp 转换为     │  │  - buildParams() 构建请求参数               │ │
│  │    AppAssistant 类型    │  │  - getApiUrl() 选择 API 端点                │ │
│  └─────────────────────────┘  └─────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────────────┘


┌───────────────────────────────────────────────────────────────────────────────┐
│                           Stores 状态层                                        │
│  ┌─────────────────────┐  ┌─────────────────────┐  ┌───────────────────────┐  │
│  │  useMessagesStore   │  │ useConversationsStore│ │  useSuggestionsStore  │  │
│  │  - messages Map     │  │  - activeConvId     │  │  - suggestions[]      │  │
│  │  - addMessage()     │  │  - conversationCache│  │  - setSuggestions()   │  │
│  │  - updateMessage()  │  │  - setActiveConv()  │  │                       │  │
│  └─────────────────────┘  └─────────────────────┘  └───────────────────────┘  │
└───────────────────────────────────────────────────────────────────────────────┘


┌───────────────────────────────────────────────────────────────────────────────┐
│                           API 请求层                                           │
│  ┌──────────────────────────────────────────────────────────────────────────┐ │
│  │                    createChatStream() (SSE 流式请求)                      │ │
│  │  - POST /aigc/chat/completions (App)                                     │ │
│  │  - POST /aigc/flow/chat/completions (Workflow)                           │ │
│  │  - POST /aigc/mcp/chat/completions (MCP)                                 │ │
│  │  - POST /aigc/share/chat/completions (Share)                             │ │
│  └──────────────────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────────────┘

Services 服务层详解

1. ChatService (services/assistant/ChatService.ts)

ChatService 是聊天功能的核心服务类,负责统一的 API 调用逻辑。 主要职责:
  • 根据 Assistant 类型选择正确的 API 端点
  • 构建请求参数(包含 modelId、modelConfig、appId 等)
  • 发起 SSE 流式请求
核心方法:
// 发送消息(自动根据助手类型选择 API)
static async sendMessage(
  assistant: Assistant,
  message: Message,
  options?: SendMessageOptions,
): Promise<AsyncIterable<StreamEvent>>

// 构建请求参数
private static buildParams(
  assistant: Assistant,
  message: Message,
  options?: SendMessageOptions,
): any

// 根据助手类型选择 API URL
private static getApiUrl(type: AssistantType, apiKey?: string): ChatApiType
请求参数结构(以 App 类型为例):
{
  message: string,           // 用户消息内容
  conversationId: string,    // 会话 ID
  appStatus: string,         // 应用状态 (DRAFT/PUBLISHED)
  chatId: string,            // 本次聊天唯一 ID (UUID)
  appId: string,             // 应用 ID
  modelId: string,           // 模型 ID
  modelConfig: {             // 模型配置
    temperature: number,
    maxTokens: number,
    topP: number,
    responseFormat: string,
    // ...其他配置
  },
  appType: 'app',
  // ...其他 extra 参数
}

2. AssistantService (services/assistant/AssistantService.ts)

AssistantService 负责 Assistant 类型的适配和转换。 主要职责:
  • 将后端返回的 AigcApp 数据转换为前端使用的 AppAssistant 类型
  • 处理模型配置(modelId、modelConfig)的映射
核心方法:
// 将 AigcApp 适配为 AppAssistant
static adaptAppToAssistant(app: AigcApp): AppAssistant {
  return {
    id: app.id,
    name: app.name,
    type: AssistantType.App,
    status: app.status,
    model: {
      id: app.modelId,
      config: app.modelConfig,  // 模型配置在此映射
    },
    // ...其他属性
  };
}

Stores 状态层详解

1. useMessagesStore (stores/messages/useMessagesStore.ts)

管理所有会话的消息列表。 数据结构:
interface State {
  messages: Map<string, Message[]>;  // conversationId -> messages
}
核心方法:
  • getMessages(conversationId): 获取指定会话的消息列表
  • addMessage(conversationId, message): 添加消息
  • updateMessage(conversationId, messageId, updates): 更新消息
  • appendMessageContent(conversationId, messageId, content): 追加消息内容(用于流式响应)
  • loadMessages(conversationId): 从后端加载历史消息

2. useConversationsStore (stores/conversations/useConversationsStore.ts)

管理会话状态和缓存。 数据结构:
interface State {
  activeConversationId: string | null;  // 当前激活的会话 ID
  conversationCache: Map<string, Conversation>;  // 会话缓存
}
核心方法:
  • setActiveConversation(id): 设置当前会话
  • clearActiveConversation(): 清除当前会话
  • getConversation(id): 获取会话详情

3. useSuggestionsStore (stores/suggestions/useSuggestionsStore.ts)

管理 AI 推荐的后续问题(猜你想问)。 核心方法:
  • setSuggestions(suggestions): 设置推荐问题列表
  • clearSuggestions(): 清除推荐问题

Composables 逻辑层详解

useChat.ts (composables/useChat.ts)

核心聊天逻辑封装,处理完整的消息发送流程。 主要职责:
  • 管理 loading 状态
  • 构建 Message 对象
  • 调用 ChatService.sendMessage()
  • 处理 SSE 流式响应事件
  • 更新消息内容和状态
核心流程:
async function send(content: string, attachments?: Attachment[]) {
  // 1. 检查内容有效性
  if (!content.trim() && !attachments?.length) return;

  // 2. 创建用户消息
  const userMessage = createUserMessage(content, attachments);
  messagesStore.addMessage(conversationId, userMessage);

  // 3. 创建 AI 消息占位
  const aiMessage = createAiMessage();
  messagesStore.addMessage(conversationId, aiMessage);

  // 4. 构建请求参数
  const extra = {
    attachments: attachments?.map(a => a.file),
    // ...其他参数
  };

  // 5. 发送请求并处理流式响应
  const stream = await ChatService.sendMessage(assistant, message, {
    conversationId,
    extra,
    signal: abortController.signal,
  });

  // 6. 处理 SSE 事件
  for await (const event of stream) {
    switch (event.type) {
      case StreamEventType.CONTENT:
        messagesStore.appendMessageContent(conversationId, aiMessage.id, event.data);
        break;
      case StreamEventType.COMPLETE:
        messagesStore.updateMessage(conversationId, aiMessage.id, { loading: false });
        break;
      case StreamEventType.ERROR:
        handleError(event.data);
        break;
      // ...处理其他事件类型
    }
  }
}

消息发送完整流程

以用户在 App 类型助手中发送消息为例:
1. 用户在 ChatInputArea 输入消息并点击发送

2. ChatInputArea 触发 @send 事件

3. ChatPanel 调用 useChat.send(content, attachments)

4. useChat 创建 userMessage 和 aiMessage,添加到 messagesStore

5. useChat 调用 ChatService.sendMessage(assistant, message, options)

6. ChatService.buildParams() 构建请求参数:
   {
     message: "用户输入的内容",
     conversationId: "xxx",
     appId: assistant.id,
     modelId: assistant.model.id,
     modelConfig: assistant.model.config,  // 包含 temperature、maxTokens 等
     appType: "app",
     chatId: uuid(),
   }

7. ChatService.getApiUrl() 选择 API: CHAT_API ("/aigc/chat/completions")

8. createChatStream() 发起 SSE POST 请求

9. 后端返回流式响应,useChat 处理 StreamEvent:
   - CONTENT: 追加消息内容
   - TOOL_CALL: 显示工具调用
   - WORKFLOW_LOG: 显示工作流日志
   - METADATA: 显示知识库引用
   - SUGGESTIONS: 设置推荐问题
   - COMPLETE: 标记消息完成

10. 消息展示在 MessageList 中

第三部分:扩展指南

添加自定义 Chat 请求参数

如果需要向后端传递额外的聊天参数,请按以下步骤修改:

场景 1:从 Assistant 配置中传递参数

如果参数来自助手配置(如 modelConfig),在 ChatService.buildParams() 中添加:
// services/assistant/ChatService.ts

private static buildParams(assistant, message, options) {
  if (assistant.type === AssistantType.App) {
    const appAssistant = assistant as AppAssistant;
    return {
      ...baseParams,
      appId: appAssistant.id,
      modelId: appAssistant.model?.id,
      modelConfig: appAssistant.model?.config,
      // 添加新参数
      myCustomParam: appAssistant.myCustomField,
    };
  }
}

场景 2:从发送时动态传递参数

如果参数在发送消息时动态确定,通过 options.extra 传递:
// composables/useChat.ts

const extra = {
  attachments: attachments?.map(a => a.file),
  // 添加新参数
  myDynamicParam: someValue,
};

const stream = await ChatService.sendMessage(assistant, message, {
  conversationId,
  extra,  // extra 会被展开到请求参数中
  signal: abortController.signal,
});

场景 3:修改 Assistant 类型定义

如果需要在 Assistant 中添加新字段:
  1. 修改类型定义 (types/assistant.ts):
export interface AppAssistant extends BaseAssistant {
  // ...
  myNewField?: string;
}
  1. 修改适配器 (services/assistant/AssistantService.ts):
static adaptAppToAssistant(app: AigcApp): AppAssistant {
  return {
    // ...
    myNewField: app.myNewField,
  };
}

添加新的 Assistant 类型

  1. AssistantType 枚举中添加新类型
  2. ChatService.getApiUrl() 中添加新的 API 映射
  3. ChatService.buildParams() 中添加新类型的参数构建逻辑
  4. AssistantService 中添加适配器方法

添加新的 StreamEvent 类型

  1. types/streamEvents.ts 中添加新的事件类型
  2. useChat.ts 的事件处理 switch 中添加新的 case 处理逻辑