前言

Function Calling(函数调用)是大语言模型(如GPT-3.5、GPT-4)的一个重要特性,它允许模型根据用户的需求,智能地决定是否需要调用外部工具或API,并生成符合要求的参数。这极大地扩展了模型的能力,使其能够执行一些它本身无法完成的任务,比如获取实时数据、执行计算、与数据库交互等。


一、Function Calling 是什么?—— 核心概念

简单来说,Function Calling 是让大语言模型根据用户的需求,智能地决定是否需要调用外部工具(函数),并自动生成正确的调用参数。

一个生动的比喻:

  • 没有 Function Calling:你向一个无所不知但被关在房间里的专家提问。他能告诉你理论,但无法实际操作。

  • 有 Function Calling:这位专家现在有了一个对讲机,可以指挥外面的助手(各种 API 和工具)去执行具体任务,比如查天气、订机票、分析数据,然后把结果告诉他,他再综合这些信息给你一个完整的答案。

技术定义: 它是一种特殊的提示工程技术,通过向模型描述可用的工具(函数),模型能够输出结构化的 JSON 数据,表明它希望调用哪个函数以及传递什么参数。

二、Function Calling的流程

Function Calling通常包含以下步骤:

  1. 定义函数:首先,开发者需要定义一系列可供模型调用的函数,包括函数名称、描述、参数(参数类型、描述等)。这些定义会作为系统提示的一部分提供给模型。

  2. 用户查询:用户提出一个自然语言请求。

  3. 模型决策:模型根据用户请求和可用的函数定义,决定是否需要调用函数。如果不需要,则直接生成自然语言回复;如果需要,则选择要调用的函数并生成参数。

  4. 执行函数:系统收到模型生成的函数调用请求后,在本地执行相应的函数(或调用API)。

  5. 结果返回:将函数执行的结果返回给模型。

  6. 生成回复:模型根据函数返回的结果,生成最终的自然语言回复给用户。

Function Calling 的整个过程是一个典型的“人机协同”循环,下图清晰地展示了其工作流:

这个过程的核心在于 步骤 1 中的函数定义。它通常是一个 JSON 对象,详细描述了函数的“身份”和“能力”,例如:

{
  "name": "get_current_weather", // 函数名
  "description": "Get the current weather in a given location", // 描述,模型据此判断是否调用
  "parameters": { // 参数定义,模型据此生成参数
    "type": "object",
    "properties": {
      "location": {
        "type": "string",
        "description": "The city and state, e.g. San Francisco, CA"
      },
      "unit": {
        "type": "string", 
        "enum": ["celsius", "fahrenheit"]
      }
    },
    "required": ["location"]
  }
}

三、Function Calling的参数定义

大语言模型本身有三大局限,Function Calling 正好解决了它们:

局限 Function Calling 的解决方案
知识截止 模型不知道最新信息(如今天天气、股价)。→ 可以调用 实时数据 API(天气、新闻、金融)。
无法执行操作 模型不能直接操作外部系统(如发邮件、查数据库)。→ 可以调用 外部服务 API(发送邮件、查询数据库)。
纯文本输出 模型输出是非结构化的自然语言。→ 可以强制模型输出 结构化数据(如 JSON),便于程序处理。

在OpenAI的API中,Function Calling是通过在聊天完成API(Chat Completions API)中传递functions参数来实现的。每个函数的定义包括:

  • name:函数名,模型通过这个名字来指定要调用的函数。

  • description:函数描述,模型通过描述来理解函数的作用。

  • parameters:函数的参数,是一个JSON Schema对象,定义了参数的类型、属性、是否必需等。

例如,一个获取天气函数的定义如下:

{
  "name": "get_current_weather",
  "description": "Get the current weather in a given location",
  "parameters": {
    "type": "object",
    "properties": {
      "location": {
        "type": "string",
        "description": "The city and state, e.g. San Francisco, CA"
      },
      "unit": {
        "type": "string",
        "enum": ["celsius", "fahrenheit"],
        "description": "The unit of temperature"
      }
    },
    "required": ["location"]
  }
}

四、API调用示例

以下是一个使用OpenAI Chat Completions API进行Function Calling的示例:

第一步:定义函数并发送用户请求

我们向API发送一个请求,包括用户消息和函数定义。

import openai
import json

# 定义函数列表
functions = [
    {
        "name": "get_current_weather",
        "description": "Get the current weather in a given location",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "The city and state, e.g. San Francisco, CA"
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "The unit of temperature"
                }
            },
            "required": ["location"]
        }
    }
]

# 用户消息
messages = [
    {"role": "user", "content": "What's the weather like in Boston?"}
]

# 调用API
response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-0613",
    messages=messages,
    functions=functions,
    function_call="auto"  # 让模型决定是否调用函数
)

第二步:模型响应

模型的响应可能如下:

{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1677652288,
  "model": "gpt-3.5-turbo-0613",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "function_call": {
          "name": "get_current_weather",
          "arguments": "{\"location\": \"Boston, MA\"}"
        }
      },
      "finish_reason": "function_call"
    }
  ]
}

注意,模型返回了一个function_call对象,其中包含了要调用的函数名和参数。

第三步:执行函数

我们根据模型返回的函数名和参数,在本地执行函数(或调用外部API)。

# 假设我们有一个函数get_current_weather
def get_current_weather(location, unit="fahrenheit"):
    # 这里应该是真实的天气API调用,这里用模拟数据
    weather_info = {
        "location": location,
        "temperature": "72",
        "unit": unit,
        "forecast": ["sunny", "windy"]
    }
    return json.dumps(weather_info)

