OpenAI Function Calling学习笔记01
2024-08-18
函数调用是OpenAI的 GPT-4 和 GPT-3.5 Turbo 模型的一项高级功能,它允许模型根据用户的指示决定是否调用特定的函数,并以结构化的形式返回信息,而不仅仅是提供文本回答。这种将大型语言模型与外部工具和API整合的能力,大大增强了模型的应用潜力。
例如,大模型本身无法获取实时天气信息,因为它没有实时数据功能。但通过函数调用,AI可以与外部系统互动,如访问信息检索系统、查询实时天气或执行代码等。这使得基于大型语言模型的智能代理能够执行更复杂的任务,显著提高了模型的实用性和应用范围。
本文是对OpenAI Guide: 《Function calling》的学习笔记。基于Function Calling可以将大语言模型连接到外部工具。
1.什么是Function Calling #
Function Calling允许将类似gpt-4o的模型连接到外部工具和系统。这对于许多方面都很有用,例如为AI助手赋能,或在应用程序和模型之间构建深度集成。
基于OpenAI的结构化输出
功能。当在函数定义中设置strict: true
时,开启结构化输出功能,可以确保模型为Function Calling生成的参数与在函数定义中提供的JSON Schema完全匹配。
作为Function Calling的替代方案,可以选择约束模型的常规输出以匹配你所选择的JSON Schema。在《When to use Structured Outputs via function calling vs via response_format》中了解更多关于何时使用function calling以及何时使用response_format来控制模型的正常输出。
1.1 示例用例 #
Function Calling适用于大量用例,例如:
- 启用助手(assistants)获取数据: 当用户询问“我的最近订单是什么?”时,AI助手需要从内部系统获取最新的客户数据,然后才能生成对用户的响应。
- 启用助手采取行动: AI助手需要根据用户偏好和日历可用性安排会议。
- 启用助手执行计算: 数学辅导助手需要执行数学计算。
- 构建丰富的流程: 数据提取管道获取原始文本,然后将其转换为结构化数据并保存到数据库中。
- 修改应用程序的UI: 可以使用Function Calling根据用户输入更新UI,例如渲染地图上的一个pin点。
2.Function Calling的生命周期 #
- 代码调用LLM API: 你的应用程序向API发送请求,其中包含你的提示(prompt)以及LLM可以调用的函数的定义。
- LLM做出决策: LLM会根据你的提示和函数定义,决定是直接回复用户,还是"可以调用"一个或多个函数。
- LLM API返回结果: API会将LLM的决策返回给你的应用程序,其中包含需要调用的函数名称以及对应的参数。
- 执行函数: 你的应用程序根据LLM API返回的信息,调用指定的函数,并传入对应的参数。
- 再次调用LLM API: 你的应用程序将函数执行的结果以及原始提示再次发送给LLM API,以便LLM能够结合新的信息生成更准确的回复。
当使用OpenAI API进行Function Calling时,模型本身不会实际执行函数,而只是在步骤3生成可以用来调用函数的参数。你的代码可以选择如何处理这些参数,通常是通过调用指定的函数。应用程序始终处于完全控制状态。
3.如何使用Function Calling #
Function Calling支持Chat Completions API、Assistants API 和 Batch API。本指南重点介绍使用Chat Completions API的函数调用。有单独的指南介绍使用Assistants API的function calling。
对于以下示例,我们将构建一个能够帮助用户处理送货订单的对话式助手。与要求用户填写传统表单不同,你的用户可以与AI驱动的助手聊天。为了使助手能够提供帮助,我们希望赋予它查找订单并回复有关用户订单真实数据的能力。
3.1 步骤 1:选择代码库中模型可以调用的函数 #
Function Calling的起点是在你的代码库中选择你希望模型能够生成参数的函数。
对于这个示例,让我们假设你希望允许模型调用代码库中的 get_delivery_date
函数,该函数接受一个 order_id
并查询你的数据库以确定给定订单的送货日期。你的函数可能看起来像下面这样。
1# 这将是模型可以调用的函数
2def get_delivery_date(order_id: str) -> datetime:
3 # 连接数据库
4 conn = sqlite3.connect('ecommerce.db')
5 cursor = conn.cursor()
6 # ...
3.2 步骤 2:向模型描述你的函数,以便理解该如何调用 #
现在我们知道了希望允许模型调用的函数,我们将创建一个“函数定义”来向模型描述该函数。该定义描述了函数的作用(以及可能应该何时调用)以及调用函数所需的参数。
函数定义的 parameters
部分应使用JSON Schema 描述。如果模型生成函数调用,它将使用此信息根据你提供的schema生成参数。
在这个示例中,它可能看起来像这样:
1{
2 "name": "get_delivery_date",
3 "description": "Get the delivery date for a customer's order. Call this whenever you need to know the delivery date, for example when a customer asks 'Where is my package'",
4 "parameters": {
5 "type": "object",
6 "properties": {
7 "order_id": {
8 "type": "string",
9 "description": "The customer's order ID.",
10 },
11 },
12 "required": ["order_id"],
13 "additionalProperties": false,
14 }
15}
3.3 步骤 3:将你的函数定义作为可用tools与messages一起传递给模型 #
接下来,我们需要在调用Chat Completions API时,将函数定义作为tools
数组的一部分提供。
像往常一样,我们将提供一个messages数组,其中可能包含你的提示(prompt)或用户(user)和助手(assistant)之间完整的对话。
此示例展示了如何调用 Chat Completions API,为处理商店客户查询的助手提供相关函数和消息。
1tools = [
2 {
3 "type": "function",
4 "function": {
5 "name": "get_delivery_date",
6 "description": "Get the delivery date for a customer's order. Call this whenever you need to know the delivery date, for example when a customer asks 'Where is my package'",
7 "parameters": {
8 "type": "object",
9 "properties": {
10 "order_id": {
11 "type": "string",
12 "description": "The customer's order ID.",
13 },
14 },
15 "required": ["order_id"],
16 "additionalProperties": False,
17 },
18 }
19 }
20]
21
22messages = [
23 {"role": "system", "content": "You are a helpful customer support assistant. Use the supplied tools to assist the user."},
24 {"role": "user", "content": "Hi, can you tell me the delivery date for my order?"}
25]
26
27response = openai.chat.completions.create(
28 model="gpt-4o",
29 messages=messages,
30 tools=tools,
31)
3.4 步骤 4:接收并处理模型响应 #
3.4.1 如果模型决定不调用函数 #
如果模型没有生成函数调用,则响应将以与普通Chat Completions相同的方式包含对用户的直接回复。
例如,在这种情况下,chat_response.choices[0].message
可能包含:
1chat.completionsMessage(content='Hi there! I can help with that. Can you please provide your order ID?', role='assistant', function_call=None, tool_calls=None)
在助手用例中,通常希望将此响应显示给用户并让他们对其进行响应,在这种情况下,你将再次调用 API(将助手和用户的最新响应附加到消息中)。
假设我们的用户回复了他们的订单ID,我们向API发送了以下请求:
1tools = [
2 {
3 "type": "function",
4 "function": {
5 "name": "get_delivery_date",
6 "description": "Get the delivery date for a customer's order. Call this whenever you need to know the delivery date, for example when a customer asks 'Where is my package'",
7 "parameters": {
8 "type": "object",
9 "properties": {
10 "order_id": {
11 "type": "string",
12 "description": "The customer's order ID."
13 }
14 },
15 "required": ["order_id"],
16 "additionalProperties": False
17 }
18 }
19 }
20]
21
22messages = []
23messages.append({"role": "system", "content": "You are a helpful customer support assistant. Use the supplied tools to assist the user."})
24messages.append({"role": "user", "content": "Hi, can you tell me the delivery date for my order?"})
25// highlight-start
26messages.append({"role": "assistant", "content": "Hi there! I can help with that. Can you please provide your order ID?"})
27messages.append({"role": "user", "content": "i think it is order_12345"})
28// highlight-end
29
30response = client.chat.completions.create(
31 model='gpt-4o',
32 messages=messages,
33 tools=tools
34)
3.4.2 如果模型生成了函数调用 #
如果模型生成了函数调用,它将根据你提供的 parameters
定义生成调用参数。
下面是一个显示此情况的示例响应:
1Choice(
2 finish_reason='tool_calls',
3 index=0,
4 logprobs=None,
5 message=chat.completionsMessage(
6 content=None,
7 role='assistant',
8 function_call=None,
9 tool_calls=[
10 chat.completionsMessageToolCall(
11 id='call_62136354',
12 function=Function(
13 arguments='{"order_id":"order_12345"}',
14 name='get_delivery_date'),
15 type='function')
16 ])
17)
3.4.3 处理模型响应,调用函数 #
假设模型响应应调用函数,你的代码现在将处理此情况:
1# Extract the arguments for get_delivery_date
2# Note this code assumes we have already determined that the model generated a function call. See below for a more production ready example that shows how to check if the model generated a function call
3tool_call = response.choices[0].message.tool_calls[0]
4arguments = json.loads(tool_call['function']['arguments'])
5
6order_id = arguments.get('order_id')
7
8# Call the get_delivery_date function with the extracted order_id
9delivery_date = get_delivery_date(order_id)
3.5 步骤 5:将函数调用结果返回给模型 #
现在我们已经本地执行了函数调用,需要将函数调用的结果返回给 Chat Completions API,以便模型生成用户应该看到的实际响应:
1# Simulate the order_id and delivery_date
2order_id = "order_12345"
3delivery_date = datetime.now()
4
5# Simulate the tool call response
6response = {
7 "choices": [
8 {
9 "message": {
10 "tool_calls": [
11 {"id": "tool_call_1"}
12 ]
13 }
14 }
15 ]
16}
17
18# Create a message containing the result of the function call
19function_call_result_message = {
20 "role": "tool",
21 "content": json.dumps({
22 "order_id": order_id,
23 "delivery_date": delivery_date.strftime('%Y-%m-%d %H:%M:%S')
24 }),
25 "tool_call_id": response['choices'][0]['message']['tool_calls'][0]['id']
26}
27
28# Prepare the chat completion call payload
29completion_payload = {
30 "model": "gpt-4o",
31 "messages": [
32 {"role": "system", "content": "You are a helpful customer support assistant. Use the supplied tools to assist the user."},
33 {"role": "user", "content": "Hi, can you tell me the delivery date for my order?"},
34 {"role": "assistant", "content": "Hi there! I can help with that. Can you please provide your order ID?"},
35 {"role": "user", "content": "i think it is order_12345"},
36 response['choices'][0]['message'],
37 function_call_result_message
38 ]
39}
40
41# Call the OpenAI API's chat completions endpoint to send the tool call result back to the model
42response = openai.chat.completions.create(
43 model=completion_payload["model"],
44 messages=completion_payload["messages"]
45)
46
47# Print the response from the API. In this case it will typically contain a message such as "The delivery date for your order #12345 is xyz. Is there anything else I can help you with?"
48print(response)
3.6 处理边缘情况 #
建议使用OpenAI SDK来处理下面描述的边缘情况。如果由于任何原因无法使用SDK,你应该在代码中处理这些情况。
当你从API接收响应时,如果你不使用SDK,则需要处理一些生产代码中的边缘情况。
一般来说,API 会返回有效的函数调用,但有些情况下不会发生这种情况,例如,当你指定了 max_tokens
并且模型的响应因此被截断时。
这个示例解释了它们:
1# Check if the conversation was too long for the context window
2if response['choices'][0]['message']['finish_reason'] == "length":
3 print("Error: The conversation was too long for the context window.")
4 # Handle the error as needed, e.g., by truncating the conversation or asking for clarification
5 handle_length_error(response)
6
7# Check if the model's output included copyright material (or similar)
8if response['choices'][0]['message']['finish_reason'] == "content_filter":
9 print("Error: The content was filtered due to policy violations.")
10 # Handle the error as needed, e.g., by modifying the request or notifying the user
11 handle_content_filter_error(response)
12
13# Check if the model has made a tool_call. This is the case either if the "finish_reason" is "tool_calls" or if the "finish_reason" is "stop" and our API request had forced a function call
14if (response['choices'][0]['message']['finish_reason'] == "tool_calls" or
15 # This handles the edge case where if we forced the model to call one of our functions, the finish_reason will actually be "stop" instead of "tool_calls"
16 (our_api_request_forced_a_tool_call and response['choices'][0]['message']['finish_reason'] == "stop")):
17 # Handle tool call
18 print("Model made a tool call.")
19 # Your code to handle tool calls
20 handle_tool_call(response)
21
22# Else finish_reason is "stop", in which case the model was just responding directly to the user
23elif response['choices'][0]['message']['finish_reason'] == "stop":
24 # Handle the normal stop case
25 print("Model responded directly to the user.")
26 # Your code to handle normal responses
27 handle_normal_response(response)
28
29# Catch any other case, this is unexpected
30else:
31 print("Unexpected finish_reason:", response['choices'][0]['message']['finish_reason'])
32 # Handle unexpected cases as needed
33 handle_unexpected_case(response)
4. 使用结构化输出的Function calling #
默认情况下,当你使用函数调用时,API将为你提供参数的最佳匹配,这意味着模型偶尔可能会在使用复杂schema时丢失参数或类型错误。
结构化输出是一种确保模型用于函数调用的输出与你提供的schema完全匹配的功能。
可以使用单个参数启用Function calling的结构化输出,只需提供strict: true
即可。
1from enum import Enum
2from typing import Union
3from pydantic import BaseModel
4import openai
5from openai import OpenAI
6
7client = OpenAI()
8
9class GetDeliveryDate(BaseModel):
10 order_id: str
11
12tools = [openai.pydantic_function_tool(GetDeliveryDate)]
13
14messages = []
15messages.append({"role": "system", "content": "You are a helpful customer support assistant. Use the supplied tools to assist the user."})
16messages.append({"role": "user", "content": "Hi, can you tell me the delivery date for my order #12345?"})
17
18response = client.chat.completions.create(
19 model='gpt-4o-2024-08-06',
20 messages=messages,
21 tools=tools
22)
23
24print(response.choices[0].message.tool_calls[0].function)
当通过提供 strict: true
来启用结构化输出时,OpenAI API将在的第一个请求中预处理你提供的schema,然后使用此工件将模型限制在你的schema内。
因此,模型将始终遵循你的精确schema,除了以下几种情况:
- 模型的响应被截断(由于
max_tokens
、stop tokens
或最大上下文长度) - 发生模型拒绝(model refusal )
- 存在
content_filter
完成原因
注意,首次使用结构化输出发送具有新模式的请求时,由于schema正在处理,因此会有额外的延迟,但后续请求应该不会产生开销。
5. 支持的Schema #
使用结构化输出的Function calling 支持JSON Schema的一个子集。
有关支持Schema的更多信息,请参阅结构化输出指南。
6. 自定义function calling的行为 #
函数调用支持多种高级功能,例如强制函数调用、并行函数调用等。
6.1 配置并行函数调用 #
OpenAI在2023年11月6日或之后发布的任何模型默认情况下可能会在单个响应中生成多个函数调用,表示它们应该并行调用。
如果执行给定函数需要很长时间,这尤其有用。例如,模型可以同时调用函数来获取3个不同位置的天气,这将导致一条消息中包含3个函数调用。 示例响应:
1response = Choice(
2 finish_reason='tool_calls',
3 index=0,
4 logprobs=None,
5 message=chat.completionsMessage(
6 content=None,
7 role='assistant',
8 function_call=None,
9 tool_calls=[
10 chat.completionsMessageToolCall(
11 id='call_62136355',
12 function=Function(
13 arguments='{"city":"New York"}',
14 name='check_weather'),
15 type='function'),
16 chat.completionsMessageToolCall(
17 id='call_62136356',
18 function=Function(
19 arguments='{"city":"London"}',
20 name='check_weather'),
21 type='function'),
22 chat.completionsMessageToolCall(
23 id='call_62136357',
24 function=Function(
25 arguments='{"city":"Tokyo"}',
26 name='check_weather'),
27 type='function')
28 ])
29)
30
31# Iterate through tool calls to handle each weather check
32for tool_call in response.message.tool_calls:
33 arguments = json.loads(tool_call.function.arguments)
34 city = arguments['city']
35 weather_info = check_weather(city)
36 print(f"Weather in {city}: {weather_info}")
每个函数调用在数组中都有一个唯一的ID。
一旦你在应用程序中执行了这些函数调用,你可以通过为每个函数调用向对话添加一条新消息来将结果提供给模型,每个消息包含一个函数调用的结果,并使用 tool_call_id
引用 tool_calls
中的 ID,例如:
1# Assume we have fetched the weather data from somewhere
2weather_data = {
3 "New York": {"temperature": "22°C", "condition": "Sunny"},
4 "London": {"temperature": "15°C", "condition": "Cloudy"},
5 "Tokyo": {"temperature": "25°C", "condition": "Rainy"}
6}
7
8# Prepare the chat completion call payload with inline function call result creation
9completion_payload = {
10 "model": "gpt-4o",
11 "messages": [
12 {"role": "system", "content": "You are a helpful assistant providing weather updates."},
13 {"role": "user", "content": "Can you tell me the weather in New York, London, and Tokyo?"},
14 # Append the original function calls to the conversation
15 response['message'],
16 # Include the result of the function calls
17 {
18 "role": "tool",
19 "content": json.dumps({
20 "city": "New York",
21 "weather": weather_data["New York"]
22 }),
23 # Here we specify the tool_call_id that this result corresponds to
24 "tool_call_id": response['message']['tool_calls'][0]['id']
25 },
26 {
27 "role": "tool",
28 "content": json.dumps({
29 "city": "London",
30 "weather": weather_data["London"]
31 }),
32 "tool_call_id": response['message']['tool_calls'][1]['id']
33 },
34 {
35 "role": "tool",
36 "content": json.dumps({
37 "city": "Tokyo",
38 "weather": weather_data["Tokyo"]
39 }),
40 "tool_call_id": response['message']['tool_calls'][2]['id']
41 }
42 ]
43}
44
45# Call the OpenAI API's chat completions endpoint to send the tool call result back to the model
46response = openai.chat.completions.create(
47 model=completion_payload["model"],
48 messages=completion_payload["messages"]
49)
50
51# Print the response from the API, which will return something like "In New York the weather is..."
52print(response)
你可以通过设置
parallel_tool_calls: false
来禁用并行函数调用。
6.1.1 并行函数调用和结构化输出 #
当模型通过并行函数调用输出多个函数调用时,模型输出可能与工具中提供的严格模式不匹配。
为了确保严格遵守模式,请通过提供 parallel_tool_calls: false
来禁用并行函数调用。使用此设置,模型将一次生成一个函数调用。
6.2 配置函数调用行为使用 tool_choice
参数
#
默认情况下,模型配置为自动选择要调用的函数,由 tool_choice: "auto"
设置决定。
提供了三种方式来自定义默认行为:
- 要强制模型始终调用一个或多个函数,你可以设置
tool_choice: "required"
。然后模型将始终选择一个或多个函数来调用。这在例如你想让模型在多个动作中选择下一个要执行的动作时很有用。 - 要强制模型调用特定函数,你可以设置
tool_choice: {"type": "function", "function": {"name": "my_function"}}
。 - 要禁用函数调用并强制模型仅生成面向用户的消息,你可以不提供任何工具,或者设置
tool_choice: "none"
。
请注意,如果你执行1或2(即强制模型调用函数),则后续的 finish_reason
将是 stop
而不是 tool_calls
。
1from openai import OpenAI
2
3client = OpenAI()
4
5tools = [
6 {
7 "type": "function",
8 "function": {
9 "name": "get_weather",
10 "strict": True,
11 "parameters": {
12 "type": "object",
13 "properties": {
14 "location": {"type": "string"},
15 "unit": {"type": "string", "enum": ["c", "f"]},
16 },
17 "required": ["location", "unit"],
18 "additionalProperties": False,
19 },
20 },
21 },
22 {
23 "type": "function",
24 "function": {
25 "name": "get_stock_price",
26 "strict": True,
27 "parameters": {
28 "type": "object",
29 "properties": {
30 "symbol": {"type": "string"},
31 },
32 "required": ["symbol"],
33 "additionalProperties": False,
34 },
35 },
36 },
37]
38
39messages = [{"role": "user", "content": "What's the weather like in Boston today?"}]
40completion = client.chat.completions.create(
41 model="gpt-4o",
42 messages=messages,
43 tools=tools,
44 tool_choice="required"
45)
46
47print(completion)
7. 理解token使用 #
在后台,函数被注入(inject)到模型训练过的语法中的系统消息中。这意味着函数计入模型的上下文限制,并作为输入token计费。如果遇到token限制,建议限制函数数量或提供函数参数的描述长度。 如果你的工具规范中定义了许多函数,也可以使用微调来减少使用的令牌数量。
8. 提示和最佳实践 #
8.1 通过设置 strict: "true"
打开结构化输出
#
当启用结构化输出时,模型为函数调用生成的参数将可靠地匹配你提供的JSON Schema。 如果你不使用结构化输出,则无法保证参数的结构正确,因此我们建议使用Pydantic等验证库来首先验证参数,然后再使用它们。
8.2 直观地命名函数,并提供详细的描述 #
如果你发现模型没有生成对正确函数的调用,你可能需要更新函数名称和描述,以便模型更清楚地了解何时应该选择每个函数。避免使用缩写或首字母缩略词来缩短函数和参数名称。 你还可以为何时应该调用工具提供详细的描述。对于复杂函数,你应该为每个参数提供描述,以帮助模型了解需要向用户询问哪些信息来收集该参数。
8.3 直观地命名函数参数,并提供详细的描述 #
为函数参数使用清晰和描述性的名称。例如,在描述中指定日期参数的预期格式(例如,YYYY-mm-dd
或 dd/mm/yy
)。
8.4 考虑在系统消息中提供有关如何以及何时调用函数的额外信息 #
在系统消息中提供清晰的指令可以显着提高模型的函数调用准确性。例如,引导模型使用check_order_status
来检查用户的订单状态,例如“我的订单在哪里?”或“我的订单是否已经发货?”。为复杂场景提供上下文,例如“在使用schedule_meeting
安排会议之前,使用 check_availability
检查用户的日历可用性以避免冲突”。
8.5 尽可能使用枚举作为函数参数 #
如果你的用例允许,你可以使用枚举来限制参数的可能值。这可以帮助减少幻觉。 例如,假设你有一个帮助订购T恤的AI助手。你可能有固定的一组T恤尺寸,并且可能希望模型以特定格式输出。如果希望模型输出“s”、“m”、“l”等表示小、中、大,则可以在枚举中提供这些值,例如:
1{
2 "name": "pick_tshirt_size",
3 "description": "Call this if the user specifies which size t-shirt they want",
4 "parameters": {
5 "type": "object",
6 "properties": {
7 "size": {
8 "type": "string",
9 "enum": ["s", "m", "l"],
10 "description": "The size of the t-shirt that the user would like to order"
11 }
12 },
13 "required": ["size"],
14 "additionalProperties": false
15 }
16}
如果你不限制输出,用户可能会说“大”或“L”,模型可能会返回任一值。你的代码可能需要特定的结构,因此限制模型可以选择的格式数量很重要。
8.6 保持较少的函数数量以提高准确性 #
我们建议你在单个工具调用中使用不超过20个函数。开发人员通常会发现,当他们有10-20个工具时,模型选择正确工具的能力会降低。
如果你的用例需要模型能够在大量函数中进行选择,你可能需要探索微调或分解工具并进行逻辑分组以创建多代理(agent)系统。
8.7 设置评估以帮助改进函数定义和系统消息的提示工程 #
我们建议对于非平凡的函数调用使用情况,设置一套评估来衡量正确函数被调用的频率或为各种可能的用户消息生成正确参数的频率。了解有关在OpenAI Cookbook上设置评估的更多信息。
然后,你可以使用这些评估来衡量调整函数定义和系统消息是否会改善或损害你的集成。
8.8 微调可能有助于提高function calling的准确性 #
微调模型可以提高函数调用的性能,尤其是在你有大量函数或复杂、细微或相似的函数时。
请参阅函数调用微调指南了解更多信息。
9.FAQ #
9.1 函数和工具有什么区别? #
当使用OpenAI API进行函数调用时,你将它们作为工具提供,使用 tool_choice
配置它们并监控 finish_reason: "tool_calls"
。
名称为 functions
和 function_call
等参数现在已弃用。
9.2 我应该将函数调用指令包含在工具规范还是系统提示中? #
我们建议在系统提示中包含有关何时调用函数的指令,同时使用函数定义来提供有关如何调用函数以及如何生成参数的指令。
9.3 哪些模型支持函数调用? #
函数调用于2023年6月13日发布的gpt-4-turbo一起推出。这包括:gpt-4o、gpt-4o-2024-08-06、gpt-4o-2024-05-13、gpt-4o-mini、gpt-4o-mini-2024-07-18、gpt-4-turbo、gpt-4-turbo-2024-04-09、gpt-4-turbo-preview、gpt-4-0125-preview、gpt-4-1106-preview、gpt-4、gpt-4-0613、gpt-3.5-turbo、gpt-3.5-turbo-0125、gpt-3.5-turbo-1106 和 gpt-3.5-turbo-0613。
在此日期之前发布的旧模型不支持函数调用。
并行函数调用支持在2023年11月6日或之后发布的模型上使用。这包括:gpt-4o、gpt-4o-2024-08-06、gpt-4o-2024-05-13、gpt-4o-mini、gpt-4o-mini-2024-07-18、gpt-4-turbo、gpt-4-turbo-2024-04-09、gpt-4-turbo-preview、gpt-4-0125-preview、gpt-4-1106-preview、gpt-3.5-turbo、gpt-3.5-turbo-0125 和 gpt-3.5-turbo-1106。
9.4 给出一些场景和示例函数? #
数据检索:
- 场景:当用户询问“谁是我的顶级客户?”时,聊天机器人需要从内部系统获取最新的客户数据。
- 实现:定义一个函数
get_customers(min_revenue: int, created_before: string, limit: int)
从你的内部 API 检索客户数据。模型可以根据用户输入建议调用此函数并提供适当的参数。
任务自动化:
- 场景:助手机器人根据用户偏好和日历可用性安排会议。
- 实现:定义一个函数
scheduleMeeting(date: str, time: str, participants: list)
与日历 API 交互。模型可以建议调用此函数的最佳时间和日期。
计算任务:
- 场景:金融应用程序根据用户输入计算贷款付款。
- 实现:定义一个函数
calculateLoanPayment(principal: float, interestRate: float, term: int)
来执行必要的计算。模型可以为该函数提供输入值。
客户支持:
- 场景:客户支持机器人通过提供订单状态来协助用户。
- 实现:定义一个函数
getOrderStatus(orderId: str)
从数据库检索订单状态信息。模型可以根据用户输入建议调用此函数并提供适当的订单ID参数。
9.5 模型可以自己执行函数吗? #
不可以,模型只建议函数调用并生成参数。你的应用程序根据这些建议处理函数的执行(并将调用这些函数的结果返回给模型)。
9.6 什么是结构化输出? #
结构化输出是2024年8月推出的一项功能,确保模型为函数调用生成的参数完全匹配提供的JSON Schema,提高可靠性并减少错误。我们建议使用它,可以通过设置 strict: "true"
来启用。
9.7 为什么我可能不想打开结构化输出? #
不使用结构化输出的主要原因是:
- 如果你需要使用尚未支持的JSON Schema功能,例如递归模式。
- 如果你的每个API请求都包含一个新Schema(即你的Schema不是固定的,而是按需生成并且很少重复),因为第一次使用新JSON Schema发送请求会有增加的延迟,因为模式是预处理的并缓存起来以限制模型的输出。
9.8 如何确保模型调用正确的函数? #
使用直观的名称和详细的描述来命名函数和参数。在系统消息中提供清晰的指导,以提高模型选择正确函数的能力。
9.9 结构化输出对零数据保留意味着什么? #
当启用结构化输出时,提供的模式不符合零数据保留条件。
OpenAI 的 Zero Data Retention是一种数据处理模式,在这种模式下,OpenAI不会存储任何与用户交互相关的数据。这意味着当用户使用API时,OpenAI不会保留输入或输出的数据。这种模式适用于那些对数据隐私和保密性有高度要求的用户,例如处理敏感信息的企业或组织。
资源 #
OpenAI Cookbook有几个端到端的示例来帮助你实现function calling。在OpenAI Cookbook中“如何使用聊天模型调用函数”中,概述了模型如何使用function calling的两个示例。
可以在OpenAI Cookbook中找到更多示例来帮助您开始使用function calling。
参考 #
- https://cookbook.openai.com/examples/how_to_call_functions_with_chat_models
- https://cookbook.openai.com/examples/function_calling_with_an_openapi_spec
- https://platform.openai.com/docs/guides/function-calling
- https://platform.openai.com/docs/guides/structured-outputs
- https://openai.com/index/introducing-structured-outputs-in-the-api/
- https://platform.openai.com/docs/guides/structured-outputs/function-calling-vs-response-format