跳转到内容

函数调用

大模型的函数调用(Function calling),其实就是工具调用,在整个agent的结构中,工具的调用是很重要的一环,在感知环境和执行大模型给出的决策时都充当了重要的角色,下面我们利用天气查询的函数调用来举例说明。

在函数调用中,我们使用大模型目的是为了让它判断出用户当前的问题是否触及了“查询天气”、“查询时间”等情况,最终输出的是调用的函数名字,通过对应函数中搜索天气的举动,得到准确的天气数据,由于这些数据多而繁杂,可以将其交给大模型加工处理,最终就能输出成我们需要的对话。

函数调用原理

那么首先我们来设计工具函数,这里仅举例,因此没有调用天气API,如果想深入了解如何操作,可以查看阿里云平台并且查看如何利用API调用天气数据。

  1. 定义工具函数

代码

Python
# 模拟查询天气,不用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}"
  1. 创建tools数组

人类在选择工具之前,需要对工具有全面的了解,包括工具的功能、何时使用以及输入参数等。大模型也需要这些信息才能更准确地选择工具。通常来说,对于现在的大模型都会有对应的对话模板,其中会添加Function Calling的模板转换,那么我们只需要按照json模板要求的格式对输入参数处理即可,具体的json模板可以在Qwen官网找到,其他的模型可能会有不同,需要查找对应的官网文档教程来设计,这里我们仅看Qwen的json格式模板:

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_weatherget_current_time
    • description字段是对工具函数功能的描述,大模型会参考该字段来选择是否使用该工具函数。
    • **parameters**字段是对工具函数入参的描述,类型是 Object ,大模型会参考该字段来进行入参的提取。如果工具函数不需要输入参数,则无需指定parameters参数。
      • type字段固定为"object"
      • properties字段描述了入参的名称、数据类型与描述,为 Object 类型,Key 值为入参的名称,Value 值为入参的数据类型与描述;
      • required字段指定哪些参数为必填项,为 Array 类型。

**parameters**是我们需要的主要的参数设置,比如天气就需要“location”,股票需要“company”,新闻需要“name”、“time”、“matter”等等,名称随你设置,但是一般都需要type,并且你需要设置下哪个参数是必须要大模型提供的,也就是required

  1. 融入对话模板

尽管在创建 tools 数组时已经对工具的作用与何时使用工具进行了描述,但在 System Message 中强调何时调用工具通常会提高工具调用的准确率。也就是说我们需要对message中的system进行修改:

提示词

Plain
你是一个很有帮助的助手。如果用户提问关于天气的问题,请调用 ‘get_current_weather’ 函数;
如果用户提问关于时间的问题,请调用‘get_current_time’函数。
请以友好的语气回答问题。

然后我们从apply_chat_template中看到,tools需要列表格式,其中包含函数调用的json模板,需要多少函数就写多少即可,然后在模板中添加,我们可以看下输出的效果:

代码

Python
text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True,
    tools=tools,
)

输出

Plain
<|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部分在模板中体现,而一旦我们问到天气、时间相关的问题的时候,就能触发相应的函数,最终模型输出的是调用的是具体哪一个函数名称,当然如果我们询问触及多个函数,也会返回多个函数,那么话不多说,我们下面看下实际效果:

  1. 运行

提示词

Plain
北京现在天气如何?

输出

Plain
<tool_call>
{"name": "get_current_weather", "arguments": {"location": "北京市"}}
</tool_call>

如果触及多个函数呢?

提示词

Plain
你好,现在几点了,北京天气如何

回答

Plain
<tool_call>
{"name": "get_current_time", "arguments": {}}
</tool_call>
<tool_call>
{"name": "get_current_weather", "arguments": {"location": "北京市"}}
</tool_call>

当然,模型给出的仅是需要调用的函数名称,我们还需要调用对应的函数运行,比如天气、时间,会给出具体的数据列表,而这往往不好直接输出,这时可以将给出的数据交给大模型进行进一步的处理:

提示词

Plain
用户提问的内容是你好,现在几点了,北京天气如何
模型给出的回答是[{'name': 'get_current_time', 'arguments': {}, 'output': '现在是2025年07月17日 16:25:05'}, {'name': 'get_current_weather', 'arguments': {'location': '北京市'}, 'output': '北京市今天是晴天'}]
请你根据用户提问的内容和模型给出的回答,组合成合适的回答用来回答用户的问题。

回答

Plain
您好!现在是2025年07月17日 16:25:05。同时,根据最新的天气信息,北京市今天是晴天。如果您还有其他问题需要了解的,欢迎随时询问!

那么很好!你已经成功完成了函数调用的整个流程,这其实是agent中工具起到的作用,贯穿了agent的整个流程。

下面我们提供了几个案例,有兴趣的小伙伴可以尝试实现,需要注意的是对于实时更新的一些资料,使用函数调用会有很好的效果,因为可以有效的避免大模型幻觉。

那么什么时候需要函数调用,什么时候没必要用函数调用,我们用一句话来理解,“能用规则 100% 搞定的,就别劳驾大模型;凡是输入语义多变、输出结构复杂、需要动态组合外部能力的场景,就上函数调用。”