引言
大型语言模型(LLM)虽然拥有强大的文本生成和理解能力,但它本质上是一个"封闭系统"------无法直接访问互联网、数据库或实时数据。为了让 LLM 真正具备"感知世界"的能力,我们需要为其配备"工具"(Tools),并通过 Function Calling(函数调用) 机制实现与外部世界的交互。
本文将带你从零开始,使用 Python + OpenAI 兼容 API(以 DeepSeek 为例),实现一个能自动查询天气的智能助手。你将学到:
- 如何定义并注册工具(Tool)
- 如何解析 LLM 的工具调用请求
- 如何执行真实函数并将结果返回给模型
- 如何完成完整的"用户提问 → 模型决策 → 调用工具 → 返回答案"闭环
1. 准备工作
安装依赖
pip install requests openai
导入必要库
javascript
import requests
import json
from openai import OpenAI
2. 编写天气查询工具函数
我们使用 心知天气 的免费 API 获取实时天气数据。
python
def get_weather(location: str) -> str:
"""
根据城市名称查询当前天气
:param location: 城市名,如 "北京"
:return: 天气描述字符串
"""
url = "https://api.seniverse.com/v3/weather/now.json"
params = {
"key": "---", # 替换为你自己的 API Key
"location": location,
"language": "zh-Hans"
}
try:
resp = requests.get(url, params=params, timeout=10)
data = resp.json()
if "results" in data:
r = data["results"][0]
city = r["location"]["name"]
now = r["now"]
text = now["text"]
temp = now["temperature"]
return f"{city}当前天气:{text},气温 {temp}℃"
else:
return "查询失败,请检查城市名称"
except Exception as e:
return f"请求异常:{e}"
3. 配置 LLM 客户端(以 DeepSeek 为例)
DeepSeek 的 API 兼容 OpenAI 协议,因此我们可以直接使用 openai SDK。
ini
client = OpenAI(
api_key='---', # 替换为你的 DeepSeek API Key
base_url='https://api.deepseek.com'
)
4. 定义工具(Tool)Schema
为了让 LLM 知道它可以调用哪些函数,我们需要提供结构化的工具描述:
ini
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的当前天气",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名称,如'北京'"
}
},
"required": ["location"]
}
}
}
]
这个 JSON Schema 告诉模型:
- 有一个叫
get_weather的函数可用 - 它需要一个
location字符串参数 - 它的作用是查天气
5. 实现完整的 Function Calling 流程
现在,我们模拟一次完整的对话:
ini
# 用户提问
messages = [{"role": "user", "content": "北京天气怎么样?"}]
# 第一次调用:让模型决定是否需要调用工具
response = client.chat.completions.create(
model="deepseek-reasoner",
messages=messages,
tools=tools,
tool_choice="auto",
temperature=0.1
)
# 获取模型返回的消息
response_message = response.choices[0].message
messages.append(response_message) # 将模型消息加入对话历史
# 检查是否需要调用工具
if response_message.tool_calls:
for tool_call in response_message.tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
# 执行对应函数
if function_name == "get_weather":
function_response = get_weather(function_args["location"])
else:
function_response = "未知工具"
# 将函数执行结果作为"tool"角色消息加入对话
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": function_response
})
# 第二次调用:将工具结果传回,让模型生成最终回答
final_response = client.chat.completions.create(
model="deepseek-reasoner",
messages=messages,
temperature=0.3
)
print(final_response.choices[0].message.content)
else:
# 不需要工具,直接输出模型回答
print(response_message.content)
6. 运行效果
当用户输入:
北京天气怎么样?
程序输出:
根据最新天气数据,北京当前天气:多云,气温 5℃。
整个过程如下:
- 用户提问
- LLM 判断需要调用
get_weather("北京") - 程序执行该函数,获取真实天气
- 将结果喂回 LLM
- LLM 生成自然语言回答
7. 关键点总结
| 步骤 | 说明 |
|---|---|
| 工具定义 | 使用 JSON Schema 描述函数签名 |
| 第一次调用 | 设置 tools 和 tool_choice="auto",让模型决定是否调用 |
| 解析 tool_calls | 从 response_message.tool_calls 中提取函数名和参数 |
| 执行真实函数 | 在本地运行 Python 函数(如网络请求) |
| 返回结果 | 以 role="tool" 的消息格式追加到对话历史 |
| 第二次调用 | 让模型基于工具结果生成最终回答 |
8. 扩展思考
- 可以注册多个工具(如查股票、发邮件、查数据库)
- 结合 LangChain 或 LlamaIndex 可构建更复杂的 Agent
- 注意控制上下文长度,避免因消息过长导致 token 超限
- 敏感操作需加入权限校验和安全过滤
结语
Function Calling 是 LLM 走出"幻觉牢笼"、连接现实世界的关键桥梁。通过本文的实践,你已经掌握了如何让大模型"动手做事"。下一步,不妨尝试接入更多 API,打造属于你自己的 AI 助手!