OpenAI函数调用(Function Calling)机制的原理与实践详解

1. 概述

OpenAI的函数调用(Function Calling)功能为大语言模型(LLM)提供了与外部代码和服务交互的能力,可以直接通过模型调用自定义函数以实现数据获取或触发实际动作。本文将介绍函数调用的实现原理、函数定义规范、关键参数配置、典型应用场景及完整的Python实现流程。

2. 技术原理

函数调用机制允许开发者通过函数描述(Schema)将自定义代码暴露给模型。模型根据系统提示与用户消息决定是否调用这些函数,开发者再根据返回的调用指令执行相应代码并将结果反馈给模型,模型据此生成最终回复。

函数调用的主要应用方向包括:

  • 数据获取:如查询知识库、调用API获取实时数据(如天气、汇率等)。
  • 动作执行:如表单提交、接口调用、UI状态变更、发送邮件等。

3. 函数定义与Schema结构

函数通过JSON Schema进行定义,主要包括:

  • type:固定为function
  • name:函数名称(如get_weather
  • description:函数用途说明
  • parameters:函数参数JSON Schema定义
  • strict:是否启用严格模式(true时约束更强)

示例:

# 定义get_weather函数的Schema(示例)
tools = [
    {
        "type": "function",
        "name": "get_weather",
        "description": "获取指定地点的当前天气信息。",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "城市和国家,例如:Bogot\u00e1, Colombia"
                },
                "units": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "返回温度的单位,可选值:celsius或fahrenheit"
                }
            },
            "required": ["location", "units"],
            "additionalProperties": False
        },
        "strict": True
    }
]

4. 完整实践流程

4.1 定义业务函数

业务函数可调用外部API获取实际数据,如下为天气信息获取示例:

import requests

def get_weather(latitude, longitude):
    """
    获取指定坐标(经纬度)的实时气温
    :param latitude: 纬度(float)
    :param longitude: 经度(float)
    :return: 当前气温(摄氏度)
    """
    url = f"https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}&current=temperature_2m"
    response = requests.get(url)
    data = response.json()
    return data["current"]["temperature_2m"]

注意:此实现要求已将地理位置(如“Paris, France”)转换为对应的经纬度。

4.2 向模型发送函数Schema及用户请求

from openai import OpenAI
import json

client = OpenAI()

tools = [
    {
        "type": "function",
        "name": "get_weather",
        "description": "根据经纬度返回当前温度(摄氏度)",
        "parameters": {
            "type": "object",
            "properties": {
                "latitude": {"type": "number"},
                "longitude": {"type": "number"}
            },
            "required": ["latitude", "longitude"],
            "additionalProperties": False,
        },
        "strict": True
    }
]

input_messages = [
    {"role": "user", "content": "What's the weather like in Paris today?"}
]

response = client.responses.create(
    model="gpt-4.1",
    input=input_messages,
    tools=tools
)

4.3 解析模型函数调用并执行

# 假设模型输出如下:
# [
#   {"type": "function_call", "id": "fc_12345xyz", "call_id": "call_12345xyz", "name": "get_weather", "arguments": "{\"latitude\":48.8566, \"longitude\":2.3522}"}
# ]

tool_call = response.output[0]
args = json.loads(tool_call["arguments"])
result = get_weather(args["latitude"], args["longitude"])

4.4 返回函数执行结果并获取最终回复

# 将函数调用信息与执行结果加入消息序列,提交给模型生成最终回复
input_messages.append(tool_call)
input_messages.append({
    "type": "function_call_output",
    "call_id": tool_call["call_id"],
    "output": str(result)
})
response_2 = client.responses.create(
    model="gpt-4.1",
    input=input_messages,
    tools=tools
)
print(response_2.output_text)
# 输出示例:The current temperature in Paris is 14°C (57.2°F).

5. 多函数及批量调用场景

模型可能一次性调用多个函数,需遍历response.output批量执行,并用call_id关联返回。

def call_function(name, args):
    if name == "get_weather":
        return get_weather(**args)
    # 可拓展其他函数

for tool_call in response.output:
    if tool_call["type"] != "function_call":
        continue
    name = tool_call["name"]
    args = json.loads(tool_call["arguments"])
    result = call_function(name, args)
    input_messages.append({
        "type": "function_call_output",
        "call_id": tool_call["call_id"],
        "output": str(result)
    })

6. 重要参数及附加配置

6.1 工具选择(tool_choice)

  • auto(默认):模型自主决定调用零到多个函数。
  • required:要求必须调用一个或多个函数。
  • 指定函数:强制仅调用某个具体函数。
  • none:不提供任何函数,模拟普通对话。

6.2 并行调用与严格模式

  • parallel_tool_calls:为False时每次仅可调用一个函数。
  • strict:强烈建议开启,保证入参结构与Schema一致。

开启严格模式的Schema示例:

{
    "type": "function",
    "name": "get_weather",
    "description": "检索指定地点当前天气。",
    "strict": True,
    "parameters": {
        "type": "object",
        "properties": {
            "location": {"type": "string", "description": "城市+国家"},
            "units": {"type": ["string", "null"], "enum": ["celsius", "fahrenheit"], "description": "温度单位"}
        },
        "required": ["location", "units"],
        "additionalProperties": False
    }
}

7. 流式响应与进度监听

通过stream=True可实时获取模型函数调用及参数填充的进度事件,便于展现执行流。

流式监听代码示例:

from openai import OpenAI
client = OpenAI()

tools = [
    {
        "type": "function",
        "name": "get_weather",
        "description": "获取指定地点的当前天气。",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {"type": "string", "description": "城市和国家"}
            },
            "required": ["location"],
            "additionalProperties": False
        }
    }
]

stream = client.responses.create(
    model="gpt-4.1",
    input=[{"role": "user", "content": "What's the weather like in Paris today?"}],
    tools=tools,
    stream=True
)

for event in stream:
    print(event)  # 可监听到参数填充与函数触发的过程

8. 函数定义与调用实践建议

  • 明确函数名、参数说明和用途,详细描述每个参数的格式与场景。
  • 使用合理的枚举与对象结构,避免无效调用。
  • 保持函数数量精炼,通常建议不超过20个以保证准确率。
  • 如需批量并行调用,需确保输出结构和call_id的唯一性。

9. Token消耗说明

函数定义(Schema)会占用模型上下文的Token额度,请合理控制函数数量和描述长度。如遇Token限制,可尝试优化Schema精简描述。

10. 总结

OpenAI函数调用机制极大拓展了大模型与实际业务系统的融合能力。通过规范的Schema定义与严格的入参约束,配合流程化的调用与结果反馈,能够满足丰富的业务场景需求。开发者可根据实际需求灵活配置参数,实现数据获取、动作执行、自动代理等多样化功能。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