Files
map-client-vue/docs/BUG_FIX_TOOL_CHAIN.md
2025-10-15 15:07:45 +08:00

5.7 KiB
Raw Blame History

🐛 Bug 修复:工具调用链断裂问题

问题描述

从日志分析发现AI 第一次成功调用了 check_login_status 工具,但第二次调用 AI 时没有传递工具列表,导致 AI 无法继续调用 publish_content 工具。

问题现象

第一次 AI 调用(成功)

🎯 [makeChatRequestStream] 准备请求参数:
   工具数量: 3  // ← 有工具

🔧 [makeChatRequestStream] 最终收集到工具调用: 1 
   工具 [0]: {
     name: "mcp__check_login_status",  // ← AI 调用了检查登录
     arguments: "{}"
   }

第二次 AI 调用(问题)

🎯 [makeChatRequestStream] 准备请求参数:
   消息数量: 3
   工具数量: 0  // ← 没有工具AI 无法继续调用 publish_content

根本原因

executeToolCalls 方法中,执行完工具后,将结果发送给 AI 时没有传递 tools 参数

// ❌ 错误的代码
await modelServiceManager.sendChatRequestStream(
  service.id,
  messages,
  selectedModel,
  onChunk
  // 缺少 tools 参数!
)

这导致 AI 在第二次调用时不知道有哪些工具可用,所以无法调用 publish_content


修复方案

1. 添加 tools 参数

修改 executeToolCalls 方法签名,接收 tools 参数:

private async executeToolCalls(
  conversation: Conversation,
  toolCalls: any[],
  mcpServerId: string,
  model: string | undefined,
  onChunk: (chunk: string) => void,
  tools?: any[]  // ← 新增 tools 参数
): Promise<void>

2. 传递 tools 给第二次 AI 调用

// ✅ 修复后的代码
await modelServiceManager.sendChatRequestStream(
  service.id,
  messages,
  selectedModel,
  onChunk,
  tools  // ← 传递工具列表
)

3. 在调用处传递 tools

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 生成友好回复:
    "✅ 文章已成功发布!链接:..."

测试验证

修复后重新测试:

用户: 主题是:如何制作酸菜鱼,帮我生成内容。发布文章。

预期日志

// 第一次 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

// 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