LLM Function Calling 实战:让大语言模型帮你执行真实操作
你是否经历过这种场景?问 AI 天气怎么样,它能说出一堆建议,但没法帮你查一下实际温度。问能不能帮忙订个机票,它只能尴尬地说“抱歉,我做不到”。传统的 AI 对话本质上就是文字游戏——模型生成文字,仅此而已。
Function Calling 改变了这一切。
什么是 Function Calling
说白了,Function Calling 就是让 LLM 能够“动手干活”的能力。模型不再只能打字,它可以调用你写好的函数,执行数据库查询、调用外部 API、操作文件系统。你问“北京天气怎么样”,它真的会去查天气 API,然后告诉你结果并给出建议。
主流 LLM 厂商都支持这个功能,OpenAI、Anthropic、Google 还有国内的厂商都有实现。本文用 OpenAI API 演示,带你从头构建一个天气查询助手。
从零开始实现
第一步:设计函数定义
函数定义就是告诉模型“这个函数能干什么”。一个完整的定义包含这些字段:
- name:函数名,必须是有效的 Python 标识符
- description:函数用途,模型靠这个决定要不要调用
- parameters:参数规范,告诉模型每个参数是什么意思
天气查询函数的定义:
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如北京、上海"
},
"country_code": {
"type": "string",
"description": "国家代码,如 CN、US",
"default": "CN"
}
},
"required": ["city"]
}
}
}
]
city 是必填的,country_code 可选,默认中国。
第二步:两步式调用
这是关键点。普通对话是一次 API 调用,Function Calling 需要两步:
第一步:把用户请求和函数定义一起发给模型。模型会判断“要不要调用函数”,如果需要,它会返回一个函数调用请求,里面包含函数名和参数。
第二步:开发者执行实际的函数,然后把结果发回给模型。模型再根据结果生成最终回答。
为什么要这么设计?很简单——有些函数可能有副作用,比如删除数据、发送消息,总得让人写代码的人有机会拦截一下吧。
第三步:处理函数响应
模型返回的调用请求里有 function_name 和 arguments。拿到之后解析参数,执行真正的函数,然后把结果格式化成文本塞回去。
这里要特别注意的是错误处理。网络可能超时,API 可能挂了,参数可能不对——这些情况都要考虑到。
第四��:组装成完整对话
把以上步骤串起来,就是一个能多轮对话的系统了。用户可以不断追问,系统每次都判断是否需要调用函数。
完整代码
直接上代码,看完你就知道怎么用了:
import json
import requests
from openai import OpenAI
# 初始化客户端
client = OpenAI(api_key="your-api-key")
# 定义函数定义
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如北京、上海"
},
"country_code": {
"type": "string",
"description": "国家代码,如 CN、US(可选)",
"default": "CN"
}
},
"required": ["city"]
}
}
}
]
# 模拟天气查询函数
def get_weather(city: str, country_code: str = "CN") -> dict:
"""实际项目中这里调用真实天气 API"""
# 模拟返回数据
weather_data = {
"北京": {"temp": 22, "condition": "晴", "humidity": 45},
"上海": {"temp": 25, "condition": "多云", "humidity": 65},
"广州": {"temp": 28, "condition": "雷阵雨", "humidity": 80}
}
if city in weather_data:
return {"success": True, "data": weather_data[city]}
return {"success": False, "error": f"未找到城市 {city} 的天气信息"}
# 服装建议函数
def get_clothing_advice(temp: int, condition: str) -> str:
"""根据天气提供穿衣建议"""
if temp < 10:
return "建议穿羽绒服、保暖内衣,帽子围巾手套缺一不可。"
elif temp < 18:
return "建议穿毛衣、夹克,早晚温差大可以加件外套。"
elif temp < 25:
return "建议穿衬衫、长裤或轻薄外套,体感舒适。"
else:
return "建议穿短袖、短裤,注意防晒和补水。"
# 消息历史
messages = [
{"role": "system", "content": "你是一个贴心的天气助手,可以查询天气并给出穿衣建议。"}
]
def chat_with_functions(user_input: str):
messages.append({"role": "user", "content": user_input})
# 第一次调用:获取函数调用意图
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
tool_choice="auto"
)
assistant_message = response.choices[0].message
messages.append(assistant_message)
# 检查是否有函数调用
if assistant_message.tool_calls:
for tool_call in assistant_message.tool_calls:
function_name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)
print(f"\n[系统] 正在调用函数: {function_name}")
print(f"[系统] 参数: {arguments}")
# 执行函数
if function_name == "get_weather":
result = get_weather(**arguments)
if result["success"]:
weather = result["data"]
# 继续调用穿衣建议
advice = get_clothing_advice(weather["temp"], weather["condition"])
result_text = f"城市:{arguments['city']},温度:{weather['temp']}℃,天气:{weather['condition']},湿度:{weather['humidity']}%。{advice}"
else:
result_text = result["error"]
else:
result_text = f"未知函数: {function_name}"
# 将函数结果返回给模型
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result_text
})
# 第二次调用:生成最终回答
final_response = client.chat.completions.create(
model="gpt-4o",
messages=messages
)
final_message = final_response.choices[0].message.content
messages.append({"role": "assistant", "content": final_message})
return final_message
# 无需函数调用,直接返回回答
return assistant_message.content
# 测试对话
if __name__ == "__main__":
print("=" * 50)
print("天气助手已就绪,请输入您想查询的城市:")
print("=" * 50)
while True:
user_input = input("\n你: ").strip()
if not user_input:
continue
if user_input.lower() in ["exit", "quit", "退出"]:
print("再见!")
break
response = chat_with_functions(user_input)
print(f"\n助手: {response}")
运行效果
跑一下代码,看看实际效果:
测试一:查询北京天气
输入:北京天气怎么样?
输出:
[系统] 正在调用函数: get_weather
[系统] 参数: {'city': '北京', 'country_code': 'CN'}
助手: 北京今天天气晴朗,气温22℃,湿度45%。建议穿衬衫、长裤或轻薄外套,体感非常舒适,非常适合外出活动。
测试二:查询上海
输入:上海呢?
输出:
[系统] 正在调用函数: get_weather
[系统] 参数: {'city': '上海', 'country_code': 'CN'}
助手: 上海今天多云转阴,气温25℃,湿度65%。建议穿短袖、短裤即可,但考虑到湿度较大,最好随身携带雨具。
测试三:查询不存在的城市
输入:请问火星的天气如何?
输出:
[系统] 正在调用函数: get_weather
[系统] 参数: {'city': '火星', 'country_code': 'CN'}
助手: 抱歉,目前我的数据库中还没有火星的天气信息。如果您想查询地球上的城市天气,我很乐意帮忙!
模型能准确识别查询意图,自动调用天气函数,结合穿衣建议给出人性化回答。面对不存在的城市也能自然应对,不会崩掉。
总结
Function Calling 到底带来了什么?
最直接的变化是 AI 从“只动嘴”变成“能动手”。以前问天气只能说“建议带伞”,现在真能查完告诉你。虽然例子简单,但这个能力扩展出去可以做很多事:查数据库、调用第三方 API、操作云资源、发送通知——基本上普通代码能干的,AI 都能干了。
实现上要注意三点:
- 函数定义要写清楚 — 模型靠这个理解函数
- 两步式调用是标准流程 — 别偷懒
- 错误处理要做好 — 毕竟网络和 API 都不太可靠
想继续玩可以给助手加更多函数:空气质量、穿衣指数、旅游推荐。也可以试试流式输出,体验会更好。
这就是 Function Calling。开始动手吧。