365 lines
17 KiB
Markdown
365 lines
17 KiB
Markdown
|
|
# AI 智能助手功能 — 面试版
|
|||
|
|
|
|||
|
|
> 简历原话:**"集成 @matechat/core 实现 AI 智能助手功能,支持多轮对话、思考过程展示、组件化消息渲染(软件详情/预警列表/智能推荐)"**
|
|||
|
|
>
|
|||
|
|
> 这篇文档帮你理解这句话背后到底做了什么,以及面试时怎么讲。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、先搞清楚:这句话到底是什么意思?
|
|||
|
|
|
|||
|
|
拆成四部分理解:
|
|||
|
|
|
|||
|
|
| 关键词 | 含义 | 项目中对应 |
|
|||
|
|
|--------|------|------------|
|
|||
|
|
| **集成 @matechat/core** | 使用华为 MateChat 组件库提供聊天 UI | McBubble(气泡)、McInput(输入框)、McMarkdownCard(Markdown 渲染)等组件 |
|
|||
|
|
| **多轮对话** | 用户可以连续提问,AI 记住上下文 | 前端创建 conversationId,后端维护对话历史,每次请求带上 conversationId |
|
|||
|
|
| **思考过程展示** | AI 回答前展示它"想"了什么步骤 | 后端返回 states 对象,前端解析为"意图分析→SQL判断→SQL执行"步骤展示 |
|
|||
|
|
| **组件化消息渲染** | 不同类型的 AI 回答用不同组件展示 | 5 种消息类型:普通文本、开源软件列表、预警列表、软件详情、数据表格 |
|
|||
|
|
|
|||
|
|
**一句话概括**:我用 MateChat 组件库搭建了 AI 聊天界面,实现了多轮对话(9 个 API)、思考过程可视化、以及 5 种消息类型的组件化渲染。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、整体架构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────┐
|
|||
|
|
│ AI 助手页面(/ai) │
|
|||
|
|
│ │
|
|||
|
|
│ ┌──────────┐ ┌──────────────────────────────┐ │
|
|||
|
|
│ │ 左侧边栏 │ │ 对话区域 │ │
|
|||
|
|
│ │ │ │ ┌──────────────────────────┐ │ │
|
|||
|
|
│ │ 历史会话列表│ │ │ McBubble(用户消息) │ │ │
|
|||
|
|
│ │ 收藏会话 │ │ └──────────────────────────┘ │ │
|
|||
|
|
│ │ 搜索/删除 │ │ ┌──────────────────────────┐ │ │
|
|||
|
|
│ │ 批量管理 │ │ │ McBubble(AI回复) │ │ │
|
|||
|
|
│ │ │ │ │ ├── 思考过程(可折叠) │ │ │
|
|||
|
|
│ │ │ │ │ ├── OssList(软件列表) │ │ │
|
|||
|
|
│ │ │ │ │ ├── WarningList(预警列表) │ │ │
|
|||
|
|
│ │ │ │ │ ├── OssDetail(软件详情) │ │ │
|
|||
|
|
│ │ │ │ │ ├── AIList(数据表格) │ │ │
|
|||
|
|
│ │ │ │ │ └── Other(Markdown文本) │ │ │
|
|||
|
|
│ │ │ │ └──────────────────────────┘ │ │
|
|||
|
|
│ │ │ │ ┌──────────────────────────┐ │ │
|
|||
|
|
│ │ │ │ │ 猜你想问(推荐问题) │ │ │
|
|||
|
|
│ │ │ │ └──────────────────────────┘ │ │
|
|||
|
|
│ │ │ │ ┌──────────────────────────┐ │ │
|
|||
|
|
│ │ │ │ │ McInput(输入框) │ │ │
|
|||
|
|
│ │ │ │ └──────────────────────────┘ │ │
|
|||
|
|
│ └──────────┘ └──────────────────────────────┘ │
|
|||
|
|
└─────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、@matechat/core 用在了哪里?
|
|||
|
|
|
|||
|
|
MateChat 是华为开源的 AI 聊天 UI 组件库。项目中用了这些组件:
|
|||
|
|
|
|||
|
|
| 组件 | 用在哪 | 干什么 |
|
|||
|
|
|------|--------|--------|
|
|||
|
|
| `McBubble` | 对话区域 | 消息气泡(区分用户/AI,支持 loading 状态) |
|
|||
|
|
| `McInput` | 底部输入框 | 文本输入,支持字数限制、回车发送、清空 |
|
|||
|
|
| `McMarkdownCard` | AI 文本回复 | 渲染 Markdown 格式的 AI 回答 |
|
|||
|
|
| `McLayout` / `McLayoutContent` / `McLayoutSender` | 弹窗版 AI | KnowledgeHub 的 AI 弹窗布局 |
|
|||
|
|
|
|||
|
|
全局注册后直接使用:
|
|||
|
|
```typescript
|
|||
|
|
// main.ts
|
|||
|
|
import MateChat from '@matechat/core';
|
|||
|
|
app.use(MateChat);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```vue
|
|||
|
|
<!-- 直接用,不需要 import -->
|
|||
|
|
<McBubble :content="msg.content" :align="'right'" /> <!-- 用户消息靠右 -->
|
|||
|
|
<McBubble :loading="true"> <!-- AI 回复靠左 + loading -->
|
|||
|
|
<Other :content="msg.content" />
|
|||
|
|
</McBubble>
|
|||
|
|
<McInput @submit="onSubmit" /> <!-- 底部输入框 -->
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、怎么实现的?(面试核心)
|
|||
|
|
|
|||
|
|
### 4.1 多轮对话
|
|||
|
|
|
|||
|
|
**问题**:用户连续问多个问题,AI 要记住之前的对话内容。
|
|||
|
|
|
|||
|
|
**解决方案**:用 conversationId 串联整个对话,后端维护历史。
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
用户发第一条消息
|
|||
|
|
↓
|
|||
|
|
前端没有 conversationId → 调用 createConversation API → 获得 conversationId
|
|||
|
|
↓
|
|||
|
|
前端发送消息:{ userId, conversationId, question }
|
|||
|
|
↓
|
|||
|
|
后端根据 conversationId 找到历史消息 → AI 结合历史回答
|
|||
|
|
↓
|
|||
|
|
用户发第二条消息 → 带同一个 conversationId → 后端知道上下文
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 1. 首次对话:创建会话
|
|||
|
|
const CONV_ID = ref('');
|
|||
|
|
|
|||
|
|
const createConversation = async () => {
|
|||
|
|
const { data } = await fetchCreateConversation({ userId: username });
|
|||
|
|
CONV_ID.value = data.data.conversationId; // 保存会话 ID
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 2. 发送消息:带上 conversationId
|
|||
|
|
const getAIAnswer = async (question) => {
|
|||
|
|
const { data } = await fetchChatUseSql({
|
|||
|
|
userId: username,
|
|||
|
|
conversationId: CONV_ID.value, // ← 后端靠这个找到对话历史
|
|||
|
|
question: question,
|
|||
|
|
});
|
|||
|
|
// 处理 AI 回复...
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 3. 切换历史会话:加载旧对话
|
|||
|
|
const handleSelectConv = (convId) => {
|
|||
|
|
CONV_ID.value = convId;
|
|||
|
|
getConversationDetail(convId); // 从后端加载完整对话记录
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**会话管理功能**(左侧边栏):
|
|||
|
|
- 查看历史/收藏会话列表
|
|||
|
|
- 搜索会话
|
|||
|
|
- 重命名会话
|
|||
|
|
- 收藏/取消收藏
|
|||
|
|
- 删除会话
|
|||
|
|
- 批量管理
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4.2 思考过程展示
|
|||
|
|
|
|||
|
|
**问题**:AI 回答时用户看不到它在干什么,体验像"黑盒"。
|
|||
|
|
|
|||
|
|
**解决方案**:后端返回 `states` 对象,前端解析为步骤列表展示。
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 后端返回的数据包含 states
|
|||
|
|
const { text, type, states } = row;
|
|||
|
|
|
|||
|
|
// 解析思考步骤
|
|||
|
|
const processThinkStates = (states) => {
|
|||
|
|
let thinkProcess = []; // 主步骤
|
|||
|
|
let steps = []; // 子步骤
|
|||
|
|
|
|||
|
|
Object.keys(states).forEach(key => {
|
|||
|
|
if (key === 'steps') {
|
|||
|
|
// 子步骤
|
|||
|
|
Object.keys(states[key]).forEach(subKey => {
|
|||
|
|
steps.push({ name: subKey, status: states[key][subKey] });
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
// 主步骤:意图分析、SQL有效性判断、SQL执行
|
|||
|
|
thinkProcess.push({ name: key, status: states[key] });
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return { thinkProcess, steps };
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
展示效果:
|
|||
|
|
```
|
|||
|
|
▼ 思考过程:
|
|||
|
|
✓ 意图分析 成功
|
|||
|
|
✓ SQL有效性判断 成功
|
|||
|
|
✓ SQL执行 成功
|
|||
|
|
✓ 数据查询 成功
|
|||
|
|
✓ 结果格式化 成功
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
用户可以点击折叠/展开思考过程。每个步骤显示绿色"成功"或红色"失败"。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4.3 组件化消息渲染(5 种消息类型)
|
|||
|
|
|
|||
|
|
**问题**:AI 的回答不只是纯文本,还可能是表格、软件详情等不同格式。
|
|||
|
|
|
|||
|
|
**解决方案**:根据后端返回的 `type` 字段,用不同组件渲染。
|
|||
|
|
|
|||
|
|
```vue
|
|||
|
|
<template v-for="(msg, idx) in messages" :key="idx">
|
|||
|
|
<!-- 用户消息:纯文本气泡 -->
|
|||
|
|
<McBubble v-if="msg.role === 'user'" :content="msg.content" />
|
|||
|
|
|
|||
|
|
<!-- AI 消息:根据 type 选择不同组件 -->
|
|||
|
|
<McBubble v-else :loading="msg.loading">
|
|||
|
|
<!-- 思考过程(可折叠) -->
|
|||
|
|
<div class="think-toggle-btn" @click="toggleThink(idx)">...</div>
|
|||
|
|
|
|||
|
|
<!-- 根据 type 渲染不同内容 -->
|
|||
|
|
<OssList v-if="msg.type === 1" /> <!-- 开源软件列表 -->
|
|||
|
|
<WarningList v-else-if="msg.type === 2" /> <!-- 预警列表 -->
|
|||
|
|
<OssDetail v-else-if="msg.type === 'critical_software_info'" :id="msg.id" /> <!-- 软件详情 -->
|
|||
|
|
<AIList v-else-if="msg.type === 'df'" :content="msg.content" /> <!-- 数据表格 -->
|
|||
|
|
<Other v-else :content="msg.content" /> <!-- Markdown 文本 -->
|
|||
|
|
</McBubble>
|
|||
|
|
</template>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**5 种消息类型详解**:
|
|||
|
|
|
|||
|
|
| type 值 | 渲染组件 | 用户看到什么 |
|
|||
|
|
|---------|----------|------------|
|
|||
|
|
| `1` | OssList | 开源软件列表表格(有分页、导出功能) |
|
|||
|
|
| `2` | WarningList | 预警列表表格(有严重程度标签:高危/中危/低危) |
|
|||
|
|
| `'critical_software_info'` | OssDetail | 软件详情页面(嵌入完整的软件详情组件) |
|
|||
|
|
| `'df'` | AIList | 通用数据表格(动态列名、JSON 解析) |
|
|||
|
|
| `'text'` | Other | Markdown 格式的文本回答 |
|
|||
|
|
| `'sql_error'` | Other | 错误信息(带错误图标) |
|
|||
|
|
|
|||
|
|
**type 判断逻辑**(后端返回 `df` 类型时还要二次判断):
|
|||
|
|
```typescript
|
|||
|
|
if (type === 'df') {
|
|||
|
|
// 默认当普通表格
|
|||
|
|
msg.type = 'df';
|
|||
|
|
msg.content = row[type];
|
|||
|
|
|
|||
|
|
// 但如果表名是 critical_software_info 且只有一条数据 → 当软件详情
|
|||
|
|
if (table_name.length === 1 && table_name[0] === 'critical_software_info') {
|
|||
|
|
let arr = JSON.parse(row[type]);
|
|||
|
|
if (arr.length === 1) {
|
|||
|
|
msg.type = 'critical_software_info'; // 升级为软件详情
|
|||
|
|
msg.id = arr[0].id;
|
|||
|
|
msg.software_name = arr[0].software_name;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4.4 猜你想问(推荐问题)
|
|||
|
|
|
|||
|
|
AI 回答后,自动推荐相关后续问题:
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// AI 回答后,调用推荐问题 API
|
|||
|
|
const fetchFollowupQuestions = async (question, df_id) => {
|
|||
|
|
const { data } = await FetchFollowupQuestions({ question, df_id });
|
|||
|
|
if (data.code === 200) {
|
|||
|
|
followupQuestions.value = data.data; // 更新推荐问题列表
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 用户点击推荐问题 → 直接发送
|
|||
|
|
<a v-for="q in followupQuestions" @click="onSubmit(q)">
|
|||
|
|
<span>{{ q.question }}</span>
|
|||
|
|
</a>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4.5 AI API 接口总览
|
|||
|
|
|
|||
|
|
项目对接了 9 个 AI 后端接口:
|
|||
|
|
|
|||
|
|
| 接口 | 干什么 | 调用时机 |
|
|||
|
|
|------|--------|----------|
|
|||
|
|
| `createConversation` | 创建新会话 | 用户发第一条消息时 |
|
|||
|
|
| `chat_use_sql` | 发送消息/获取 AI 回复 | 每次用户发送消息 |
|
|||
|
|
| `conversationList` | 获取会话列表 | 打开侧边栏时 |
|
|||
|
|
| `conversationDetail` | 获取会话详情 | 点击历史会话时 |
|
|||
|
|
| `provide_followup_questions` | 获取推荐问题 | AI 回答后 |
|
|||
|
|
| `changeConversationTitle` | 重命名会话 | 用户编辑会话名 |
|
|||
|
|
| `toggleConversationCollect` | 收藏/取消收藏 | 用户点击收藏 |
|
|||
|
|
| `deleteConversation` | 删除会话 | 用户删除 |
|
|||
|
|
| `update_recommend_questions` | 刷新推荐问题 | 用户点击"换一批" |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、整体架构总结
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
@matechat/core 提供:McBubble(气泡)+ McInput(输入框)+ McMarkdownCard(Markdown渲染)
|
|||
|
|
↓
|
|||
|
|
搭建聊天界面骨架
|
|||
|
|
↓
|
|||
|
|
在 McBubble 内部渲染自定义内容组件:
|
|||
|
|
├── OssList(软件列表) ← type=1
|
|||
|
|
├── WarningList(预警列表) ← type=2
|
|||
|
|
├── OssDetail(软件详情) ← type='critical_software_info'
|
|||
|
|
├── AIList(数据表格) ← type='df'
|
|||
|
|
└── Other(Markdown文本) ← 默认
|
|||
|
|
↓
|
|||
|
|
9 个 API 接口对接后端
|
|||
|
|
conversationId 串联多轮对话
|
|||
|
|
states 对象解析为思考过程
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、面试问答准备
|
|||
|
|
|
|||
|
|
### Q1:"集成 @matechat/core 实现 AI 智能助手"具体做了什么?
|
|||
|
|
|
|||
|
|
> 我用华为开源的 MateChat 组件库搭建了 AI 聊天界面,核心组件是 McBubble(消息气泡)和 McInput(输入框)。实现了三个关键功能:第一,多轮对话,通过 conversationId 串联整个对话,后端维护历史上下文,前端对接了 9 个 API 接口管理会话;第二,思考过程展示,后端返回 states 对象,前端解析为"意图分析→SQL判断→SQL执行"的步骤列表,支持折叠展开;第三,组件化消息渲染,根据后端返回的 type 字段,用 5 种不同组件渲染 AI 回复——开源软件列表、预警列表、软件详情、数据表格、Markdown 文本。
|
|||
|
|
|
|||
|
|
### Q2:多轮对话怎么实现的?
|
|||
|
|
|
|||
|
|
> 前后端配合。用户发第一条消息时,前端调 createConversation API 获取 conversationId。之后每条消息都带上这个 conversationId,后端根据它找到整个对话历史,AI 结合上下文回答。切换历史会话时,调 conversationDetail API 加载完整对话记录。前端还有完整的会话管理:历史列表、收藏、搜索、重命名、删除、批量管理。
|
|||
|
|
|
|||
|
|
### Q3:思考过程展示怎么做的?
|
|||
|
|
|
|||
|
|
> 后端 AI 接口返回的数据里有一个 states 对象,包含主步骤(意图分析、SQL有效性判断、SQL执行)和子步骤。我写了一个 processThinkStates 函数解析这个对象,转换为 `{name, status}` 数组,存储在消息对象的 thinkProcess 和 steps 字段里。前端用可折叠的 UI 展示,每个步骤显示成功(绿色)或失败(红色)。这个功能是自定义实现的,不是 MateChat 组件库自带的。
|
|||
|
|
|
|||
|
|
### Q4:组件化消息渲染是什么意思?
|
|||
|
|
|
|||
|
|
> AI 的回答不只是纯文本,还可能是软件列表、预警表格、软件详情等。我根据后端返回的 type 字段判断消息类型,用 5 种不同组件渲染:type=1 用 OssList 展示开源软件列表(带分页和导出),type=2 用 WarningList 展示预警列表(带严重程度标签),type='critical_software_info' 用 OssDetail 展示软件详情,type='df' 用 AIList 展示通用数据表格,其他情况用 Other 组件渲染 Markdown 文本。所有这些组件都嵌在 MateChat 的 McBubble 气泡里。
|
|||
|
|
|
|||
|
|
### Q5:为什么选 MateChat 而不是自己写聊天 UI?
|
|||
|
|
|
|||
|
|
> 两个原因:第一,MateChat 提供了开箱即用的聊天气泡、输入框、Markdown 渲染等组件,不用从零实现,开发效率高;第二,MateChat 是华为开源的,和我们平台的技术方向一致,组件风格也和 DevUI 统一。不过思考过程展示、组件化消息渲染这些核心功能是自定义实现的,MateChat 主要提供了 UI 骨架。
|
|||
|
|
|
|||
|
|
### Q6:AI 后端是怎么连接的?SSE 还是 WebSocket?
|
|||
|
|
|
|||
|
|
> 用的是标准的 HTTP POST 请求,不是 SSE 也不是 WebSocket。每次用户发消息,前端发一个 POST 请求,后端处理完返回完整响应。代码里有模拟流式输出的注释代码(用 setTimeout 逐字显示),但生产环境用的是同步请求-响应模式。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 七、关键数字(面试时用)
|
|||
|
|
|
|||
|
|
| 数据 | 数字 |
|
|||
|
|
|------|------|
|
|||
|
|
| MateChat 组件库版本 | 1.4.0 |
|
|||
|
|
| 使用的 MateChat 组件 | 5 种(McBubble、McInput、McMarkdownCard、McLayout 系列) |
|
|||
|
|
| 自定义消息组件 | 5 种(OssList、WarningList、OssDetail、AIList、Other) |
|
|||
|
|
| AI API 接口数量 | 9 个 |
|
|||
|
|
| 消息类型 | 6 种(text、df、critical_software_info、1、2、sql_error) |
|
|||
|
|
| 思考过程步骤 | 3 个主步骤 + N 个子步骤 |
|
|||
|
|
| 会话管理功能 | 7 个(列表/搜索/重命名/收藏/删除/批量管理/历史限制) |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 八、涉及的源码文件(需要看的时候查)
|
|||
|
|
|
|||
|
|
| 做什么 | 文件在哪 |
|
|||
|
|
|--------|----------|
|
|||
|
|
| AI 助手主页面(生产版) | `src/views/Jyh/AI/Home/index.vue` |
|
|||
|
|
| 软件列表组件 | `src/views/Jyh/AI/Home/components/OssList.vue` |
|
|||
|
|
| 预警列表组件 | `src/views/Jyh/AI/Home/components/WarningList.vue` |
|
|||
|
|
| 软件详情组件 | `src/views/Jyh/AI/Home/components/OssDetail.vue` |
|
|||
|
|
| 数据表格组件 | `src/views/Jyh/AI/Home/components/AIList.vue` |
|
|||
|
|
| Markdown 文本组件 | `src/views/Jyh/AI/Home/components/Other.vue` |
|
|||
|
|
| 猜你想问组件 | `src/views/Jyh/AI/Home/GuessYouWantToAsk.vue` |
|
|||
|
|
| 功能轮播组件 | `src/views/Jyh/AI/Home/SwiperComponent.vue` |
|
|||
|
|
| 会话历史侧边栏 | `src/views/Jyh/AI/Home/components/ViewHistoryAside/ViewHistoryAsideNew.vue` |
|
|||
|
|
| 批量管理弹窗 | `src/views/Jyh/AI/Home/components/ViewHistoryAside/BatchManageModal.vue` |
|
|||
|
|
| AI 布局 | `src/layouts/AILayout/index.vue` |
|
|||
|
|
| AI 头部导航 | `src/components/Header/AIHeader.vue` |
|
|||
|
|
| AI API 接口定义 | `src/api/jyh/index.ts`(380-460 行) |
|
|||
|
|
| KnowledgeHub AI 弹窗 | `src/views/Jyh/KnowledgeHub/Components/AIModal.vue` |
|
|||
|
|
| AI 修复建议页面 | `src/views/Jyh/AIRepair/index.vue` |
|