1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
|
"""
多工具 Agent:天气查询 + 股票价格查询
使用 GPT-5.4 构建,支持多轮对话
"""
import json
import os
import datetime
from openai import OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# ===================== 工具定义 =====================
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的当前天气信息,包括温度、天气状况、湿度和风力",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
},
"date": {
"type": "string",
"description": "查询日期,格式 YYYY-MM-DD,默认今天"
}
},
"required": ["city"]
}
}
},
{
"type": "function",
"function": {
"name": "get_stock_price",
"description": "查询股票的实时价格信息",
"parameters": {
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "股票代码,如 AAPL(苹果)、GOOGL(谷歌)、000001.SS(上证指数)"
},
"market": {
"type": "string",
"enum": ["us", "cn", "hk"],
"description": "市场:us(美股)、cn(A股)、hk(港股)"
}
},
"required": ["symbol"]
}
}
},
{
"type": "function",
"function": {
"name": "calculate",
"description": "执行数学计算,支持加减乘除、百分比、汇率换算等",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "数学表达式,如 '28 * 9/5 + 32' 或 '100 * (1 - 0.15)'"
}
},
"required": ["expression"]
}
}
}
]
# ===================== 工具实现 =====================
def get_weather(city: str, date: str = None) -> dict:
"""查询天气(模拟实现)"""
import random
if date is None:
date = datetime.date.today().isoformat()
# 模拟不同城市的天气
weather_patterns = {
"北京": {"temp_range": (15, 35), "conditions": ["晴", "多云", "阴", "小雨"]},
"上海": {"temp_range": (18, 33), "conditions": ["多云", "阴", "小雨", "晴"]},
"深圳": {"temp_range": (22, 36), "conditions": ["晴", "多云", "雷阵雨", "阴"]},
"东京": {"temp_range": (10, 28), "conditions": ["晴", "多云", "小雨"]},
"New York": {"temp_range": (5, 30), "conditions": ["晴", "多云", "Rain", "Snow"]},
}
pattern = weather_patterns.get(city, {"temp_range": (15, 30), "conditions": ["晴", "多云"]})
temp = random.randint(*pattern["temp_range"])
condition = random.choice(pattern["conditions"])
return {
"city": city,
"date": date,
"temperature": f"{temp}°C",
"condition": condition,
"humidity": f"{random.randint(30, 90)}%",
"wind": f"{random.choice(['微风', '轻风', '和风', '劲风'])} {random.randint(1, 6)}级"
}
def get_stock_price(symbol: str, market: str = "us") -> dict:
"""查询股价(模拟实现)"""
import random
# 模拟股价数据
mock_stocks = {
"AAPL": {"name": "苹果公司", "base_price": 198.50},
"GOOGL": {"name": "谷歌", "base_price": 175.20},
"MSFT": {"name": "微软", "base_price": 420.80},
"NVDA": {"name": "英伟达", "base_price": 880.50},
"000001.SS": {"name": "上证指数", "base_price": 3250.00},
}
stock = mock_stocks.get(symbol, {"name": symbol, "base_price": 100.00})
change_pct = random.uniform(-5, 5)
current_price = round(stock["base_price"] * (1 + change_pct / 100), 2)
return {
"symbol": symbol,
"name": stock["name"],
"market": market,
"current_price": f"${current_price}" if market == "us" else f"¥{current_price}",
"change_pct": f"{change_pct:+.2f}%",
"volume": f"{random.randint(10, 500)}M",
"timestamp": datetime.datetime.now().isoformat()
}
def calculate(expression: str) -> dict:
"""安全执行数学计算"""
import ast
import operator as op
# 安全的运算符映射
safe_ops = {
ast.Add: op.add,
ast.Sub: op.sub,
ast.Mult: op.mul,
ast.Div: op.truediv,
ast.Pow: op.pow,
ast.Mod: op.mod,
}
def _eval(node):
if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
return node.value
elif isinstance(node, ast.BinOp):
left = _eval(node.left)
right = _eval(node.right)
return safe_ops[type(node.op)](left, right)
elif isinstance(node, ast.UnaryOp):
return -_eval(node.operand)
else:
raise ValueError(f"不支持的表达式: {ast.dump(node)}")
try:
tree = ast.parse(expression, mode='eval')
result = _eval(tree.body)
return {"expression": expression, "result": result, "success": True}
except Exception as e:
return {"expression": expression, "error": str(e), "success": False}
# ===================== 工具路由 =====================
TOOL_MAP = {
"get_weather": get_weather,
"get_stock_price": get_stock_price,
"calculate": calculate,
}
def execute_tool(tool_call) -> str:
"""执行工具调用并返回结果"""
func_name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)
func = TOOL_MAP.get(func_name)
if func is None:
return json.dumps({"error": f"未知工具: {func_name}"})
try:
result = func(**arguments)
return json.dumps(result, ensure_ascii=False)
except Exception as e:
return json.dumps({"error": f"工具执行失败: {str(e)}"})
# ===================== Agent 循环 =====================
def run_agent(user_input: str, conversation_history: list = None, max_rounds: int = 5) -> str:
"""
运行 Agent,支持多轮工具调用
Args:
user_input: 用户输入
conversation_history: 对话历史
max_rounds: 最大工具调用轮数(防止无限循环)
Returns:
最终回复文本
"""
if conversation_history is None:
conversation_history = [
{
"role": "system",
"content": (
"你是一个智能助手,可以查询天气、股票价格,并进行数学计算。"
"请用自然、友好的方式回答用户的问题。"
"如果需要获取实时数据,请调用相应的工具。"
"你可以同时调用多个工具来获取完整信息。"
)
}
]
conversation_history.append({"role": "user", "content": user_input})
for round_num in range(max_rounds):
response = client.chat.completions.create(
model="gpt-5.4",
messages=conversation_history,
tools=tools,
tool_choice="auto",
)
message = response.choices[0].message
conversation_history.append(message.model_dump())
# 如果没有工具调用,返回最终回答
if not message.tool_calls:
return message.content
# 执行所有工具调用
print(f"[第{round_num + 1}轮] 模型请求调用 {len(message.tool_calls)} 个工具:")
for tc in message.tool_calls:
print(f" - {tc.function.name}({tc.function.arguments})")
for tool_call in message.tool_calls:
result = execute_tool(tool_call)
print(f" → 结果: {result[:100]}...")
conversation_history.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
return "抱歉,处理过程中出现了问题,请稍后再试。"
# ===================== 运行示例 =====================
if __name__ == "__main__":
# 示例1:单工具调用
print("=" * 60)
print("示例1:查询天气")
print("=" * 60)
answer = run_agent("北京今天天气怎么样?")
print(f"回答: {answer}\n")
# 示例2:多工具并行调用
print("=" * 60)
print("示例2:同时查询天气和股票")
print("=" * 60)
answer = run_agent("帮我看看北京天气,还有苹果和英伟达的股价")
print(f"回答: {answer}\n")
# 示例3:需要计算的调用
print("=" * 60)
print("示例3:带计算的查询")
print("=" * 60)
answer = run_agent("如果我在北京穿短袖出门,需要多少度以上才合适?另外帮我算算华氏温度")
print(f"回答: {answer}\n")
|