OpenAI Function Calling 技术详解与实用示例

目录


概述

Function Calling 是 OpenAI 模型提供的一项能力,允许模型按照指定 schema 与用户自定义代码或外部服务进行交互。这一机制不仅可以从外部检索实时数据,还能驱动模型执行实际操作。本文将系统介绍其原理、示例代码及工程实践注意事项。

示例中 API 域名统一使用 https://zzzzapi.com,仅用于演示目的。实际项目请替换为自有或合规的服务地址。

应用场景

函数调用机制主要应用于以下两类需求:

  1. 数据检索(Fetching Data):如检索知识库、获取天气、实时行情等。
  2. 动作执行(Taking Action):如调用外部 API、发送邮件、修改应用状态、发起工单等。

功能调用基本流程

下列以“查询天气”为例,演示完整的 Function Calling 流程。

1. 函数 Schema 定义

定义函数调用工具,指定名称、描述及参数结构:

# 文件名:call_weather.py
from openai import OpenAI
client = OpenAI()

# 定义工具列表
tools = [
    {
        "type": "function",
        "name": "get_weather",
        "description": "获取指定地点当前温度(摄氏度)。",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "城市与国家,例如 'Paris, France'"
                }
            },
            "required": ["location"],
            "additionalProperties": False
        },
        "strict": True
    }
]

2. 向模型发送请求

将工具与用户消息一同发送至模型:

input_messages = [
    {"role": "user", "content": "请查询今天巴黎的天气。"}
]

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

模型若判定需要调用函数,会在 output 返回如下结构:

[
    {
        "type": "function_call",
        "id": "fc_12345xyz",
        "call_id": "call_12345xyz",
        "name": "get_weather",
        "arguments": {"location": "Paris, France"}
    }
]

3. 执行后端函数

实际函数需自行实现,如可通过公开 API 查询天气(示例,需合规使用实际 API):

# 文件名:weather_impl.py
import requests

def get_weather(location: str):
    # 此处建议本地维护一份地点到经纬度的映射表,或调用地理编码 API
    latitude, longitude = 48.8566, 2.3522  # 以巴黎为例
    url = "https://api.open-meteo.com/v1/forecast?latitude={}&longitude={}&current_weather=true".format(latitude, longitude)
    resp = requests.get(url, timeout=5)
    resp.raise_for_status()  # 错误处理,抛出异常
    data = resp.json()
    temp_c = data.get("current_weather", {}).get("temperature")
    return temp_c

4. 将结果返回模型

将函数结果按规范传回模型,供其生成最终回复:

tool_call = response.output[0]
result = get_weather(tool_call.arguments["location"])

input_messages.append(tool_call)  # 添加函数调用记录
input_messages.append({
    "type": "function_call_output",
    "call_id": tool_call.call_id,
    "output": str(result)
})

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

模型将自动融合结果生成最终回答。

定义函数与 Schema 规范

函数工具在 API 请求时通过 tools 参数传递。Schema 必须包含如下字段:

字段 作用
type 固定为 "function"
name 函数名,如 get_weather
description 函数用途及何时调用
parameters JSON Schema 格式定义输入参数
strict 是否启用严格模式

示例(带枚举和严格模式):

{
    "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
    }
}

Schema 设计建议

  • 说明函数用途及每个参数格式;包含必要示例。
  • 枚举参数可防止无效调用。
  • 推荐保持函数数量适中(建议≤20),避免模型理解困难。
  • 对输出类型、错误码等做明确约定。

错误处理与安全要点

  • 网络调用需设置超时(如 requests 的 timeout 参数),防止阻塞。
  • 使用 raise_for_status() 捕获 HTTP 错误。
  • 对 API 返回结果做字段有效性判定。
  • 速率限制与重试机制建议由业务层实现,以防 API 限流或失败。
  • 输入参数应校验,防止注入与异常。

并发、严格模式与附加配置

工具选择

tool_choice 参数可以控制是否强制调用某个工具或禁止函数调用。例如:

client.responses.create(
    model="gpt-4.1",
    input=input_messages,
    tools=tools,
    tool_choice="required"  # 强制至少调用一个函数
)

并发调用

parallel_tool_calls 默认允许模型一次调用多个函数。若需限制,设置 parallel_tool_calls=False

严格模式

启用 strict=True 可确保调用参数完全遵循 schema。需注意如下约束:

  • 所有 properties 字段必须为必填。
  • additionalProperties 必须为 false
  • 可使用 ["string", "null"] 标注可选字段。

流式函数调用

OpenAI 支持函数调用的流式输出,有助于实时追踪模型参数填充与调用进度。其事件类型包括:

  • response.output_item.added: 新增函数调用条目
  • response.function_call_arguments.delta: 参数填充增量
  • response.function_call_arguments.done: 参数填充完成

流式代码示例(简化):

stream = client.responses.create(
    model="gpt-4.1",
    input=input_messages,
    tools=tools,
    stream=True
)
final_tool_calls = {}
for event in stream:
    if event.type == "response.output_item.added":
        final_tool_calls[event.output_index] = event.item
    elif event.type == "response.function_call_arguments.delta":
        index = event.output_index
        if index in final_tool_calls:
            final_tool_calls[index].arguments.update(event.delta)

资源与性能注意事项

  • 工具 schema 会占用模型上下文令牌(token),影响性能与费用。
  • 推荐精简参数描述及函数数量。
  • 大量工具场景可考虑微调、缓存机制。

更新说明

  • 部分 API 实现与参数以 2024 年 6 月 OpenAI 文档为准,后续请关注官方变更。
  • 示例域名 https://zzzzapi.com 仅用于技术演示,实际应用需遵守服务合规性要求。

本文介绍了 OpenAI Function Calling 的完整工程流程及技术细节,涵盖 Schema 设计、调用实现、错误处理与流式追踪等关键环节。实际开发中请结合自身业务需求合理规划函数定义和安全策略。

Logo

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

更多推荐