SUMMARY_CN.md 4.7 KB

工具调用无限循环问题修复总结

问题现象

用户在使用工具调用(Tool Use)功能时,AI 会重复调用相同的工具,进入无限循环:

用户: 帮我看一下 index.html 是否提交
AI: 好的我来帮你检查
*tool use: git diff
*tool use: git status
AI: 用户说xxxx,好的我来帮你检查  ← 重复!
*tool use: git diff
*tool use: git status
AI: 用户说xxxx,我马上来检查  ← 又重复!
... 无限循环 ...

根本原因

代码位置claude_converter.pyprocess_history() 函数(第290-320行)

问题:合并连续USER消息时,没有区分包含 tool_result 的消息和普通文本消息,导致它们被错误地合并在一起。

具体场景

# 输入消息
[
  USER: "M: 检查文件",
  ASSISTANT: [tool_use...],
  USER: [tool_result...],     # 包含工具执行结果
  USER: "用户的跟进问题",     # 普通文本(连续的USER消息)
]

# 旧代码输出(错误)
[
  USER: "M: 检查文件",
  ASSISTANT: [tool_use...],
  USER: "用户的跟进问题" + [tool_result...]  # ❌ 被合并了!
]

后果

  • AI 无法识别已执行的工具调用
  • AI 无法识别已执行的工具调用
  • 消息历史不完整
  • AI 认为需要重新执行工具
  • 进入无限循环

修复方案

核心修复:merge_user_messages 函数

修改函数以收集并合并所有消息的 toolResults

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

双模式检测(性能优化)

添加智能检测,只在需要时才进行合并:

# 检测消息是否已正确交替
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%场景)直接返回,性能优化
  • ✅ 异常消息序列自动应用合并逻辑
  • ✅ 调试日志明确显示使用模式

修复后效果

# 连续USER消息(包含多个tool_result)
输入: [USER(r1), USER(r2), USER(text)]

# 旧代码(错误)
输出: {toolResults: [r1]}  # ❌ r2丢失

# 新代码(正确)
输出: {toolResults: [r1, r2], content: "text"}  # ✅ 全部保留

优势

  • ✅ 所有 toolResults 正确合并
  • ✅ AI 可以看到完整的工具执行历史
  • ✅ 消除无限循环
  • ✅ 提高对话质量
  • ✅ 性能优化(正常场景跳过合并)

测试验证

所有测试通过:

  • ✅ 正确交替的消息(快速路径,跳过合并)
  • ✅ 连续USER消息(合并路径)
  • ✅ 连续USER消息包含toolResults(正确合并所有toolResults)
  • ✅ 现有功能不受影响

代码质量:

  • ✅ 代码审查通过
  • ✅ 安全检查通过(CodeQL 0 alerts)

其他改进

  1. 消息顺序验证:新增 _validate_message_order() 函数
  2. 增强循环检测:改进 _detect_tool_call_loop() 函数
  3. 调试模式:环境变量 DEBUG_MESSAGE_CONVERSION=true
  4. 完善文档详细修复文档

如何使用

升级

  1. 拉取最新代码
  2. 重启服务
  3. 问题自动解决

调试(可选)

如果需要查看详细日志:

# 在 .env 中添加
DEBUG_MESSAGE_CONVERSION=true

# 重启服务后会看到详细的消息转换日志

相关资源


修复版本: v1.0
修复日期: 2025-12-08
影响范围: 所有使用工具调用的场景