ZyphrZero commited on
Commit
8118659
·
1 Parent(s): d264039

Update test_tool_call_fix.py

Browse files
Files changed (1) hide show
  1. tests/test_tool_call_fix.py +105 -187
tests/test_tool_call_fix.py CHANGED
@@ -2,214 +2,132 @@
2
  # -*- coding: utf-8 -*-
3
 
4
  """
5
- 测试修复后的工具调用功能
6
  """
7
 
8
  import json
9
- import asyncio
10
- import httpx
11
  from typing import Dict, Any
12
 
13
- # 测试配置
14
- TEST_URL = "http://localhost:8080/v1/chat/completions"
15
- TEST_AUTH_TOKEN = "sk-test-key"
16
-
17
- # 测试工具定义
18
- TEST_TOOLS = [
19
- {
20
- "type": "function",
21
- "function": {
22
- "name": "get_weather",
23
- "description": "获取指定城市的天气信息",
24
- "parameters": {
25
- "type": "object",
26
- "properties": {
27
- "city": {
28
- "type": "string",
29
- "description": "城市名称"
30
- },
31
- "unit": {
32
- "type": "string",
33
- "enum": ["celsius", "fahrenheit"],
34
- "description": "温度单位"
35
- }
36
- },
37
- "required": ["city"]
38
- }
39
- }
40
- }
41
- ]
42
 
43
- async def test_tool_call_streaming():
44
- """测试流式工具调用"""
45
- print("🧪 开始测试流式工具调用...")
46
-
47
- payload = {
48
  "model": "glm-4.5",
49
  "messages": [
50
  {
51
- "role": "user",
52
- "content": "请帮我查询北京的天气,使用摄氏度"
53
  }
54
  ],
55
- "tools": TEST_TOOLS,
56
- "stream": True,
57
- "temperature": 0.7
58
- }
59
-
60
- headers = {
61
- "Content-Type": "application/json",
62
- "Authorization": f"Bearer {TEST_AUTH_TOKEN}"
 
 
 
 
 
 
 
 
 
 
 
 
63
  }
64
-
 
 
 
 
 
 
 
 
 
 
 
65
  try:
66
- async with httpx.AsyncClient(timeout=30.0) as client:
67
- async with client.stream(
68
- "POST",
69
- TEST_URL,
70
- json=payload,
71
- headers=headers
72
- ) as response:
73
- print(f"📡 响应状态: {response.status_code}")
74
- print(f"📡 响应头: {dict(response.headers)}")
75
-
76
- if response.status_code != 200:
77
- error_text = await response.aread()
78
- print(f"❌ 请求失败: {error_text.decode()}")
79
- return
80
-
81
- print("\n📦 开始接收流式数据:")
82
- print("-" * 80)
83
-
84
  chunk_count = 0
85
- tool_calls_found = False
86
-
87
- async for line in response.aiter_lines():
88
- if not line:
89
- continue
90
-
91
- if line.startswith("data: "):
92
  chunk_count += 1
93
- data_str = line[6:].strip()
94
-
95
- if data_str == "[DONE]":
96
- print(f"🏁 [{chunk_count:03d}] 流结束: [DONE]")
97
  break
98
-
99
  try:
100
  chunk = json.loads(data_str)
101
-
102
  # 检查是否包含工具调用
103
- choices = chunk.get("choices", [])
104
- if choices:
105
- choice = choices[0]
106
- delta = choice.get("delta", {})
107
- tool_calls = delta.get("tool_calls", [])
108
-
109
- if tool_calls:
110
- tool_calls_found = True
111
- print(f"🔧 [{chunk_count:03d}] 工具调用块:")
112
- for tool_call in tool_calls:
113
- print(f" ID: {tool_call.get('id', 'N/A')}")
114
- print(f" 类型: {tool_call.get('type', 'N/A')}")
115
- function = tool_call.get('function', {})
116
- print(f" 函数名: {function.get('name', 'N/A')}")
117
- print(f" 参数: {function.get('arguments', 'N/A')}")
118
- print(f" 参数类型: {type(function.get('arguments', 'N/A'))}")
119
-
120
- finish_reason = choice.get("finish_reason")
121
- if finish_reason:
122
- print(f"🏁 [{chunk_count:03d}] 完成原因: {finish_reason}")
123
-
124
- # 显示其他内容
125
- content = delta.get("content")
126
- if content:
127
- print(f"💬 [{chunk_count:03d}] 内容: {content}")
128
-
129
- # 显示usage信息
130
- usage = chunk.get("usage")
131
- if usage:
132
- print(f"📊 [{chunk_count:03d}] 使用统计: {usage}")
133
-
134
  except json.JSONDecodeError as e:
