基于LLM进行工具调用或技能执行,是近期最热门的话题之一。
目前已经有很多LLM工具调用框架,比如langchain、openclaw、owl等。
然而,工具调用过程一般被封装在框架内,用户一般只能接触到各种配置,窥探不到调用细节。
这里尝试基于网络资料,模拟获取天气的函数,示例如何利用LLM进行Function Calling的过程。
1 环境准备
1.1 安装openai
如果尚未安装,首先安装 OpenAI 库。
pip install openai
1.2 配置openai
然后在代码中设置LLM的 API Key、Base Url,示例代码如下。
import os
model_name = gpt_model_name # LLM名称,比如deepseek-r1, qwen3.5-8b
os.environ['OPENAI_API_KEY'] = gpt_api_key # LLM供应商提供的api key
os.environ['OPENAI_BASE_URL'] = gpt_api_url # LLM供应商提供llm访问api的url
2 工具准备
由于是模拟一个获取天气的函数,让模型在需要时调用它。
所以在实际模拟之前,需要定义工具和实现函数。
2.1 定义可用的工具
定义可用工具,在这里即指定义Function。
需要以 JSON 格式描述函数,包括函数名、描述和参数。
这里定义一个获取城市天气的函数:
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的当前天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,例如:北京、上海"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位,默认为摄氏度"
}
},
"required": ["city"]
}
}
}
]
2.2 实现函数逻辑
这里通过字典实现一个及其简单的示例函数,模拟简单模拟返回一个字符串。
示例代码如下
def get_weather(city, unit="celsius"):
# 模拟天气数据
weather_data = {
"北京": {"celsius": "18°C 晴", "fahrenheit": "64°F 晴"},
"上海": {"celsius": "22°C 多云", "fahrenheit": "72°F 多云"},
}
info = weather_data.get(city, {}).get(unit, "未知城市或单位")
return f"{city}当前天气:{info}"
实际应用中,这里可以调用真实的天气 API。
3 调用示例
3.1 工具对话示例
这里发起带有 tools 的对话请求,发送用户消息,模型可能会决定是否调用函数。
对话示例代码如下。
from openai import OpenAI
# 2. 初始化客户端
client = OpenAI()
def chat_with_function():
messages = [{"role": "user", "content": "北京今天天气怎么样?"}]
response = client.beta.chat.completions.create(
model=model_name, # 或 gpt-4-turbo 等支持 function calling 的模型
messages=messages,
tools=tools,
tool_choice="auto", # 让模型自动决定是否调用函数
)
# 获取模型的响应
response_message = response.choices[0].message
print("初始响应:", response_message)
# 检查是否有工具调用请求
if response_message.tool_calls:
# 将模型的响应添加到对话历史
messages.append(response_message)
# 遍历所有工具调用
for tool_call in response_message.tool_calls:
function_name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)
if function_name == "get_weather":
# 调用我们实际的函数
result = get_weather(**arguments)
# 将函数执行结果作为消息返回
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result,
})
# 再次请求模型,将工具返回结果传递给模型,获得最终回答
second_response = client.beta.chat.completions.create(
model=model_name,
messages=messages,
tools=tools,
)
final_message = second_response.choices[0].message.content
print("最终回答:", final_message)
else:
# 没有工具调用,直接输出内容
print("回答:", response_message.content)
# 执行
chat_with_function()
以下是运行结果示例
初始响应: ChatCompletionMessage(content=None, refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageFunctionToolCall(id='chatcmpl-tool-8078c38xxxxxxx', function=Function(arguments='{"city": "北京"}', name='get_weather'), type='function')], reasoning='用户询问北京今天的天气情况。我需要使用 get_weather 工具来获取北京的天气信息。\n\n根据工具定义:\n- city 参数是必需的,用户已经提供了"北京"\n- unit 参数是可选的,默认是摄氏度,用户没有特别指定,所以使用默认值\n\n我应该调用 get_weather 函数,参数 city 设为"北京"。\n')
最终回答:
北京今天天气晴朗,当前气温为18°C。是个不错的天气,适合外出活动!
示例完整展示了Function Calling的基本流程,可根据业务需求扩展更多函数和更复杂的逻辑。
3.2 关键点说明
这里给出上述调用过程需要注意的一些地方。
1)工具描述
这里通过通过tools参数告知模型有哪些可用函数,描述要清晰,参数要准确。
2)模型决策
这里设置 tool_choice="auto"让模型自主判断是否需要调用函数。
也可以强制调用某个函数,如 {"type": "function", "function": {"name": "get_weather"}}。
3)处理响应
模型返回的tool_calls中包含了要调用的函数名和参数,执行后需要将结果以role: tool的形式追加到对话历史,并再次请求模型以获得最终自然语言回答。
4)支持多轮
如果一次响应中有多个工具调用,可以依次执行并汇总结果。
reference
OpenAI Function Call Streaming Example
OpenAI 函数调用:上手示例大全
https://docs.kanaries.net/zh/articles/openai-function-calling
大模型Function Call案例实战