#!/usr/bin/env python3 """ 测试多个工具调用的处理逻辑 """ import sys import os sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from app.utils.sse_tool_handler import SSEToolHandler def test_multiple_tool_calls(): """测试多个工具调用的处理""" handler = SSEToolHandler("test-model", stream=False) print("🧪 测试多个工具调用处理\n") # 模拟真实的多工具调用序列(基于日志) test_chunks = [ # 第一个工具调用开始 { "phase": "tool_call", "edit_content": '{"type": "mcp", "data": {"metadata": {"id": "call_5y5gir0mygx", "name": "mcp__playwright__browser_navigate", "arguments": "{\\"url\\":\\"https://www.bil", "result": "", "display_result": "", "duration": "...", "status": "completed", "is_error": false, "mcp_server": {"name": "mcp-server"}}, "thought": null, "ppt": null, "browser": null}}', "edit_index": 24 }, # 第一个工具调用参数补充 { "phase": "tool_call", "edit_content": 'ibili.com\\"}', "edit_index": 194 }, # 第一个工具调用结束 { "phase": "other", "edit_content": 'null, "display_result": "", "duration": "...", "status": "completed", "is_error": false, "mcp_server": {"name": "mcp-server"}}, "thought": null, "ppt": null, "browser": null}}', "edit_index": 219 }, # 第二个工具调用开始 { "phase": "tool_call", "edit_content": '{"type": "mcp", "data": {"metadata": {"id": "call_j8r24x6xtg", "name": "mcp__playwright__browser_snapshot", "arguments": "{}", "result": "", "display_result": "", "duration": "...", "status": "completed", "is_error": false, "mcp_server": {"name": "mcp-server"}}, "thought": null, "ppt": null, "browser": null}}', "edit_index": 406 }, # 第二个工具调用结束 { "phase": "other", "edit_content": 'null, "display_result": "", "duration": "...", "status": "completed", "is_error": false, "mcp_server": {"name": "mcp-server"}}, "thought": null, "ppt": null, "browser": null}}', "edit_index": 566 }, # 第三个工具调用开始(重复的 navigate) { "phase": "tool_call", "edit_content": '{"type": "mcp", "data": {"metadata": {"id": "call_scvwo0xaoil", "name": "mcp__playwright__browser_navigate", "arguments": "{\\"url\\":\\"https://www.bil", "result": "", "display_result": "", "duration": "...", "status": "completed", "is_error": false, "mcp_server": {"name": "mcp-server"}}, "thought": null, "ppt": null, "browser": null}}', "edit_index": 753 }, # 第三个工具调用参数补充 { "phase": "tool_call", "edit_content": 'ibili.com\\"}', "edit_index": 925 }, # 第三个工具调用结束 { "phase": "other", "edit_content": 'null, "display_result": "", "duration": "...", "status": "completed", "is_error": false, "mcp_server": {"name": "mcp-server"}}, "thought": null, "ppt": null, "browser": null}}', "edit_index": 950 } ] tool_calls_completed = [] for i, chunk in enumerate(test_chunks, 1): print(f"处理块 {i}: edit_index={chunk['edit_index']}, phase={chunk['phase']}") # 记录处理前的工具状态 old_tool_id = handler.tool_id old_tool_name = handler.tool_name old_has_tool_call = handler.has_tool_call # 处理块 results = list(handler.process_sse_chunk(chunk)) # 检查是否有新工具调用开始 if handler.tool_id != old_tool_id and handler.tool_id: print(f" 🎯 新工具调用开始: {handler.tool_name} (id: {handler.tool_id})") # 检查是否有工具调用完成 if old_has_tool_call and not handler.has_tool_call: tool_calls_completed.append({ "name": old_tool_name or "unknown", "id": old_tool_id }) print(f" ✅ 工具调用完成: {old_tool_name or 'unknown'}") print(f" 当前状态: has_tool_call={handler.has_tool_call}, tool_id={handler.tool_id}") print() print(f"📊 测试结果:") print(f" 完成的工具调用数量: {len(tool_calls_completed)}") for i, tool in enumerate(tool_calls_completed, 1): print(f" {i}. {tool['name']} (id: {tool['id']})") # 验证是否正确处理了所有工具调用 expected_tools = [ "mcp__playwright__browser_navigate", "mcp__playwright__browser_snapshot", "mcp__playwright__browser_navigate" ] completed_tool_names = [tool['name'] for tool in tool_calls_completed] if completed_tool_names == expected_tools: print("\n✅ 测试通过!正确处理了所有工具调用") print("📝 结论:重复的工具调用是上游发送的,我们的处理逻辑是正确的") return True else: print(f"\n❌ 测试失败!") print(f" 期望: {expected_tools}") print(f" 实际: {completed_tool_names}") return False if __name__ == "__main__": success = test_multiple_tool_calls() if success: print("\n🎯 总结:") print("1. 我们的 API 代理正确处理了每个不同的工具调用") print("2. 重复的工具调用是上游 Z.AI 模型发送的,不是我们的问题") print("3. 每个工具调用都有不同的 ID,说明这是模型的有意行为") print("4. 可能的原因:模型重试、验证操作、或处理复杂任务的策略") else: print("\n❌ 需要进一步调试处理逻辑")