135
- print(f"❌ [{chunk_count:03d}] JSON解析错误: {e}")
136
- print(f" 原始数据: {data_str[:200]}...")
137
-
138
- print("-" * 80)
139
- print(f"✅ 测试完成,共处理 {chunk_count} 个数据块")
140
- print(f"🔧 工具调用检测: {'成功' if tool_calls_found else '失败'}")
141
-
142
- except Exception as e:
143
- print(f" 测试异常: {e}")
144
- import traceback
145
- traceback.print_exc()
146
-
147
- async def test_tool_call_non_streaming():
148
- """测试非流式工具调用"""
149
- print("\n🧪 开始测试非流式工具调用...")
150
-
151
- payload = {
152
- "model": "glm-4.5",
153
- "messages": [
154
- {
155
- "role": "user",
156
- "content": "请帮我查询上海的天气"
157
- }
158
- ],
159
- "tools": TEST_TOOLS,
160
- "stream": False,
161
- "temperature": 0.7
162
- }
163
-
164
- headers = {
165
- "Content-Type": "application/json",
166
- "Authorization": f"Bearer {TEST_AUTH_TOKEN}"
167
- }
168
-
169
- try:
170
- async with httpx.AsyncClient(timeout=30.0) as client:
171
- response = await client.post(TEST_URL, json=payload, headers=headers)
172
-
173
- print(f"📡 响应状态: {response.status_code}")
174
-
175
- if response.status_code == 200:
176
- result = response.json()
177
- print("📦 响应结果:")
178
- print(json.dumps(result, indent=2, ensure_ascii=False))
179
-
180
- # 检查工具调用
181
- choices = result.get("choices", [])
182
- if choices:
183
- message = choices[0].get("message", {})
184
- tool_calls = message.get("tool_calls", [])
185
- if tool_calls:
186
- print(f"🔧 发现 {len(tool_calls)} 个工具调用")
187
- for i, tool_call in enumerate(tool_calls):
188
- print(f" 工具 {i+1}: {tool_call}")
189
- else:
190
- print("❌ ��发现工具调用")
191
  else:
192
- print(f"❌ 请求失败: {response.text}")
193
-
 
194
  except Exception as e:
195
- print(f"❌ 测试异常: {e}")
196
-
197
- async def main():
198
- """主测试函数"""
199
- print("🚀 开始工具调用修复验证测试")
200
- print("=" * 80)
201
-
202
- # 测试流式工具调用
203
- await test_tool_call_streaming()
204
-
205
- # 等待一下
206
- await asyncio.sleep(2)
207
-
208
- # 测试非流式工具调用
209
- await test_tool_call_non_streaming()
210
-
211
- print("\n" + "=" * 80)
212
- print("🎯 测试完成")
213
 
214
  if __name__ == "__main__":
215
- asyncio.run(main())
 
2
  # -*- coding: utf-8 -*-
3
 
4
  """
5
+ 测试工具调用
6
  """
7
 
8
  import json
9
+ import urllib.request
10
+ import urllib.parse
11
  from typing import Dict, Any
12
 
