13 KiB
13 KiB
聊天模块 V2.1 优化更新
📅 更新日期
2025年10月14日
🎯 本次优化内容
1. ✅ 右侧对话列表可折叠
功能描述:右侧的对话列表现在支持折叠/展开,节省屏幕空间。
实现细节:
- 在对话头部添加折叠按钮
- 按钮图标根据状态变化(ChevronLeft / ChevronRight)
- 按钮文字显示"显示列表" / "隐藏列表"
- 使用 CSS transition 实现平滑动画
代码实现:
<!-- 头部按钮 -->
<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 模型选择列表动态加载
功能描述:模型选择器现在会动态读取"模型服务"中已配置的所有可用模型。
实现细节:
// 从 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
})
工作流程:
- 用户在"模型服务"页面添加服务(如火山引擎、OpenAI)
- 服务连接成功后,其模型会自动出现在聊天页面的模型选择器中
- 选择模型后,该模型会被用于当前对话
- 模型信息格式:
服务名 | 模型名(如"火山引擎 | doubao-1.5-pro-32k")
特性:
- ✅ 实时同步:添加新服务后立即可用
- ✅ 多服务支持:同时显示所有服务的模型
- ✅ 清晰标识:服务名和模型名分开显示
- ✅ 图标辅助:每个选项都有模型图标
3. ✅ MCP 服务支持(基础架构)
功能描述:聊天对话中现在支持选择和使用 MCP 服务器。
实现细节:
3.1 MCP 服务器列表动态加载
// 从 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 服务器传递到聊天服务
// 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 自动加载和重连
// 初始化时加载 MCP 服务器
onMounted(async () => {
store.initialize()
scrollToBottom()
// 加载 MCP 服务器配置
mcpStore.loadServers()
// 尝试自动重连之前已连接的服务器
try {
await mcpStore.autoReconnect()
} catch (error) {
console.warn('自动重连 MCP 服务器失败:', error)
}
})
工作流程:
- 用户在"MCP 设置"页面添加并连接服务器
- 服务器连接成功后,自动出现在聊天页面的 MCP 选择器中
- 选择服务器后,该服务器 ID 会被传递到聊天服务
- 聊天服务可以使用该服务器的工具(待实现)
当前状态:
- ✅ 基础架构完成:MCP 服务器 ID 可以从 UI 传递到服务层
- ✅ 服务器列表动态加载:实时显示已连接的服务器和工具数量
- ✅ 自动重连:页面刷新后自动重连之前的服务器
- ⏳ 工具调用逻辑:已预留接口,等待实现
下一步实现:
// 在 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,让它生成最终回复
}
// 正常的流式响应
// ...
}
📊 完整功能清单
已完成功能
- ✅ 左侧导航可折叠(V2.0)
- ✅ 右侧对话列表(V2.0)
- ✅ 右侧对话列表可折叠(V2.1 新增)
- ✅ 工具栏 - MCP 服务选择
- ✅ 工具栏 - 模型动态加载(V2.1 优化)
- ✅ MCP 服务集成基础架构(V2.1 新增)
- ✅ 快捷操作按钮
- ✅ 消息实时更新
- ✅ 消息条数正确显示
待实现功能
- ⏳ MCP 工具调用实际逻辑
- ⏳ Markdown 渲染
- ⏳ 代码语法高亮
- ⏳ 真正的流式响应(SSE)
- ⏳ 图片和文件消息
🎬 使用示例
场景1:使用特定模型对话
-
添加模型服务
侧边栏 → 模型服务 → 添加服务 例如:添加"火山引擎"服务 -
在聊天中选择模型
聊天页面 → 工具栏 → 点击"选择模型▼" 选择:火山引擎 | doubao-1.5-pro-32k-character -
发送消息
输入框 → 输入"你好" → Enter AI 使用选中的模型回复
场景2:使用 MCP 服务器扩展能力
-
添加 MCP 服务器
侧边栏 → MCP 设置 → 添加服务器 例如:添加"xhs-sse"服务器 URL: http://localhost:3200 -
连接服务器
点击"连接"按钮 等待连接成功,显示可用工具数量 -
在聊天中选择 MCP
聊天页面 → 工具栏 → 点击"不启用 MCP 服务▼" 选择:xhs-sse (5 个工具) -
发送消息(准备使用工具)
输入框 → 输入"搜索最新的 Vue 3 教程" AI 可以调用 MCP 工具进行搜索(功能待实现)
场景3:折叠对话列表获得更大空间
-
隐藏对话列表
点击右上角"隐藏列表"按钮 对话列表平滑隐藏 主对话区域扩大 -
再次显示
点击"显示列表"按钮 对话列表平滑显示
🔧 技术细节
数据流:模型选择
用户添加服务
↓
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 工具调用逻辑
📝 配置示例
模型服务配置示例
{
"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 服务器配置示例
{
"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 工具调用实现
// 实现 AI 工具调用流程
1. 将 MCP 工具列表格式化为 OpenAI Function Calling 格式
2. 在调用模型时传递工具定义
3. 解析 AI 返回的工具调用请求
4. 执行 MCP 工具
5. 将结果返回给 AI
6. 显示完整的对话过程
优先级2:模型切换优化
// 记住每个对话的模型选择
1. 在 Topic 中保存 modelId
2. 切换对话时自动选择对应模型
3. 支持为不同对话设置默认模型
优先级3:UI 优化
// 更好的用户体验
1. 工具调用进度显示
2. MCP 工具调用结果可视化
3. 模型和 MCP 状态指示器
4. 更多的快捷键支持
⚠️ 注意事项
MCP 服务器要求
- 必须先配置:在"MCP 设置"中添加并连接服务器
- 连接状态:只有已连接的服务器才会出现在选择器中
- 自动重连:页面刷新后会自动尝试重连
- 工具数量:选择器显示每个服务器的工具数量
模型服务要求
- 必须先配置:在"模型服务"中添加服务
- 启用状态:只有启用的服务的模型才会出现
- 连接状态:建议先测试连接再使用
- API Key:确保 API Key 有效且有足够配额
性能建议
- 服务器数量:建议不超过 5 个 MCP 服务器同时连接
- 模型选择:根据对话复杂度选择合适的模型
- 工具调用:复杂工具可能需要更长时间
📖 更新记录
V2.1(2025/10/14)
- ✅ 右侧对话列表支持折叠
- ✅ 模型选择器动态加载已配置的模型
- ✅ MCP 服务集成基础架构完成
- ✅ 自动重连 MCP 服务器
- ✅ 完善的数据流和状态管理
V2.0(2025/10/14)
- ✅ 左侧导航可折叠
- ✅ 右侧对话列表布局
- ✅ 完整工具栏
- ✅ 消息实时更新
- ✅ 消息条数修复
优化完成! 🎉
现在您可以:
- ✅ 折叠对话列表获得更大空间
- ✅ 使用已配置的任意模型对话
- ✅ 选择 MCP 服务器(基础架构就绪)
继续完善 MCP 工具调用功能,敬请期待 V2.2!