OpenAI API Function Calling 教程
什么是 OpenAI API Function Calling
OpenAI API Function Calling(函数调用)是 OpenAI 在 2023 年推出的一项强大功能,它允许开发者将自定义函数描述传递给 GPT 模型,让模型能够智能地决定何时调用这些函数,并生成符合函数参数要求的 JSON 数据。这项功能极大地扩展了 AI 应用的能力边界,使得 GPT 模型可以与外部系统、数据库、API 服务无缝集成。
通过 OpenAI API Function Calling 教程,你可以构建出能够查询天气、预订酒店、操作数据库、控制智能家居等复杂功能的 AI 应用。本文将从基础概念到实战代码,全面讲解如何使用这一功能。
Function Calling 的工作原理
OpenAI 函数调用的核心流程分为三个步骤:
- 函数定义:开发者向 API 提供函数的名称、描述和参数结构(JSON Schema 格式)
- 模型判断:GPT 模型根据用户输入和函数描述,决定是否需要调用函数,并生成符合参数要求的 JSON
- 执行返回:开发者在本地执行函数,将结果返回给模型,模型基于结果生成最终回复
这种设计让模型保持无状态,所有函数执行都在开发者的控制之下,既保证了安全性,又提供了极大的灵活性。
快速开始:第一个 Function Calling 示例
Python 实现
以下是一个完整的 Python 示例,演示如何使用 OpenAI API Function Calling 实现天气查询功能:
import openai
import json
# 初始化 OpenAI 客户端
client = openai.OpenAI(api_key="your-api-key")
# 定义函数描述
functions = [
{
"name": "get_weather",
"description": "获取指定城市的天气信息",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名称,例如:北京、上海"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位"
}
},
"required": ["location"]
}
}
]
# 模拟天气查询函数
def get_weather(location, unit="celsius"):
# 实际应用中这里应该调用真实的天气 API
weather_data = {
"北京": {"temp": 15, "condition": "晴朗"},
"上海": {"temp": 20, "condition": "多云"}
}
return json.dumps(weather_data.get(location, {"error": "城市未找到"}))
# 第一次调用:让模型决定是否需要调用函数
response = client.chat.completions.create(
model="gpt-4-turbo",
messages=[{"role": "user", "content": "北京今天天气怎么样?"}],
functions=functions,
function_call="auto"
)
message = response.choices[0].message
# 检查模型是否要求调用函数
if message.function_call:
function_name = message.function_call.name
function_args = json.loads(message.function_call.arguments)
# 执行函数
if function_name == "get_weather":
function_response = get_weather(**function_args)
# 第二次调用:将函数结果返回给模型
second_response = client.chat.completions.create(
model="gpt-4-turbo",
messages=[
{"role": "user", "content": "北京今天天气怎么样?"},
message,
{
"role": "function",
"name": function_name,
"content": function_response
}
]
)
print(second_response.choices[0].message.content)
Node.js 实现
对于 Node.js 开发者,以下是等效的实现:
const OpenAI = require('openai');
const client = new OpenAI({
apiKey: 'your-api-key'
});
const functions = [
{
name: 'get_weather',
description: '获取指定城市的天气信息',
parameters: {
type: 'object',
properties: {
location: {
type: 'string',
description: '城市名称,例如:北京、上海'
},
unit: {
type: 'string',
enum: ['celsius', 'fahrenheit']
}
},
required: ['location']
}
}
];
function getWeather(location, unit = 'celsius') {
const weatherData = {
'北京': { temp: 15, condition: '晴朗' },
'上海': { temp: 20, condition: '多云' }
};
return JSON.stringify(weatherData[location] || { error: '城市未找到' });
}
async function main() {
const response = await client.chat.completions.create({
model: 'gpt-4-turbo',
messages: [{ role: 'user', content: '北京今天天气怎么样?' }],
functions: functions,
function_call: 'auto'
});
const message = response.choices[0].message;
if (message.function_call) {
const functionName = message.function_call.name;
const functionArgs = JSON.parse(message.function_call.arguments);
const functionResponse = getWeather(functionArgs.location, functionArgs.unit);
const secondResponse = await client.chat.completions.create({
model: 'gpt-4-turbo',
messages: [
{ role: 'user', content: '北京今天天气怎么样?' },
message,
{
role: 'function',
name: functionName,
content: functionResponse
}
]
});
console.log(secondResponse.choices[0].message.content);
}
}
main();
进阶技巧:多函数调用与并行处理
在实际应用中,你可能需要定义多个函数供模型选择。OpenAI API Function Calling 教程的进阶部分包括如何处理多函数场景:
定义多个函数
functions = [
{
"name": "get_weather",
"description": "获取天气信息",
"parameters": {...}
},
{
"name": "book_hotel",
"description": "预订酒店",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"},
"check_in": {"type": "string", "format": "date"},
"check_out": {"type": "string", "format": "date"}
},
"required": ["city", "check_in", "check_out"]
}
},
{
"name": "search_flights",
"description": "搜索航班",
"parameters": {...}
}
]
并行函数调用(GPT-4 Turbo 支持)
从 GPT-4 Turbo 开始,模型支持在一次响应中调用多个函数:
response = client.chat.completions.create(
model="gpt-4-turbo",
messages=[{
"role": "user",
"content": "帮我查一下北京的天气,并预订明天到后天的酒店"
}],
functions=functions,
function_call="auto"
)
# 处理多个函数调用
for tool_call in response.choices[0].message.tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
# 执行对应函数...
最佳实践与常见陷阱
1. 函数描述要清晰准确
模型完全依赖你提供的 description 字段来理解函数用途。描述越详细,模型的判断越准确。
2. 参数验证不可省略
虽然模型会尽力生成符合 JSON Schema 的参数,但仍需在代码中进行验证:
def get_weather(location, unit="celsius"):
if not location:
return json.dumps({"error": "location 参数不能为空"})
if unit not in ["celsius", "fahrenheit"]:
return json.dumps({"error": "unit 参数无效"})
# 正常处理...
3. 处理函数调用失败
当函数执行出错时,应该将错误信息返回给模型,让它生成友好的用户提示:
try:
result = call_external_api(params)
function_response = json.dumps(result)
except Exception as e:
function_response = json.dumps({"error": str(e)})
4. 控制函数调用行为
function_call 参数提供三种模式:
"auto":让模型自动决定(推荐){"name": "function_name"}:强制调用指定函数"none":禁用函数调用
实战案例:构建智能客服系统
以下是一个完整的智能客服示例,整合了订单查询、退款申请和常见问题解答:
functions = [
{
"name": "query_order",
"description": "查询订单状态",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "订单号"}
},
"required": ["order_id"]
}
},
{
"name": "request_refund",
"description": "申请退款",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string"},
"reason": {"type": "string", "description": "退款原因"}
},
"required": ["order_id", "reason"]
}
}
]
def handle_customer_service(user_message):
messages = [{"role": "user", "content": user_message}]
while True:
response = client.chat.completions.create(
model="gpt-4-turbo",
messages=messages,
functions=functions
)
message = response.choices[0].message
if not message.function_call:
return message.content
# 执行函数
function_name = message.function_call.name
function_args = json.loads(message.function_call.arguments)
if function_name == "query_order":
result = query_order_from_db(function_args["order_id"])
elif function_name == "request_refund":
result = process_refund(function_args["order_id"], function_args["reason"])
messages.append(message)
messages.append({
"role": "function",
"name": function_name,
"content": json.dumps(result)
})
性能优化与成本控制
使用 OpenAI API Function Calling 时需要注意成本控制:
- 减少不必要的函数定义:只传递当前对话可能用到的函数
- 使用流式响应:对于不需要函数调用的场景,启用
stream=True提升体验 - 缓存函数结果:对于相同参数的函数调用,可以缓存结果避免重复执行
- 选择合适的模型:GPT-3.5-turbo 也支持函数调用,成本更低
对于需要频繁调用 API 的应用,可以考虑使用 API 中转服务来优化请求路由和成本管理,这些服务通常提供负载均衡、请求缓存和更灵活的计费方式。
常见问题解答
Function Calling 支持哪些 OpenAI 模型?
目前支持函数调用的模型包括:gpt-4、gpt-4-turbo、gpt-4o、gpt-3.5-turbo(0613 版本及以后)。推荐使用 gpt-4-turbo 或 gpt-4o,它们支持并行函数调用和更复杂的参数推理。
函数调用会增加多少 Token 消耗?
函数定义会计入输入 Token,每个函数的描述和参数结构大约消耗 50-200 个 Token。函数调用的响应(包含 function_call 字段)也会计入输出 Token。建议在开发时使用 response.usage 监控实际消耗。
如何让模型更准确地选择函数?
关键在于函数的 description 字段。应该清晰描述函数的用途、适用场景和限制条件。例如:"查询指定日期范围内的订单,日期格式为 YYYY-MM-DD,最多支持查询 90 天内的数据"。
Function Calling 和 Plugins 有什么区别?
Function Calling 是开发者在代码中定义和执行函数,完全由开发者控制;Plugins(已废弃)是 OpenAI 托管的第三方服务。Function Calling 提供了更好的安全性、灵活性和性能。
可以在函数中调用外部 API 吗?
完全可以。Function Calling 的设计初衷就是让 GPT 模型能够与外部系统交互。你可以在函数中调用任何 API、查询数据库、操作文件系统等。只需确保将结果以 JSON 字符串形式返回给模型即可。
总结
通过本篇 OpenAI API Function Calling 教程,你已经掌握了从基础概念到实战应用的完整知识体系。函数调用功能让 GPT 模型从单纯的对话工具进化为能够执行实际任务的智能代理,极大地拓展了 AI 应用的可能性。
在实际开发中,建议从简单的单函数场景开始,逐步过渡到多函数并行调用的复杂应用。记住始终验证函数参数、处理异常情况,并通过合理的架构设计控制成本。随着对这项技术的深入理解,你将能够构建出更加智能、实用的 AI 应用。
通过 XiaoMu AI 使用所有主流 AI API
一个 API Key 访问 GPT-4o、Claude、Gemini 等全部模型。国内直连,无需翻墙,按量计费更省钱。
立即领取新用户赠送免费额度,无需绑定信用卡
常见问题
Function Calling 支持哪些 OpenAI 模型?
目前支持函数调用的模型包括:gpt-4、gpt-4-turbo、gpt-4o、gpt-3.5-turbo(0613 版本及以后)。推荐使用 gpt-4-turbo 或 gpt-4o,它们支持并行函数调用和更复杂的参数推理。
函数调用会增加多少 Token 消耗?
函数定义会计入输入 Token,每个函数的描述和参数结构大约消耗 50-200 个 Token。函数调用的响应(包含 function_call 字段)也会计入输出 Token。建议在开发时使用 response.usage 监控实际消耗。
如何让模型更准确地选择函数?
关键在于函数的 description 字段。应该清晰描述函数的用途、适用场景和限制条件。例如:"查询指定日期范围内的订单,日期格式为 YYYY-MM-DD,最多支持查询 90 天内的数据"。
Function Calling 和 Plugins 有什么区别?
Function Calling 是开发者在代码中定义和执行函数,完全由开发者控制;Plugins(已废弃)是 OpenAI 托管的第三方服务。Function Calling 提供了更好的安全性、灵活性和性能。
可以在函数中调用外部 API 吗?
完全可以。Function Calling 的设计初衷就是让 GPT 模型能够与外部系统交互。你可以在函数中调用任何 API、查询数据库、操作文件系统等。只需确保将结果以 JSON 字符串形式返回给模型即可。