523 lines
13 KiB
Markdown
523 lines
13 KiB
Markdown
# 聊天模块 V2.1 优化更新
|
||
|
||
## 📅 更新日期
|
||
2025年10月14日
|
||
|
||
## 🎯 本次优化内容
|
||
|
||
### 1. ✅ 右侧对话列表可折叠
|
||
|
||
**功能描述**:右侧的对话列表现在支持折叠/展开,节省屏幕空间。
|
||
|
||
**实现细节**:
|
||
- 在对话头部添加折叠按钮
|
||
- 按钮图标根据状态变化(ChevronLeft / ChevronRight)
|
||
- 按钮文字显示"显示列表" / "隐藏列表"
|
||
- 使用 CSS transition 实现平滑动画
|
||
|
||
**代码实现**:
|
||
```vue
|
||
<!-- 头部按钮 -->
|
||
<n-button text @click="showSidebar = !showSidebar">
|
||
<n-icon :component="showSidebar ? ChevronRightIcon : ChevronLeftIcon" />
|
||
<span>{{ showSidebar ? '隐藏列表' : '显示列表' }}</span>
|
||
</n-button>
|
||
|
||
<!-- CSS 动画 -->
|
||
<style>
|
||
.topics-sidebar {
|
||
width: 320px;
|
||
transition: all 0.3s ease;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.topics-sidebar:not(.visible) {
|
||
width: 0;
|
||
border-left: none;
|
||
opacity: 0;
|
||
}
|
||
</style>
|
||
```
|
||
|
||
**使用方法**:
|
||
- 点击对话头部右上角的折叠按钮
|
||
- 对话列表会平滑地隐藏/显示
|
||
- 响应式设计:小屏幕时自动变为浮动面板
|
||
|
||
---
|
||
|
||
### 2. ✅ AI 模型选择列表动态加载
|
||
|
||
**功能描述**:模型选择器现在会动态读取"模型服务"中已配置的所有可用模型。
|
||
|
||
**实现细节**:
|
||
```typescript
|
||
// 从 modelStore 动态读取模型列表
|
||
const modelOptions = computed(() => {
|
||
const services = modelStore.providers
|
||
const options: any[] = []
|
||
|
||
services.forEach((service: any) => {
|
||
if (service.enabled && service.models) {
|
||
service.models.forEach((model: any) => {
|
||
options.push({
|
||
label: `${service.name} | ${model.name}`,
|
||
key: `${service.id}:${model.id}`,
|
||
icon: () => h(NIcon, { component: BrainIcon })
|
||
})
|
||
})
|
||
}
|
||
})
|
||
|
||
return options
|
||
})
|
||
|
||
// 显示选中的模型名称
|
||
const selectedModelName = computed(() => {
|
||
if (!selectedModel.value) return undefined
|
||
const [serviceId, modelId] = selectedModel.value.split(':')
|
||
const service = modelStore.providers.find((s: any) => s.id === serviceId)
|
||
const model = service?.models?.find((m: any) => m.id === modelId)
|
||
return model ? `${service?.name} | ${model.name}` : undefined
|
||
})
|
||
```
|
||
|
||
**工作流程**:
|
||
1. 用户在"模型服务"页面添加服务(如火山引擎、OpenAI)
|
||
2. 服务连接成功后,其模型会自动出现在聊天页面的模型选择器中
|
||
3. 选择模型后,该模型会被用于当前对话
|
||
4. 模型信息格式:`服务名 | 模型名`(如"火山引擎 | doubao-1.5-pro-32k")
|
||
|
||
**特性**:
|
||
- ✅ 实时同步:添加新服务后立即可用
|
||
- ✅ 多服务支持:同时显示所有服务的模型
|
||
- ✅ 清晰标识:服务名和模型名分开显示
|
||
- ✅ 图标辅助:每个选项都有模型图标
|
||
|
||
---
|
||
|
||
### 3. ✅ MCP 服务支持(基础架构)
|
||
|
||
**功能描述**:聊天对话中现在支持选择和使用 MCP 服务器。
|
||
|
||
**实现细节**:
|
||
|
||
#### 3.1 MCP 服务器列表动态加载
|
||
```typescript
|
||
// 从 mcpStore 读取已连接的服务器
|
||
const mcpOptions = computed(() => {
|
||
const options: any[] = [
|
||
{
|
||
label: '不启用 MCP 服务',
|
||
key: 'none'
|
||
}
|
||
]
|
||
|
||
// 添加已连接的服务器
|
||
mcpStore.connectedServers.forEach((server) => {
|
||
const toolCount = server.capabilities?.tools?.length || 0
|
||
options.push({
|
||
label: `${server.name} (${toolCount} 个工具)`,
|
||
key: server.id,
|
||
icon: () => h(NIcon, { component: PlugIcon })
|
||
})
|
||
})
|
||
|
||
return options
|
||
})
|
||
|
||
// 显示选中的 MCP 服务器名称
|
||
const selectedMCPName = computed(() => {
|
||
if (!selectedMCP.value || selectedMCP.value === 'none') return '不启用 MCP 服务'
|
||
const server = mcpStore.servers.find(s => s.id === selectedMCP.value)
|
||
return server?.name || '未知服务'
|
||
})
|
||
```
|
||
|
||
#### 3.2 MCP 服务器传递到聊天服务
|
||
```typescript
|
||
// ChatLayout.vue - 发送消息时传递 MCP 服务器 ID
|
||
const handleSendMessage = async () => {
|
||
const mcpId = selectedMCP.value === 'none' ? undefined : selectedMCP.value
|
||
await store.sendMessageStream(
|
||
content,
|
||
selectedModel.value,
|
||
mcpId, // 传递 MCP 服务器 ID
|
||
() => { scrollToBottom() }
|
||
)
|
||
}
|
||
|
||
// chatStore.ts - 转发到 chatService
|
||
const sendMessageStream = async (
|
||
content: string,
|
||
model?: string,
|
||
mcpServerId?: string, // 新增参数
|
||
onChunk?: (chunk: string) => void
|
||
) => {
|
||
await chatService.sendMessageStream(
|
||
{ topicId, content, model, stream: true },
|
||
onChunk,
|
||
mcpServerId // 传递给 service
|
||
)
|
||
}
|
||
|
||
// chatService.ts - 接收并准备使用
|
||
async sendMessageStream(
|
||
options: SendMessageOptions,
|
||
onChunk: (event: StreamEvent) => void,
|
||
mcpServerId?: string // 接收 MCP 服务器 ID
|
||
): Promise<void> {
|
||
// TODO: 在这里实现 MCP 工具调用逻辑
|
||
await this.callModelStream(conversation, model, onChunk, mcpServerId)
|
||
}
|
||
```
|
||
|
||
#### 3.3 自动加载和重连
|
||
```typescript
|
||
// 初始化时加载 MCP 服务器
|
||
onMounted(async () => {
|
||
store.initialize()
|
||
scrollToBottom()
|
||
|
||
// 加载 MCP 服务器配置
|
||
mcpStore.loadServers()
|
||
|
||
// 尝试自动重连之前已连接的服务器
|
||
try {
|
||
await mcpStore.autoReconnect()
|
||
} catch (error) {
|
||
console.warn('自动重连 MCP 服务器失败:', error)
|
||
}
|
||
})
|
||
```
|
||
|
||
**工作流程**:
|
||
1. 用户在"MCP 设置"页面添加并连接服务器
|
||
2. 服务器连接成功后,自动出现在聊天页面的 MCP 选择器中
|
||
3. 选择服务器后,该服务器 ID 会被传递到聊天服务
|
||
4. 聊天服务可以使用该服务器的工具(待实现)
|
||
|
||
**当前状态**:
|
||
- ✅ 基础架构完成:MCP 服务器 ID 可以从 UI 传递到服务层
|
||
- ✅ 服务器列表动态加载:实时显示已连接的服务器和工具数量
|
||
- ✅ 自动重连:页面刷新后自动重连之前的服务器
|
||
- ⏳ 工具调用逻辑:已预留接口,等待实现
|
||
|
||
**下一步实现**:
|
||
```typescript
|
||
// 在 callModelStream 中检测 AI 的工具调用请求
|
||
private async callModelStream(
|
||
conversation: Conversation,
|
||
model: string | undefined,
|
||
onChunk: (chunk: string) => void,
|
||
mcpServerId?: string
|
||
): Promise<void> {
|
||
if (mcpServerId) {
|
||
// 1. 获取 MCP 服务器的可用工具列表
|
||
const server = mcpStore.servers.find(s => s.id === mcpServerId)
|
||
const tools = server?.capabilities?.tools || []
|
||
|
||
// 2. 将工具列表传递给 AI 模型
|
||
// 让 AI 知道可以调用哪些工具
|
||
|
||
// 3. 如果 AI 返回工具调用请求,执行工具
|
||
// const toolResult = await mcpStore.callTool(mcpServerId, toolName, params)
|
||
|
||
// 4. 将工具结果返回给 AI,让它生成最终回复
|
||
}
|
||
|
||
// 正常的流式响应
|
||
// ...
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 完整功能清单
|
||
|
||
### 已完成功能
|
||
1. ✅ 左侧导航可折叠(V2.0)
|
||
2. ✅ 右侧对话列表(V2.0)
|
||
3. ✅ **右侧对话列表可折叠(V2.1 新增)**
|
||
4. ✅ 工具栏 - MCP 服务选择
|
||
5. ✅ **工具栏 - 模型动态加载(V2.1 优化)**
|
||
6. ✅ **MCP 服务集成基础架构(V2.1 新增)**
|
||
7. ✅ 快捷操作按钮
|
||
8. ✅ 消息实时更新
|
||
9. ✅ 消息条数正确显示
|
||
|
||
### 待实现功能
|
||
1. ⏳ MCP 工具调用实际逻辑
|
||
2. ⏳ Markdown 渲染
|
||
3. ⏳ 代码语法高亮
|
||
4. ⏳ 真正的流式响应(SSE)
|
||
5. ⏳ 图片和文件消息
|
||
|
||
---
|
||
|
||
## 🎬 使用示例
|
||
|
||
### 场景1:使用特定模型对话
|
||
|
||
1. **添加模型服务**
|
||
```
|
||
侧边栏 → 模型服务 → 添加服务
|
||
例如:添加"火山引擎"服务
|
||
```
|
||
|
||
2. **在聊天中选择模型**
|
||
```
|
||
聊天页面 → 工具栏 → 点击"选择模型▼"
|
||
选择:火山引擎 | doubao-1.5-pro-32k-character
|
||
```
|
||
|
||
3. **发送消息**
|
||
```
|
||
输入框 → 输入"你好" → Enter
|
||
AI 使用选中的模型回复
|
||
```
|
||
|
||
### 场景2:使用 MCP 服务器扩展能力
|
||
|
||
1. **添加 MCP 服务器**
|
||
```
|
||
侧边栏 → MCP 设置 → 添加服务器
|
||
例如:添加"xhs-sse"服务器
|
||
URL: http://localhost:3200
|
||
```
|
||
|
||
2. **连接服务器**
|
||
```
|
||
点击"连接"按钮
|
||
等待连接成功,显示可用工具数量
|
||
```
|
||
|
||
3. **在聊天中选择 MCP**
|
||
```
|
||
聊天页面 → 工具栏 → 点击"不启用 MCP 服务▼"
|
||
选择:xhs-sse (5 个工具)
|
||
```
|
||
|
||
4. **发送消息(准备使用工具)**
|
||
```
|
||
输入框 → 输入"搜索最新的 Vue 3 教程"
|
||
AI 可以调用 MCP 工具进行搜索(功能待实现)
|
||
```
|
||
|
||
### 场景3:折叠对话列表获得更大空间
|
||
|
||
1. **隐藏对话列表**
|
||
```
|
||
点击右上角"隐藏列表"按钮
|
||
对话列表平滑隐藏
|
||
主对话区域扩大
|
||
```
|
||
|
||
2. **再次显示**
|
||
```
|
||
点击"显示列表"按钮
|
||
对话列表平滑显示
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 技术细节
|
||
|
||
### 数据流:模型选择
|
||
|
||
```
|
||
用户添加服务
|
||
↓
|
||
ModelService 连接
|
||
↓
|
||
modelStore.providers 更新
|
||
↓
|
||
modelOptions 计算属性更新
|
||
↓
|
||
下拉列表自动刷新
|
||
↓
|
||
用户选择模型
|
||
↓
|
||
selectedModel = "serviceId:modelId"
|
||
↓
|
||
发送消息时使用该模型
|
||
↓
|
||
modelServiceManager.sendChatRequest(serviceId, messages, modelId)
|
||
```
|
||
|
||
### 数据流:MCP 集成
|
||
|
||
```
|
||
用户添加 MCP 服务器
|
||
↓
|
||
MCPClientService 连接
|
||
↓
|
||
mcpStore.servers 更新
|
||
↓
|
||
mcpOptions 计算属性更新
|
||
↓
|
||
下拉列表自动刷新
|
||
↓
|
||
用户选择 MCP 服务器
|
||
↓
|
||
selectedMCP = serverId
|
||
↓
|
||
发送消息时传递 serverId
|
||
↓
|
||
chatService.sendMessageStream(..., mcpServerId)
|
||
↓
|
||
callModelStream(..., mcpServerId)
|
||
↓
|
||
[待实现] mcpStore.callTool(mcpServerId, toolName, params)
|
||
```
|
||
|
||
### 关键组件关系
|
||
|
||
```
|
||
ChatLayout.vue
|
||
├─ uses chatStore (聊天状态管理)
|
||
├─ uses modelStore (模型列表)
|
||
├─ uses mcpStore (MCP 服务器列表)
|
||
└─ calls sendMessageStream(content, model, mcpServerId)
|
||
|
||
chatStore.ts
|
||
└─ calls chatService.sendMessageStream(options, onChunk, mcpServerId)
|
||
|
||
chatService.ts
|
||
└─ calls callModelStream(conversation, model, onChunk, mcpServerId)
|
||
└─ [TODO] 实现 MCP 工具调用逻辑
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 配置示例
|
||
|
||
### 模型服务配置示例
|
||
```json
|
||
{
|
||
"id": "volcengine-001",
|
||
"name": "火山引擎",
|
||
"type": "volcengine",
|
||
"url": "https://ark.cn-beijing.volces.com/api/v3",
|
||
"apiKey": "your-api-key",
|
||
"enabled": true,
|
||
"models": [
|
||
{
|
||
"id": "doubao-1.5-pro-32k",
|
||
"name": "豆包-1.5-pro-32k",
|
||
"type": "chat"
|
||
},
|
||
{
|
||
"id": "doubao-1.5-pro-32k-character",
|
||
"name": "豆包-1.5-pro-32k-角色扮演",
|
||
"type": "chat"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### MCP 服务器配置示例
|
||
```json
|
||
{
|
||
"id": "mcp-xhs-001",
|
||
"name": "xhs-sse",
|
||
"url": "http://localhost:3200",
|
||
"transport": "sse",
|
||
"status": "connected",
|
||
"capabilities": {
|
||
"tools": [
|
||
{
|
||
"name": "search",
|
||
"description": "搜索互联网内容"
|
||
},
|
||
{
|
||
"name": "read_file",
|
||
"description": "读取本地文件"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 下一步开发计划
|
||
|
||
### 优先级1:MCP 工具调用实现
|
||
```typescript
|
||
// 实现 AI 工具调用流程
|
||
1. 将 MCP 工具列表格式化为 OpenAI Function Calling 格式
|
||
2. 在调用模型时传递工具定义
|
||
3. 解析 AI 返回的工具调用请求
|
||
4. 执行 MCP 工具
|
||
5. 将结果返回给 AI
|
||
6. 显示完整的对话过程
|
||
```
|
||
|
||
### 优先级2:模型切换优化
|
||
```typescript
|
||
// 记住每个对话的模型选择
|
||
1. 在 Topic 中保存 modelId
|
||
2. 切换对话时自动选择对应模型
|
||
3. 支持为不同对话设置默认模型
|
||
```
|
||
|
||
### 优先级3:UI 优化
|
||
```typescript
|
||
// 更好的用户体验
|
||
1. 工具调用进度显示
|
||
2. MCP 工具调用结果可视化
|
||
3. 模型和 MCP 状态指示器
|
||
4. 更多的快捷键支持
|
||
```
|
||
|
||
---
|
||
|
||
## ⚠️ 注意事项
|
||
|
||
### MCP 服务器要求
|
||
1. **必须先配置**:在"MCP 设置"中添加并连接服务器
|
||
2. **连接状态**:只有已连接的服务器才会出现在选择器中
|
||
3. **自动重连**:页面刷新后会自动尝试重连
|
||
4. **工具数量**:选择器显示每个服务器的工具数量
|
||
|
||
### 模型服务要求
|
||
1. **必须先配置**:在"模型服务"中添加服务
|
||
2. **启用状态**:只有启用的服务的模型才会出现
|
||
3. **连接状态**:建议先测试连接再使用
|
||
4. **API Key**:确保 API Key 有效且有足够配额
|
||
|
||
### 性能建议
|
||
1. **服务器数量**:建议不超过 5 个 MCP 服务器同时连接
|
||
2. **模型选择**:根据对话复杂度选择合适的模型
|
||
3. **工具调用**:复杂工具可能需要更长时间
|
||
|
||
---
|
||
|
||
## 📖 更新记录
|
||
|
||
### V2.1(2025/10/14)
|
||
- ✅ 右侧对话列表支持折叠
|
||
- ✅ 模型选择器动态加载已配置的模型
|
||
- ✅ MCP 服务集成基础架构完成
|
||
- ✅ 自动重连 MCP 服务器
|
||
- ✅ 完善的数据流和状态管理
|
||
|
||
### V2.0(2025/10/14)
|
||
- ✅ 左侧导航可折叠
|
||
- ✅ 右侧对话列表布局
|
||
- ✅ 完整工具栏
|
||
- ✅ 消息实时更新
|
||
- ✅ 消息条数修复
|
||
|
||
---
|
||
|
||
**优化完成!** 🎉
|
||
|
||
现在您可以:
|
||
1. ✅ 折叠对话列表获得更大空间
|
||
2. ✅ 使用已配置的任意模型对话
|
||
3. ✅ 选择 MCP 服务器(基础架构就绪)
|
||
|
||
继续完善 MCP 工具调用功能,敬请期待 V2.2!
|