函数调用
大模型的函数调用(Function calling),其实就是工具调用,在整个agent
的结构中,工具的调用是很重要的一环,在感知环境和执行大模型给出的决策时都充当了重要的角色,下面我们利用天气查询的函数调用来举例说明。
在函数调用中,我们使用大模型目的是为了让它判断出用户当前的问题是否触及了“查询天气”、“查询时间”等情况,最终输出的是调用的函数名字,通过对应函数中搜索天气的举动,得到准确的天气数据,由于这些数据多而繁杂,可以将其交给大模型加工处理,最终就能输出成我们需要的对话。

那么首先我们来设计工具函数,这里仅举例,因此没有调用天气API,如果想深入了解如何操作,可以查看阿里云平台并且查看如何利用API调用天气数据。
- 定义工具函数
代码 :
# 模拟查询天气,不用API调用,直接输出{地点}今天是{天气}
def get_current_weather(arguments):
# 定义备选天气选项(固定好的)
weather_conditions=["晴天", "阴天", "小雨", "大雨", "雪天", "多云"]
# 随机选择一个天气
weather = random.choice(weather_conditions)
# 获取地点信息
location = arguments["location"]
# 输出内容
return f"{location}今天是{weather}"
# 模拟查询当前时间工具,不使用API调用,直接输出现在是{时间}
def get_current_time(arguments):
# 获取当前时间
now = datetime.now()
# 格式化时间为字符串
current_time = now.strftime("%Y年%m月%d日 %H:%M:%S")
# 输出内容
return f"现在是{current_time}"
- 创建tools数组
人类在选择工具之前,需要对工具有全面的了解,包括工具的功能、何时使用以及输入参数等。大模型也需要这些信息才能更准确地选择工具。通常来说,对于现在的大模型都会有对应的对话模板,其中会添加Function Calling的模板转换,那么我们只需要按照json模板要求的格式对输入参数处理即可,具体的json模板可以在Qwen官网找到,其他的模型可能会有不同,需要查找对应的官网文档教程来设计,这里我们仅看Qwen的json格式模板:
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "当你想查询指定城市的天气时非常有用。",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市或县区,比如北京市、杭州市、余杭区等。",
}
},
"required": ["location"]
}
}
}
其中:
type
字段固定为"function"
;function
字段为 Object 类型;name
字段为自定义的工具函数名称,建议使用与函数相同的名称,如get_current_weather
或get_current_time
;description
字段是对工具函数功能的描述,大模型会参考该字段来选择是否使用该工具函数。- **
parameters
**字段是对工具函数入参的描述,类型是 Object ,大模型会参考该字段来进行入参的提取。如果工具函数不需要输入参数,则无需指定parameters
参数。type
字段固定为"object"
;properties
字段描述了入参的名称、数据类型与描述,为 Object 类型,Key 值为入参的名称,Value 值为入参的数据类型与描述;required
字段指定哪些参数为必填项,为 Array 类型。
**parameters
**是我们需要的主要的参数设置,比如天气就需要“location”,股票需要“company”,新闻需要“name”、“time”、“matter”等等,名称随你设置,但是一般都需要type
,并且你需要设置下哪个参数是必须要大模型提供的,也就是required
。
- 融入对话模板
尽管在创建 tools 数组时已经对工具的作用与何时使用工具进行了描述,但在 System Message 中强调何时调用工具通常会提高工具调用的准确率。也就是说我们需要对message中的system进行修改:
提示词 :
你是一个很有帮助的助手。如果用户提问关于天气的问题,请调用 ‘get_current_weather’ 函数;
如果用户提问关于时间的问题,请调用‘get_current_time’函数。
请以友好的语气回答问题。
然后我们从apply_chat_template中看到,tools需要列表格式,其中包含函数调用的json模板,需要多少函数就写多少即可,然后在模板中添加,我们可以看下输出的效果:
代码 :
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
tools=tools,
)
输出 :
<|im_start|>system
你是一个很有帮助的助手。如果用户提问关于天气的问题,请调用 ‘get_current_weather’ 函数;
如果用户提问关于时间的问题,请调用‘get_current_time’函数。
请以友好的语气回答问题。
# Tools
You may call one or more functions to assist with the user query.
You are provided with function signatures within <tools></tools> XML tags:
<tools>
{"type": "function", "function": {"name": "get_current_weather", "description": "当你想查询指定城市的天气时非常有用。", "parameters": {"type": "object", "properties": {"location": {"type": "string", "description": "城市或县区,比如北京市、杭州市、余杭区等。"}}, "required": ["location"]}}}
{"type": "function", "function": {"name": "get_current_time", "description": "当你想知道现在的时间时非常有用。"}}
</tools>
For each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:
<tool_call>
{"name": <function-name>, "arguments": <args-json-object>}
</tool_call><|im_end|>
<|im_start|>user
你好,今天天气如何<|im_end|>
<|im_start|>assistant
可以看到function calling部分在模板中体现,而一旦我们问到天气、时间相关的问题的时候,就能触发相应的函数,最终模型输出的是调用的是具体哪一个函数名称,当然如果我们询问触及多个函数,也会返回多个函数,那么话不多说,我们下面看下实际效果:
- 运行
提示词 :
北京现在天气如何?
输出 :
<tool_call>
{"name": "get_current_weather", "arguments": {"location": "北京市"}}
</tool_call>
如果触及多个函数呢?
提示词 :
你好,现在几点了,北京天气如何
回答 :
<tool_call>
{"name": "get_current_time", "arguments": {}}
</tool_call>
<tool_call>
{"name": "get_current_weather", "arguments": {"location": "北京市"}}
</tool_call>
当然,模型给出的仅是需要调用的函数名称,我们还需要调用对应的函数运行,比如天气、时间,会给出具体的数据列表,而这往往不好直接输出,这时可以将给出的数据交给大模型进行进一步的处理:
提示词 :
用户提问的内容是你好,现在几点了,北京天气如何
模型给出的回答是[{'name': 'get_current_time', 'arguments': {}, 'output': '现在是2025年07月17日 16:25:05'}, {'name': 'get_current_weather', 'arguments': {'location': '北京市'}, 'output': '北京市今天是晴天'}]
请你根据用户提问的内容和模型给出的回答,组合成合适的回答用来回答用户的问题。
回答 :
您好!现在是2025年07月17日 16:25:05。同时,根据最新的天气信息,北京市今天是晴天。如果您还有其他问题需要了解的,欢迎随时询问!
那么很好!你已经成功完成了函数调用的整个流程,这其实是agent中工具起到的作用,贯穿了agent的整个流程。
下面我们提供了几个案例,有兴趣的小伙伴可以尝试实现,需要注意的是对于实时更新的一些资料,使用函数调用会有很好的效果,因为可以有效的避免大模型幻觉。
那么什么时候需要函数调用,什么时候没必要用函数调用,我们用一句话来理解,“能用规则 100% 搞定的,就别劳驾大模型;凡是输入语义多变、输出结构复杂、需要动态组合外部能力的场景,就上函数调用。”