# 🐛 Bug 修复:工具调用链断裂问题 ## 问题描述 从日志分析发现,AI 第一次成功调用了 `check_login_status` 工具,但第二次调用 AI 时没有传递工具列表,导致 AI 无法继续调用 `publish_content` 工具。 ## 问题现象 ### ✅ 第一次 AI 调用(成功) ```javascript 🎯 [makeChatRequestStream] 准备请求参数: 工具数量: 3 // ← 有工具 🔧 [makeChatRequestStream] 最终收集到工具调用: 1 个 工具 [0]: { name: "mcp__check_login_status", // ← AI 调用了检查登录 arguments: "{}" } ``` ### ❌ 第二次 AI 调用(问题) ```javascript 🎯 [makeChatRequestStream] 准备请求参数: 消息数量: 3 工具数量: 0 // ← 没有工具!AI 无法继续调用 publish_content ``` ## 根本原因 在 `executeToolCalls` 方法中,执行完工具后,将结果发送给 AI 时**没有传递 `tools` 参数**: ```typescript // ❌ 错误的代码 await modelServiceManager.sendChatRequestStream( service.id, messages, selectedModel, onChunk // 缺少 tools 参数! ) ``` 这导致 AI 在第二次调用时不知道有哪些工具可用,所以无法调用 `publish_content`。 --- ## 修复方案 ### 1. 添加 tools 参数 修改 `executeToolCalls` 方法签名,接收 tools 参数: ```typescript private async executeToolCalls( conversation: Conversation, toolCalls: any[], mcpServerId: string, model: string | undefined, onChunk: (chunk: string) => void, tools?: any[] // ← 新增 tools 参数 ): Promise ``` ### 2. 传递 tools 给第二次 AI 调用 ```typescript // ✅ 修复后的代码 await modelServiceManager.sendChatRequestStream( service.id, messages, selectedModel, onChunk, tools // ← 传递工具列表 ) ``` ### 3. 在调用处传递 tools ```typescript if (result.data?.toolCalls && result.data.toolCalls.length > 0 && mcpServerId) { await this.executeToolCalls( conversation, result.data.toolCalls, mcpServerId, model, onChunk, tools // ← 传递 tools ) } ``` --- ## 完整的工具调用链 修复后的完整流程: ``` 用户输入: "发布文章,主题:酸菜鱼" ↓ 第一次 AI 调用(带 tools) messages: [ { role: 'system', content: '你是一个智能助手...' }, { role: 'user', content: '发布文章,主题:酸菜鱼' } ] tools: [mcp__check_login_status, mcp__publish_content, ...] ← 有工具 ↓ AI 决策: "先检查登录状态" tool_calls: [{ name: 'mcp__check_login_status', arguments: '{}' }] ↓ 执行工具: check_login_status result: "✅ 登录状态正常" ↓ 第二次 AI 调用(带 tools)✅ 修复后 messages: [ { role: 'system', content: '...' }, { role: 'user', content: '...' }, { role: 'assistant', tool_calls: [...] }, { role: 'tool', content: '✅ 登录状态正常' } ] tools: [mcp__check_login_status, mcp__publish_content, ...] ← 有工具✅ ↓ AI 决策: "登录正常,现在发布内容" tool_calls: [{ name: 'mcp__publish_content', arguments: '{...}' }] ↓ 执行工具: publish_content result: "✅ 发布成功" ↓ 第三次 AI 调用(带 tools) ↓ AI 生成友好回复: "✅ 文章已成功发布!链接:..." ``` --- ## 测试验证 修复后重新测试: ``` 用户: 主题是:如何制作酸菜鱼,帮我生成内容。发布文章。 ``` **预期日志**: ```javascript // 第一次 AI 调用 🎯 [makeChatRequestStream] 工具数量: 3 🔧 AI 调用: mcp__check_login_status // 第二次 AI 调用(修复后) 🔧 [executeToolCalls] 继续传递工具列表: 3 个 ← 新增日志 🎯 [makeChatRequestStream] 工具数量: 3 ← 修复后有工具了! 🔧 AI 调用: mcp__publish_content // 第三次 AI 调用 🎯 [makeChatRequestStream] 工具数量: 3 ✅ AI 返回: "文章已成功发布..." ``` --- ## 技术要点 ### 为什么需要每次都传递 tools? 在 OpenAI Function Calling 机制中: 1. **AI 需要知道有哪些工具可用** - 每次调用 AI 时都需要传递完整的工具列表 - AI 根据上下文决定是否需要调用工具 2. **支持多轮工具调用** ``` AI → Tool A → AI → Tool B → AI → Tool C → AI ``` 每次 AI 调用都需要工具列表,才能决定下一步操作 3. **工具链的完整性** - 第一步:检查登录状态 - 第二步:发布内容 - 第三步:查询发布结果 - ... ### Cherry Studio 的实现 查看 Cherry Studio 源码可以确认,它也是每次都传递 tools: ```typescript // Cherry Studio 的实现 export async function executeToolCalls(toolCalls: any[], tools: any[]) { const toolResults = await Promise.all( toolCalls.map(call => executeTool(call)) ) // 继续调用 AI 时传递 tools return await sendMessage({ messages: [...history, ...toolResults], tools // ← 传递 tools }) } ``` --- ## 相关文件 - `/web/src/services/chatService.ts` - 核心修复位置 - Line 945: `executeToolCalls` 方法签名 - Line 1040: 传递 tools 给第二次 AI 调用 - Line 563: 调用 `executeToolCalls` 时传递 tools --- ## 总结 | 项目 | 修复前 | 修复后 | |------|--------|--------| | 第一次 AI 调用 | ✅ 有工具(3个) | ✅ 有工具(3个) | | 执行工具 | ✅ 成功执行 | ✅ 成功执行 | | 第二次 AI 调用 | ❌ 无工具(0个) | ✅ 有工具(3个)| | AI 能否继续调用 | ❌ 不能 | ✅ 能 | | 工具调用链 | ❌ 断裂 | ✅ 完整 | **修复状态**: ✅ 已修复 **测试状态**: ⏳ 待测试 **版本**: v1.0.2+ Bug Fix --- **更新时间**: 2024-01-15