13
+ def test_tool_call():
14
+ """测试工具调用功能"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
+ # 测试请求
17
+ test_request = {
 
 
 
18
  "model": "glm-4.5",
19
  "messages": [
20
  {
21
+ "role": "user",
22
+ "content": "请打开Google网站"
23
  }
24
  ],
25
+ "tools": [
26
+ {
27
+ "type": "function",
28
+ "function": {
29
+ "name": "playwri-browser_navigate",
30
+ "description": "Navigate to a URL in the browser",
31
+ "parameters": {
32
+ "type": "object",
33
+ "properties": {
34
+ "url": {
35
+ "type": "string",
36
+ "description": "The URL to navigate to"
37
+ }
38
+ },
39
+ "required": ["url"]
40
+ }
41
+ }
42
+ }
43
+ ],
44
+ "stream": True
45
  }
46
+
47
+ print("🚀 发送工具调用测试请求...")
48
+ print(f"📦 请求内容: {json.dumps(test_request, ensure_ascii=False, indent=2)}")
49
+
50
+ # 准备HTTP请求
51
+ url = "http://localhost:8080/v1/chat/completions"
52
+ data = json.dumps(test_request).encode('utf-8')
53
+
54
+ req = urllib.request.Request(url, data=data)
55
+ req.add_header('Content-Type', 'application/json')
56
+ req.add_header('Authorization', 'Bearer sk-test-key')
57
+
58
  try:
59
+ with urllib.request.urlopen(req) as response:
60
+ print(f"📈 响应状态: {response.status}")
61
+
62
+ if response.status == 200:
63
+ print("✅ 开始接收流式响应...")
64
+
65
+ tool_calls_found = []
 
 
 
 
 
 
 
 
 
 
 
66
  chunk_count = 0
67
+
68
+ for line in response:
69
+ line = line.decode('utf-8').strip()
70
+ if line.startswith('data: '):
 
 
 
71
  chunk_count += 1
72
+ data_str = line[6:] # 去掉 'data: ' 前缀
73
+
74
+ if data_str == '[DONE]':
75
+ print("🏁 接收到结束信号")
76
  break
77
+
78
  try:
79
  chunk = json.loads(data_str)
80
+
81
  # 检查是否包含工具调用
82
+ if 'choices' in chunk and chunk['choices']:
83
+ choice = chunk['choices'][0]
84
+ if 'delta' in choice and 'tool_calls' in choice['delta']:
85
+ tool_calls = choice['delta']['tool_calls']
86
+ if tool_calls:
87
+ for tool_call in tool_calls:
88
+ print(f"🔧 发现工具调用: {json.dumps(tool_call, ensure_ascii=False, indent=2)}")
89
+ tool_calls_found.append(tool_call)
90
+
91
+ # 检查完成原因
92
+ if choice.get('finish_reason') == 'tool_calls':
93
+ print(" 工具调用完成")
94
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  except json.JSONDecodeError as e:
96
+ print(f"❌ JSON解析错误: {e}, 数据: {data_str[:200]}")
97
+
98
+ print(f"📊 总共接收到 {chunk_count} 个数据块")
99
+ print(f"🔧 发现 {len(tool_calls_found)} 个工具调用")
100
+
101
+ # 分析工具调用格式
102
+ for i, tool_call in enumerate(tool_calls_found):
103
+ print(f"\n🔍 工具调用 {i+1} 分析:")
104
+ print(f" ID: {tool_call.get('id', 'N/A')}")
105
+ print(f" 类型: {tool_call.get('type', 'N/A')}")
106
+
107
+ if 'function' in tool_call:
108
+ func = tool_call['function']
109
+ print(f" 函数名: {func.get('name', 'N/A')}")
110
+
111
+ arguments = func.get('arguments', '')
112
+ print(f" 参数类型: {type(arguments)}")
113
+ print(f" 参数内容: {arguments}")
114
+
115
+ # 尝试解析参数
116
+ if isinstance(arguments, str) and arguments:
117
+ try:
118
+ parsed_args = json.loads(arguments)
119
+ print(f" ✅ 参数解析成功: {parsed_args}")
120
+ except json.JSONDecodeError as e:
121
+ print(f" ❌ 参数解析失败: {e}")
122
+ elif isinstance(arguments, dict):
123
+ print(f" ⚠️ 参数是对象格式(应该是字符串): {arguments}")
124
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  else:
126
+ error_text = response.read().decode('utf-8')
127
+ print(f"❌ 请求失败: {error_text}")
128
+
129
  except Exception as e:
130
+ print(f"❌ 请求异常: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
 
132
  if __name__ == "__main__":
133
+ test_tool_call()