update at 2025-10-15 15:07:45
This commit is contained in:
232
docs/BUG_FIX_TOOL_CHAIN.md
Normal file
232
docs/BUG_FIX_TOOL_CHAIN.md
Normal file
@@ -0,0 +1,232 @@
|
||||
# 🐛 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<void>
|
||||
```
|
||||
|
||||
### 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
|
||||
Reference in New Issue
Block a user