|
|
@@ -42,50 +42,92 @@ AI: 用户说xxxx,我马上来检查 ← 又重复!
|
|
|
|
|
|
**后果**:
|
|
|
- AI 无法识别已执行的工具调用
|
|
|
+- AI 无法识别已执行的工具调用
|
|
|
- 消息历史不完整
|
|
|
- AI 认为需要重新执行工具
|
|
|
- 进入无限循环
|
|
|
|
|
|
## 修复方案
|
|
|
|
|
|
-在合并逻辑中添加检测:
|
|
|
+### 核心修复:merge_user_messages 函数
|
|
|
+
|
|
|
+修改函数以收集并合并所有消息的 `toolResults`:
|
|
|
+
|
|
|
+```python
|
|
|
+def merge_user_messages(messages: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
|
+ all_tool_results = [] # 收集所有消息的 toolResults
|
|
|
+
|
|
|
+ for msg in messages:
|
|
|
+ msg_ctx = msg.get("userInputMessageContext", {})
|
|
|
+
|
|
|
+ if base_context is None:
|
|
|
+ base_context = msg_ctx.copy()
|
|
|
+ # 移除 toolResults,单独合并
|
|
|
+ if "toolResults" in base_context:
|
|
|
+ all_tool_results.extend(base_context.pop("toolResults"))
|
|
|
+ else:
|
|
|
+ # 从后续消息收集 toolResults
|
|
|
+ if "toolResults" in msg_ctx:
|
|
|
+ all_tool_results.extend(msg_ctx["toolResults"])
|
|
|
+
|
|
|
+ # 将合并的 toolResults 添加到结果
|
|
|
+ if all_tool_results:
|
|
|
+ result["userInputMessageContext"]["toolResults"] = all_tool_results
|
|
|
+```
|
|
|
+
|
|
|
+### 双模式检测(性能优化)
|
|
|
+
|
|
|
+添加智能检测,只在需要时才进行合并:
|
|
|
|
|
|
```python
|
|
|
-# 检测是否包含 tool_result
|
|
|
-has_tool_results = "toolResults" in user_ctx and user_ctx["toolResults"]
|
|
|
-
|
|
|
-if has_tool_results:
|
|
|
- # 不合并,保持独立
|
|
|
- history.append(item)
|
|
|
-else:
|
|
|
- # 可以合并
|
|
|
- pending_user_msgs.append(user_msg)
|
|
|
+# 检测消息是否已正确交替
|
|
|
+has_consecutive_same_role = False
|
|
|
+for item in raw_history:
|
|
|
+ current_role = "user" if "userInputMessage" in item else "assistant"
|
|
|
+ if prev_role == current_role:
|
|
|
+ has_consecutive_same_role = True
|
|
|
+ break
|
|
|
+ prev_role = current_role
|
|
|
+
|
|
|
+# 模式1:快速路径 - 消息已正确交替,跳过合并
|
|
|
+if not has_consecutive_same_role:
|
|
|
+ return raw_history
|
|
|
+
|
|
|
+# 模式2:合并路径 - 检测到连续的同角色消息,应用合并逻辑
|
|
|
+# ... 合并逻辑 ...
|
|
|
```
|
|
|
|
|
|
+**双模式优势**:
|
|
|
+- ✅ 正常对话(90%场景)直接返回,性能优化
|
|
|
+- ✅ 异常消息序列自动应用合并逻辑
|
|
|
+- ✅ 调试日志明确显示使用模式
|
|
|
+
|
|
|
## 修复后效果
|
|
|
|
|
|
```python
|
|
|
-# 相同的输入,修复后输出(正确)
|
|
|
-[
|
|
|
- USER: "M: 检查文件",
|
|
|
- ASSISTANT: [tool_use...],
|
|
|
- USER: [tool_result...], # ✅ 独立
|
|
|
- USER: "用户的跟进问题", # ✅ 独立
|
|
|
-]
|
|
|
+# 连续USER消息(包含多个tool_result)
|
|
|
+输入: [USER(r1), USER(r2), USER(text)]
|
|
|
+
|
|
|
+# 旧代码(错误)
|
|
|
+输出: {toolResults: [r1]} # ❌ r2丢失
|
|
|
+
|
|
|
+# 新代码(正确)
|
|
|
+输出: {toolResults: [r1, r2], content: "text"} # ✅ 全部保留
|
|
|
```
|
|
|
|
|
|
**优势**:
|
|
|
-- ✅ tool_result 消息保持独立
|
|
|
+- ✅ 所有 toolResults 正确合并
|
|
|
- ✅ AI 可以看到完整的工具执行历史
|
|
|
- ✅ 消除无限循环
|
|
|
- ✅ 提高对话质量
|
|
|
+- ✅ 性能优化(正常场景跳过合并)
|
|
|
|
|
|
## 测试验证
|
|
|
|
|
|
所有测试通过:
|
|
|
-- ✅ 标准工具调用流程(3条消息)
|
|
|
-- ✅ 多轮工具调用(5条消息,2轮对话)
|
|
|
-- ✅ 连续USER消息(包含tool_result + 普通文本)
|
|
|
+- ✅ 正确交替的消息(快速路径,跳过合并)
|
|
|
+- ✅ 连续USER消息(合并路径)
|
|
|
+- ✅ 连续USER消息包含toolResults(正确合并所有toolResults)
|
|
|
- ✅ 现有功能不受影响
|
|
|
|
|
|
代码质量:
|