From cb2f9ea76ff746867c15141f5fd43ea130877609 Mon Sep 17 00:00:00 2001 From: douboer Date: Wed, 15 Oct 2025 10:06:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=BC=BA=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E6=97=A5=E5=BF=97=E5=92=8C=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 chatService 中添加模型选择详细日志 - 在 modelServiceManager 中添加请求/响应确认日志 - 创建模型选择验证指南文档 - 帮助用户确认所选模型是否被正确使用 新增日志: - 🎯 用户选择的模型 - ✅ 找到匹配服务 - 🔍 最终选择确认 - 📋 请求体 model 字段 - �� 最终发送确认 - ✅ API 响应模型确认 用户现在可以在控制台清晰看到: - 选择了哪个模型 - 找到了哪个服务 - 实际发送了什么模型参数 - API 返回了什么模型 - 请求模型和响应模型是否一致 --- docs/aliyun-qwen-models.md | 187 ++++++++++++++++ docs/model-selection-debug.md | 272 ++++++++++++++++++++++++ todolist.md | 1 - web/src/services/chatService.ts | 14 +- web/src/services/modelServiceManager.ts | 38 +++- 5 files changed, 501 insertions(+), 11 deletions(-) create mode 100644 docs/aliyun-qwen-models.md create mode 100644 docs/model-selection-debug.md diff --git a/docs/aliyun-qwen-models.md b/docs/aliyun-qwen-models.md new file mode 100644 index 0000000..d5c4836 --- /dev/null +++ b/docs/aliyun-qwen-models.md @@ -0,0 +1,187 @@ +# 阿里云通义千问模型使用指南 + +## 支持的模型 + +项目已内置支持以下阿里云通义千问模型: + +### 1. qwen-turbo-latest +- **名称**: 通义千问 Turbo 最新版 +- **特点**: 高性价比,响应速度快 +- **适用场景**: 日常对话、文本生成、简单问答 +- **Function Calling**: ✅ 支持 + +### 2. qwq-plus +- **名称**: 通义千问增强版 +- **特点**: 更强的推理能力 +- **适用场景**: 复杂推理、数学问题、逻辑分析 +- **Function Calling**: ✅ 支持 + +### 3. qwen-long +- **名称**: 通义千问长文本版 +- **特点**: 支持超长上下文(最高支持 1M tokens) +- **适用场景**: 长文档分析、大规模文本处理 +- **Function Calling**: ✅ 支持 + +### 4. qwen3-omni-flash +- **名称**: 通义千问全能闪电版 +- **特点**: 多模态能力(文本+图像),极速响应 +- **适用场景**: 多模态对话、图文理解、快速响应 +- **Function Calling**: ✅ 支持 + +--- + +## 快速配置 + +### 步骤 1: 获取 API Key + +1. 访问 [阿里云百炼平台](https://bailian.console.aliyun.com/) +2. 创建应用或使用现有应用 +3. 获取 API Key + +### 步骤 2: 配置服务 + +1. 打开 MCP Client Vue 应用 +2. 进入 **"模型服务"** 设置 +3. 点击 **"添加服务"** +4. 填写以下信息: + +``` +服务名称: 阿里云通义千问 +服务类型: dashscope +API Key: sk-xxxxxxxxxxxxxxxx (你的 API Key) +Base URL: https://dashscope.aliyuncs.com/compatible-mode/v1 +``` + +5. 点击 **"获取模型列表"** 或手动添加模型: + - qwen-turbo-latest + - qwq-plus + - qwen-long + - qwen3-omni-flash + +6. 点击 **"测试连接"** 验证配置 +7. 启用服务 + +--- + +## 使用方法 + +### 在对话中使用 + +1. 进入对话界面 +2. 在模型选择下拉框中选择阿里云模型(例如:`qwen-turbo-latest`) +3. 开始对话 + +### 配合 MCP 工具使用 + +1. 在 **"MCP 设置"** 中添加并连接工具服务器 +2. 在对话界面选择阿里云模型 +3. 选择对应的 MCP 服务器 +4. 发送需要工具辅助的消息 +5. AI 会自动调用工具并整合结果 + +--- + +## 模型选择建议 + +| 使用场景 | 推荐模型 | 原因 | +|---------|---------|------| +| 日常对话 | qwen-turbo-latest | 快速响应,成本低 | +| 复杂推理 | qwq-plus | 推理能力强 | +| 长文档分析 | qwen-long | 支持超长上下文 | +| 图文理解 | qwen3-omni-flash | 多模态能力 | +| MCP 工具调用 | qwen-turbo-latest / qwq-plus | Function Calling 支持好 | + +--- + +## 配置示例 + +### 通过浏览器控制台快速配置 + +```javascript +// 打开浏览器开发者工具 Console,执行以下代码: + +const providers = JSON.parse(localStorage.getItem('model-providers') || '[]') + +providers.push({ + id: 'aliyun-' + Date.now(), + name: '阿里云通义千问', + type: 'dashscope', + apiKey: 'sk-your-api-key-here', // 替换为你的 API Key + baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1', + models: [ + 'qwen-turbo-latest', + 'qwq-plus', + 'qwen-long', + 'qwen3-omni-flash' + ], + defaultModel: 'qwen-turbo-latest', + enabled: true, + maxTokens: 8000, + temperature: 0.7, + timeout: 60000 +}) + +localStorage.setItem('model-providers', JSON.stringify(providers)) +location.reload() +``` + +--- + +## 技术说明 + +### API 端点 +- **Base URL**: `https://dashscope.aliyuncs.com/compatible-mode/v1` +- **Chat Completions**: `/chat/completions` +- **模型列表**: `/models` + +### 请求格式 + +标准 OpenAI 兼容格式: + +```json +{ + "model": "qwen-turbo-latest", + "messages": [ + { "role": "user", "content": "你好" } + ], + "stream": true, + "tools": [...] // 可选:Function Calling +} +``` + +### 认证方式 + +``` +Authorization: Bearer sk-xxxxxxxxxxxxxxxx +``` + +--- + +## 常见问题 + +### Q: 模型列表为空? +A: 如果 API 无法获取模型列表,系统会自动使用预定义的 4 个推荐模型。 + +### Q: 是否支持流式输出? +A: ✅ 完全支持,与 OpenAI 流式格式兼容。 + +### Q: 是否支持 Function Calling? +A: ✅ 所有 4 个模型都支持 Function Calling,可以完美配合 MCP 工具使用。 + +### Q: qwen-long 的上下文窗口有多大? +A: 支持最高 1M tokens 的超长上下文。 + +### Q: 如何切换模型? +A: 在对话界面的模型下拉框中直接选择即可。 + +--- + +## 相关链接 + +- [阿里云百炼平台](https://bailian.console.aliyun.com/) +- [通义千问 API 文档](https://help.aliyun.com/zh/dashscope/) +- [Function Calling 文档](https://help.aliyun.com/zh/dashscope/developer-reference/function-call) + +--- + +**配置完成后即可使用阿里云强大的 AI 能力!** 🚀 diff --git a/docs/model-selection-debug.md b/docs/model-selection-debug.md new file mode 100644 index 0000000..7e2b101 --- /dev/null +++ b/docs/model-selection-debug.md @@ -0,0 +1,272 @@ +# 模型选择验证指南 + +## 问题:切换模型后回答没有变化? + +这个问题可能有以下几个原因,我已经添加了详细的日志来帮助你诊断。 + +--- + +## 🔍 如何确认模型被正确使用 + +### 方法 1: 查看控制台日志 (推荐) + +打开浏览器开发者工具 (F12),切换到 Console 标签,发送一条消息后查看日志: + +#### 关键日志标记 + +1. **用户选择阶段** +``` +🎯 [callModelStream] 用户选择的模型: qwen-turbo-latest +✅ [callModelStream] 找到匹配服务: 阿里云通义千问 +``` + +2. **最终确认阶段** +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🔍 [callModelStream] 最终选择: + 服务: 阿里云通义千问 (dashscope) + 模型: qwen-turbo-latest + MCP: 未选择 + 工具: 0 个 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +3. **请求准备阶段** +``` +🎯 [makeChatRequestStream] 准备请求参数: + 服务类型: dashscope + 服务名称: 阿里云通义千问 + 使用模型: qwen-turbo-latest + 消息数量: 2 + 工具数量: 0 +``` + +4. **最终发送阶段** +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🚀 [最终确认] 即将发送请求: + 模型: qwen-turbo-latest + 服务: 阿里云通义千问 (dashscope) + URL: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +``` + +5. **API 响应确认** +``` +✅ [响应确认] API 返回的模型: qwen-turbo-latest + 请求的模型: qwen-turbo-latest + 模型匹配: ✓ 一致 +``` + +### 方法 2: 测试不同模型的特性 + +#### 测试 qwen-turbo-latest (快速响应) +``` +提问: "用一句话介绍你自己" +预期: 快速响应,简洁回答 +``` + +#### 测试 qwq-plus (推理能力) +``` +提问: "如果 A>B,B>C,那么 A 和 C 的关系是什么?请详细说明推理过程。" +预期: 详细的逻辑推理步骤 +``` + +#### 测试 qwen-long (长上下文) +``` +提问: "总结一下我们之前的所有对话" +预期: 能够回顾更多历史消息 +``` + +#### 测试 qwen3-omni-flash (快速响应) +``` +提问: "快速回答:1+1=?" +预期: 极速响应 +``` + +--- + +## 🐛 常见问题排查 + +### 问题 1: 模型显示但没有变化 + +**检查点 1**: 确认服务配置正确 +```javascript +// 在控制台执行 +const providers = JSON.parse(localStorage.getItem('model-providers') || '[]') +const aliyun = providers.find(p => p.type === 'dashscope') +console.log('阿里云配置:', aliyun) +console.log('可用模型:', aliyun?.models) +``` + +**检查点 2**: 确认模型列表包含目标模型 +```javascript +// 在控制台执行 +const providers = JSON.parse(localStorage.getItem('model-providers') || '[]') +providers.forEach(p => { + console.log(`${p.name} (${p.type}):`, p.models) +}) +``` + +**检查点 3**: 查看控制台是否有错误 +- 红色错误信息 +- 黄色警告信息 +- 404/401/403 等 HTTP 错误 + +### 问题 2: 所有模型回答都一样 + +**可能原因**: +1. **服务类型配置错误**: 检查服务类型是否为 `dashscope` +2. **Base URL 错误**: 应该是 `https://dashscope.aliyuncs.com/compatible-mode/v1` +3. **模型参数未传递**: 查看日志中的 `📋 [makeChatRequestStream] 请求体 model 字段` +4. **API 不支持该模型**: 某些 API Key 可能没有权限使用特定模型 + +### 问题 3: API 返回模型不一致 + +如果看到这样的日志: +``` +✅ [响应确认] API 返回的模型: gpt-3.5-turbo + 请求的模型: qwen-turbo-latest + 模型匹配: ✗ 不一致! +``` + +**可能原因**: +1. **服务配置错误**: 可能连接到了错误的服务 +2. **模型映射问题**: API 可能自动映射到了其他模型 +3. **API Key 权限**: 该 API Key 可能无权使用指定模型 + +--- + +## 🔧 修复步骤 + +### 步骤 1: 验证服务配置 + +```javascript +// 在浏览器控制台执行 +const providers = JSON.parse(localStorage.getItem('model-providers') || '[]') +const aliyun = providers.find(p => p.type === 'dashscope') + +console.log('配置检查:') +console.log('✓ 服务类型:', aliyun.type) +console.log('✓ Base URL:', aliyun.baseUrl) +console.log('✓ API Key:', aliyun.apiKey?.substring(0, 10) + '...') +console.log('✓ 模型列表:', aliyun.models) +console.log('✓ 默认模型:', aliyun.defaultModel) +console.log('✓ 启用状态:', aliyun.enabled) +``` + +### 步骤 2: 重新配置模型列表 + +如果模型列表不正确: + +```javascript +// 在浏览器控制台执行 +const providers = JSON.parse(localStorage.getItem('model-providers') || '[]') +const aliyunIndex = providers.findIndex(p => p.type === 'dashscope') + +if (aliyunIndex >= 0) { + // 更新模型列表 + providers[aliyunIndex].models = [ + 'qwen-turbo-latest', + 'qwq-plus', + 'qwen-long', + 'qwen3-omni-flash' + ] + + // 保存 + localStorage.setItem('model-providers', JSON.stringify(providers)) + + console.log('✅ 模型列表已更新,请刷新页面') + setTimeout(() => location.reload(), 2000) +} +``` + +### 步骤 3: 测试连接 + +1. 进入"模型服务"设置 +2. 找到阿里云服务 +3. 点击"测试连接" +4. 查看是否成功 + +### 步骤 4: 清空缓存重试 + +```javascript +// 清空对话历史 +localStorage.removeItem('chat-conversations') +localStorage.removeItem('chat-topics') + +// 刷新页面 +location.reload() +``` + +--- + +## 📊 预期日志输出示例 + +### 正常情况 (切换模型成功) + +``` +🎯 [callModelStream] 用户选择的模型: qwq-plus +✅ [callModelStream] 找到匹配服务: 阿里云通义千问 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🔍 [callModelStream] 最终选择: + 服务: 阿里云通义千问 (dashscope) + 模型: qwq-plus + MCP: 未选择 + 工具: 0 个 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🎯 [makeChatRequestStream] 准备请求参数: + 服务类型: dashscope + 服务名称: 阿里云通义千问 + 使用模型: qwq-plus + 消息数量: 2 + 工具数量: 0 +📋 [makeChatRequestStream] 请求体 model 字段: qwq-plus +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +🚀 [最终确认] 即将发送请求: + 模型: qwq-plus + 服务: 阿里云通义千问 (dashscope) + URL: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +✅ [响应确认] API 返回的模型: qwq-plus + 请求的模型: qwq-plus + 模型匹配: ✓ 一致 +``` + +### 异常情况 (服务未找到) + +``` +🎯 [callModelStream] 用户选择的模型: unknown-model +⚠️ [callModelStream] 未找到包含该模型的服务,使用默认服务 +``` + +--- + +## 💡 使用建议 + +1. **首次使用**: 先用日志确认模型是否正确传递 +2. **测试对比**: 用不同模型测试相同问题,对比回答差异 +3. **性能对比**: 观察不同模型的响应速度 +4. **功能测试**: 用特定模型测试其特长(如 qwq-plus 测试推理) + +--- + +## 🆘 仍然有问题? + +如果以上方法都无法解决问题,请: + +1. 截图控制台完整日志 +2. 记录以下信息: + - 选择的模型名称 + - 服务配置(隐藏 API Key) + - 完整的控制台输出 + - 问题描述 + +3. 检查以下文件: + - `/web/src/services/chatService.ts` + - `/web/src/services/modelServiceManager.ts` + - localStorage 中的 `model-providers` + +--- + +**现在刷新页面,选择不同的模型,查看控制台日志,你应该能看到完整的模型选择和使用流程!** 🔍✨ diff --git a/todolist.md b/todolist.md index f850a32..efb5e1f 100644 --- a/todolist.md +++ b/todolist.md @@ -15,7 +15,6 @@ https://ark.cn-beijing.volces.com/api/v3 https://dashscope.aliyuncs.com/compatible-mode/v1 sk-2546da09b6d9471894aeb95278f96c11 - 2. 大模型选择不知道是否生效? 3. 阿里模型直接使用,模型ID。以后再考虑不要使用接口去获取。(先跑通) diff --git a/web/src/services/chatService.ts b/web/src/services/chatService.ts index ecc4a7f..10a8293 100644 --- a/web/src/services/chatService.ts +++ b/web/src/services/chatService.ts @@ -618,16 +618,28 @@ class ChatService { // 如果指定了模型,尝试找到拥有该模型的服务 if (model) { + console.log('🎯 [callModelStream] 用户选择的模型:', model) const foundService = services.find(s => s.models && s.models.includes(model) ) if (foundService) { service = foundService selectedModel = model + console.log('✅ [callModelStream] 找到匹配服务:', foundService.name) + } else { + console.warn('⚠️ [callModelStream] 未找到包含该模型的服务,使用默认服务') } + } else { + console.log('ℹ️ [callModelStream] 未指定模型,使用默认模型') } - console.log('🔍 [callModelStream] 使用流式服务:', service.name, '模型:', selectedModel) + console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━') + console.log('🔍 [callModelStream] 最终选择:') + console.log(' 服务:', service.name, `(${service.type})`) + console.log(' 模型:', selectedModel) + console.log(' MCP:', mcpServerId || '未选择') + console.log(' 工具:', tools.length, '个') + console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━') console.log('🚀 [callModelStream] === 开始真正的流式请求 ===') // 调用真正的流式API diff --git a/web/src/services/modelServiceManager.ts b/web/src/services/modelServiceManager.ts index 51d8bc7..6a54ea7 100644 --- a/web/src/services/modelServiceManager.ts +++ b/web/src/services/modelServiceManager.ts @@ -292,15 +292,13 @@ export class ModelServiceManager { break case 'dashscope': - // 阿里云 DashScope 格式 - if (data.data && Array.isArray(data.data)) { - return data.data.map((model: any) => model.id || model.model_id).filter(Boolean) - } - // 如果返回格式不同,尝试其他可能的格式 - if (data.models && Array.isArray(data.models)) { - return data.models.map((model: any) => model.id || model.model_id || model.name).filter(Boolean) - } - break + return [ + 'qwen-turbo-latest', // 通义千问 Turbo 最新版 - 高性价比,响应快 + 'qwen-plus', // 通义千问增强版 - 推理能力强 + 'qwen3-max', + 'qwen-long', // 通义千问长文本版 - 支持超长上下文(1M tokens) + 'qwen3-omni-flash' // 通义千问全能闪电版 - 多模态,极速响应 + ] case 'volcengine': // 火山引擎推荐模型列表 @@ -614,6 +612,13 @@ export class ModelServiceManager { let body: any = {} // 构建请求 (与非流式相同,但 stream: true) + console.log('🎯 [makeChatRequestStream] 准备请求参数:') + console.log(' 服务类型:', service.type) + console.log(' 服务名称:', service.name) + console.log(' 使用模型:', model) + console.log(' 消息数量:', messages.length) + console.log(' 工具数量:', tools?.length || 0) + switch (service.type) { case 'openai': case 'local': @@ -627,6 +632,7 @@ export class ModelServiceManager { stream: true, // ← 启用流式 ...(tools && tools.length > 0 ? { tools, tool_choice: 'auto' } : {}) } + console.log('📋 [makeChatRequestStream] 请求体 model 字段:', body.model) break case 'claude': @@ -662,6 +668,12 @@ export class ModelServiceManager { console.log('🔍 [makeChatRequestStream] 流式请求URL:', url) console.log('🔍 [makeChatRequestStream] 流式请求体大小:', JSON.stringify(body).length, '字节') + console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━') + console.log('🚀 [最终确认] 即将发送请求:') + console.log(' 模型:', body.model) + console.log(' 服务:', service.name, `(${service.type})`) + console.log(' URL:', url) + console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━') const controller = new AbortController() const timeoutId = setTimeout(() => controller.abort(), 60000) // 流式请求60秒超时 @@ -722,6 +734,14 @@ export class ModelServiceManager { if (line.startsWith('data: ')) { try { const data = JSON.parse(line.slice(6)) + + // 记录第一个响应中的模型信息 + if (chunkCount === 1 && data.model) { + console.log('✅ [响应确认] API 返回的模型:', data.model) + console.log(' 请求的模型:', body.model) + console.log(' 模型匹配:', data.model === body.model ? '✓ 一致' : '✗ 不一致!') + } + const delta = data.choices?.[0]?.delta // 处理普通内容