3. 工具调用基础
任务目标
本案例将构建一个支持工具调用的Agent基础框架。Agent在收到用户问题时,能够自主判断是否需要调用外部工具(计算器、天气API),并根据工具返回结果生成最终回答。通过本案例,你将理解工具调用的核心机制:意图识别 → 工具执行 → 结果整合。
环境依赖
- Python 3.9+
- 安装依赖:
pip install(需配置有效的)
核心实现
以下代码实现了一个最小可用的工具调用Agent。它通过的Function Calling能力,让模型在需要时输出结构化工具调用请求,Agent执行工具后把结果回传给模型生成最终回答。代码中内置了两个工具:计算器(执行四则运算)和天气查询(模拟返回固定城市天气)。
import json
from import
client = () # 请确保环境变量 _ 已设置
# ---------- 工具定义 ----------
TOOLS = [
{
"type": "function",
"function": {
"name": "calculator",
"description": "执行四则运算,支持 + - * /",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "数学表达式,如 (3+5)*2"
}
},
"required": ["expression"]
}
}
},
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的当前天气",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如 北京"
}
},
"required": ["city"]
}
}
}
]
# ---------- 工具执行逻辑 ----------
def execute_tool(name: str, args: dict) -> str:
if name == "calculator":
# 安全计算:仅允许数字和运算符
expr = args["expression"].replace(" ", "")
if not all(c in "0123456789+-*/()." for c in expr):
return "错误:表达式包含非法字符"
try:
return str(eval(expr)) # 教学演示用,生产环境应使用安全解析器
except Exception as e:
return f"计算错误: {e}"
elif name == "get_weather":
# 模拟天气数据,实际可替换为真实API调用
mock_data = {"北京": "晴 25°C", "上海": "多云 28°C", "广州": "雷阵雨 30°C"}
return mock_data.get(args["city"], f"暂无{city}的天气数据")
return "未知工具"
# ---------- Agent 主循环 ----------
def agent_chat(user_input: str, max_turns: int = 3):
messages = [{"role": "user", "content": user_input}]
for _ in range(max_turns):
response = client.chat.completions.create(
model="-mini",
messages=messages,
tools=TOOLS,
tool_choice="auto"
)
msg = response.choices[0].message
# 情况1:模型没有请求调用工具,直接返回最终回答
if not msg.tool_calls:
return msg.content
# 情况2:模型请求调用工具,执行并回传结果
messages.append(msg) # 保留助手消息(含工具调用请求)
for tool_call in msg.tool_calls:
result = execute_tool(tool_call.function.name,
json.loads(tool_call.function.arguments))
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
return "已达到最大工具调用轮次,请简化问题后重试。"
# ---------- 测试入口 ----------
if __name__ == "__main__":
# 测试1:触发计算器工具
print("用户:计算 (23+17)*4 的结果")
print("Agent:", agent_chat("计算 (23+17)*4 的结果"))
print()
# 测试2:触发天气工具
print("用户:北京今天天气怎么样?")
print("Agent:", agent_chat("北京今天天气怎么样?"))
print()
# 测试3:无需工具直接回答
print("用户:你好,介绍一下你自己")
print("Agent:", agent_chat("你好,介绍一下你自己"))
运行与验证
- 将上述代码保存为
tool_agent.py。 - 在终端运行:
python tool_agent.py - 通过条件:观察输出,应满足以下三点——
① 第一个问题返回160(即 (23+17)*4 的计算结果);
② 第二个问题返回包含晴 25°C的天气描述;
③ 第三个问题返回正常的自我介绍文本,且不触发任何工具调用。
关键说明
- 工具调用流程:模型在需要时返回
tool_calls结构,Agent 负责执行对应函数并把结果以role="tool"的消息回传,模型据此生成最终回答。这是 Function Calling的标准交互模式。 - 安全提示:示例中计算器使用
eval仅为教学演示。生产环境应使用ast.literal_eval或专用表达式解析库(如asteval)来防止代码注入。 - 扩展真实API:将
get_weather中的模拟数据替换为对真实天气API(如OpenWeatherMap)的HTTP请求即可接入实际服务,无需改动Agent主循环逻辑。