# 从模型响应中提取函数名和参数
function_name = response.choices[0].message.function_call.name
function_args = json.loads(response.choices[0].message.function_call.arguments)

# 调用函数
function_response = get_current_weather(
    location=function_args.get("location"),
    unit=function_args.get("unit")
)

第四步:将函数结果返回给模型

我们将函数执行的结果作为新的消息追加到对话中,并再次调用API,让模型生成对用户的回复。

# 将函数调用的响应追加到消息列表
messages.append(response.choices[0].message)  # 添加助理的函数调用消息
messages.append(
    {
        "role": "function",
        "name": function_name,
        "content": function_response,
    }
)

# 再次调用API,让模型生成回复
second_response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo-0613",
    messages=messages,
)

# 这次模型会根据函数返回的结果生成自然语言回复
print(second_response.choices[0].message.content)

最终的回复可能是:“The weather in Boston is 72 degrees fahrenheit and it's sunny and windy.”

五、一个完整的代码示例(Python 伪代码)

假设我们有一个获取天气的函数。

# 1. 定义可用的函数列表(这是给模型看的“工具手册”)
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_current_weather",
            "description": "获取指定城市的当前天气情况",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {"type": "string", "description": "城市名称,例如:北京"},
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"], "description": "温度单位"}
                },
                "required": ["location"]
            }
        }
    }
]

# 2. 用户请求
user_query = "今天北京热吗?需要穿什么衣服?"

# 3. 第一次调用模型:让模型判断是否需要调用函数
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": user_query}],
    tools=tools, # 关键:把“工具手册”传给模型
    tool_choice="auto", # 让模型自己决定是否调用工具
)

response_message = response.choices[0].message

# 4. 检查模型是否想调用函数
if response_message.tool_calls:
    # 5. 解析模型生成的函数调用请求
    tool_call = response_message.tool_calls[0]
    function_name = tool_call.function.name
    function_args = json.loads(tool_call.function.arguments) # 模型生成的参数:{"location": "北京", "unit": "celsius"}

    # 6. 在开发者自己的代码中执行真实的函数
    if function_name == "get_current_weather":
        weather_data = get_current_weather(
            location=function_args.get("location"),
            unit=function_args.get("unit")
        ) # 假设返回:{"temperature": 28, "condition": "晴朗"}

    # 7. 第二次调用模型:把函数执行结果返回给模型,让它生成最终回答
    second_response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {"role": "user", "content": user_query},
            response_message, # 模型上次的回复(包含函数调用意图)
            {
                "role": "tool", # 关键:以“tool”的角色返回结果
                "content": json.dumps(weather_data),
                "tool_call_id": tool_call.id
            }
        ],
    )
    # 8. 输出最终答案
    print(second_response.choices[0].message.content)
    # 输出:"北京今天天气晴朗,气温28摄氏度。天气较热,建议穿短袖、短裤等夏装,并注意防晒。"
else:
    # 如果模型认为不需要调用函数,直接输出回答
    print(response_message.content)

六、Function Calling的注意事项

  1. 模型不会执行函数:模型只负责生成函数名和参数,实际执行由开发者负责。

  2. 安全性:由于模型生成的参数是文本,需要谨慎处理,避免注入攻击。确保对参数进行验证。

  3. 错误处理:函数执行可能会失败,需要有自己的错误处理机制,并将错误信息返回给模型,让模型决定如何回复用户。

  4. 成本:Function Calling会增加API调用的次数(有时需要两次调用:一次决定调用函数,一次根据函数结果生成回复),从而增加成本。

七、Function Calling 的核心优势

  1. 可靠性:模型输出的是结构化的 JSON,而非自由文本,极大降低了解析的难度和错误率。

  2. 安全性:模型只负责“思考”和“规划”,真正的操作(如发送邮件、支付)由开发者的安全代码执行,控制权在开发者手中。

  3. 能力扩展:理论上,可以为模型连接任何可通过 API 调用的服务,使其能力无限扩展。

  4. 标准化:OpenAI 等公司将其标准化,使得不同应用和工具之间的集成变得简单。

八、主要应用场景

场景 说明
RAG(检索增强生成) Function Calling 是实现 RAG 的优雅方式。可以将“向量数据库检索”定义为一个函数,模型在需要时调用它来获取相关知识。
AI Agent(智能代理) Agent 的核心就是“思考-行动”循环。Function Calling 为模型提供了“行动”的手段,使其能完成复杂多步任务。
自然语言接口 将任何软件系统(CRM、数据库、智能家居)的 API 封装成函数,用户就可以用自然语言与之交互。
数据提取与标准化 从非结构化的文本(如用户邮件、文档)中提取出结构化的信息(如订单号、客户需求),填入预定义的 JSON 格式。

总结

Function Calling是大语言模型与外部工具连接的关键桥梁,它使模型能够突破纯文本生成的限制,实现更复杂的功能。通过精心设计的函数描述和参数定义,可以引导模型在合适的场景下调用正确的函数,从而完成各种任务。

Function Calling 的本质是赋予大语言模型“动手能力”。它将模型的“大脑”(强大的理解和推理能力)与外部工具的“手脚”(执行能力)完美结合,是构建真正实用、强大的 AI 应用的核心技术之一。 它标志着大模型从“对话式AI”向“行动式AI”的范式转变。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