OpenAI Function Calling 函数调用能力与外部交互

函数调用为 OpenAI 模型提供了一种强大而灵活的方式与您的代码或外部服务进行交互。本指南将解释如何将模型连接到您自己的自定义代码以获取数据或采取行动。
获取天气发送邮件搜索知识库
使用 get_weather 函数的函数调用示例
Python

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-python"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span><span style="color:var(--text-disabled)">7
</span><span style="color:var(--text-disabled)">8
</span><span style="color:var(--text-disabled)">9
</span><span style="color:var(--text-disabled)">10
</span><span style="color:var(--text-disabled)">11
</span><span style="color:var(--text-disabled)">12
</span><span style="color:var(--text-disabled)">13
</span><span style="color:var(--text-disabled)">14
</span><span style="color:var(--text-disabled)">15
</span><span style="color:var(--text-disabled)">16
</span><span style="color:var(--text-disabled)">17
</span><span style="color:var(--text-disabled)">18
</span><span style="color:var(--text-disabled)">19
</span><span style="color:var(--text-disabled)">20
</span><span style="color:var(--text-disabled)">21
</span><span style="color:var(--text-disabled)">22
</span><span style="color:var(--text-disabled)">23
</span><span style="color:var(--text-disabled)">24
</span><span style="color:var(--text-disabled)">25
</span><span style="color:var(--text-disabled)">26
</span><span style="color:var(--text-disabled)">27
</span><span style="color:var(--text-disabled)">28
</span><span style="color:var(--text-disabled)">29
</span><span style="color:var(--text-disabled)">30
</span></code><span style="color:var(--syntax2)">from</span> openai <span style="color:var(--syntax2)">import</span> OpenAI

client = OpenAI()

tools = [{
    <span style="color:var(--syntax3)">"type"</span>: <span style="color:var(--syntax3)">"function"</span>,
    <span style="color:var(--syntax3)">"name"</span>: <span style="color:var(--syntax3)">"get_weather"</span>,
    <span style="color:var(--syntax3)">"description"</span>: <span style="color:var(--syntax3)">"Get current temperature for a given location."</span>,
    <span style="color:var(--syntax3)">"parameters"</span>: {
        <span style="color:var(--syntax3)">"type"</span>: <span style="color:var(--syntax3)">"object"</span>,
        <span style="color:var(--syntax3)">"properties"</span>: {
            <span style="color:var(--syntax3)">"location"</span>: {
                <span style="color:var(--syntax3)">"type"</span>: <span style="color:var(--syntax3)">"string"</span>,
                <span style="color:var(--syntax3)">"description"</span>: <span style="color:var(--syntax3)">"City and country e.g. Bogotá, Colombia"</span>
            }
        },
        <span style="color:var(--syntax3)">"required"</span>: [
            <span style="color:var(--syntax3)">"location"</span>
        ],
        <span style="color:var(--syntax3)">"additionalProperties"</span>: <span style="color:var(--syntax2)">False</span>
    }
}]

response = client.responses.create(
    model=<span style="color:var(--syntax3)">"gpt-4o"</span>,
    <span style="color:var(--syntax1)">input</span>=[{<span style="color:var(--syntax3)">"role"</span>: <span style="color:var(--syntax3)">"user"</span>, <span style="color:var(--syntax3)">"content"</span>: <span style="color:var(--syntax3)">"What is the weather like in Paris today?"</span>}],
    tools=tools
)

<span style="color:var(--syntax1)">print</span>(response.output)</code></span>

输出

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-json"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span><span style="color:var(--text-disabled)">7
</span></code>[{
    <span style="color:var(--syntax4)">"type"</span>: <span style="color:var(--syntax3)">"function_call"</span>,
    <span style="color:var(--syntax4)">"id"</span>: <span style="color:var(--syntax3)">"fc_12345xyz"</span>,
    <span style="color:var(--syntax4)">"call_id"</span>: <span style="color:var(--syntax3)">"call_12345xyz"</span>,
    <span style="color:var(--syntax4)">"name"</span>: <span style="color:var(--syntax3)">"get_weather"</span>,
    <span style="color:var(--syntax4)">"arguments"</span>: <span style="color:var(--syntax3)">"{\"location\":\"Paris, France\"}"</span>
}]</code></span>

Playground中试验函数调用并生成函数模式

概述

您可以通过函数调用 让模型访问您自己的自定义代码。根据系统提示和消息,模型可能会决定调用这些函数 ---而不是(或除了)生成文本或音频

然后,您将执行函数代码,发回结果,模型会将它们合并到最终响应中。

函数调用有两个主要用例:

获取数据 检索最新信息以纳入模型响应 (RAG)。可用于搜索知识库和从 API 检索特定数据(例如当前天气数据)。
采取行动 执行诸如提交表单、调用 API、修改应用程序状态(UI/前端或后端)或采取代理工作流操作(如交接对话)等操作。

示例函数

让我们看看让模型使用get_weather下面定义的真实函数的步骤:
在您的代码库中实现的示例 get_weather 函数
Python

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-python"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span></code><span style="color:var(--syntax2)">import</span> requests

<span style="color:var(--syntax2)">def</span> <span style="color:var(--syntax5)">get_weather</span>(latitude, longitude):
    response = requests.get(<span style="color:var(--syntax3)">f"https://api.open-meteo.com/v1/forecast?latitude=</span><span style="color:var(--syntax3)">{latitude}</span><span style="color:var(--syntax3)">&longitude=</span><span style="color:var(--syntax3)">{longitude}</span><span style="color:var(--syntax3)">&current=temperature_2m,wind_speed_10m&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m"</span>)
    data = response.json()
    <span style="color:var(--syntax2)">return</span> data[<span style="color:var(--syntax3)">'current'</span>][<span style="color:var(--syntax3)">'temperature_2m'</span>]</code></span>

与之前的图表不同,此函数需要精确的参数latitude,而longitude不是一般的location参数。(但是,我们的模型可以自动确定许多位置的坐标!)

函数调用步骤

步骤 1:使用定义的 get_weather 工具调用模型
Python

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-python"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span><span style="color:var(--text-disabled)">7
</span><span style="color:var(--text-disabled)">8
</span><span style="color:var(--text-disabled)">9
</span><span style="color:var(--text-disabled)">10
</span><span style="color:var(--text-disabled)">11
</span><span style="color:var(--text-disabled)">12
</span><span style="color:var(--text-disabled)">13
</span><span style="color:var(--text-disabled)">14
</span><span style="color:var(--text-disabled)">15
</span><span style="color:var(--text-disabled)">16
</span><span style="color:var(--text-disabled)">17
</span><span style="color:var(--text-disabled)">18
</span><span style="color:var(--text-disabled)">19
</span><span style="color:var(--text-disabled)">20
</span><span style="color:var(--text-disabled)">21
</span><span style="color:var(--text-disabled)">22
</span><span style="color:var(--text-disabled)">23
</span><span style="color:var(--text-disabled)">24
</span><span style="color:var(--text-disabled)">25
</span><span style="color:var(--text-disabled)">26
</span><span style="color:var(--text-disabled)">27
</span><span style="color:var(--text-disabled)">28
</span></code><span style="color:var(--syntax2)">from</span> openai <span style="color:var(--syntax2)">import</span> OpenAI
<span style="color:var(--syntax2)">import</span> json

client = OpenAI()

tools = [{
    <span style="color:var(--syntax3)">"type"</span>: <span style="color:var(--syntax3)">"function"</span>,
    <span style="color:var(--syntax3)">"name"</span>: <span style="color:var(--syntax3)">"get_weather"</span>,
    <span style="color:var(--syntax3)">"description"</span>: <span style="color:var(--syntax3)">"Get current temperature for provided coordinates in celsius."</span>,
    <span style="color:var(--syntax3)">"parameters"</span>: {
        <span style="color:var(--syntax3)">"type"</span>: <span style="color:var(--syntax3)">"object"</span>,
        <span style="color:var(--syntax3)">"properties"</span>: {
            <span style="color:var(--syntax3)">"latitude"</span>: {<span style="color:var(--syntax3)">"type"</span>: <span style="color:var(--syntax3)">"number"</span>},
            <span style="color:var(--syntax3)">"longitude"</span>: {<span style="color:var(--syntax3)">"type"</span>: <span style="color:var(--syntax3)">"number"</span>}
        },
        <span style="color:var(--syntax3)">"required"</span>: [<span style="color:var(--syntax3)">"latitude"</span>, <span style="color:var(--syntax3)">"longitude"</span>],
        <span style="color:var(--syntax3)">"additionalProperties"</span>: <span style="color:var(--syntax2)">False</span>
    },
    <span style="color:var(--syntax3)">"strict"</span>: <span style="color:var(--syntax2)">True</span>
}]

input_messages = [{<span style="color:var(--syntax3)">"role"</span>: <span style="color:var(--syntax3)">"user"</span>, <span style="color:var(--syntax3)">"content"</span>: <span style="color:var(--syntax3)">"What's the weather like in Paris today?"</span>}]

response = client.responses.create(
    model=<span style="color:var(--syntax3)">"gpt-4o"</span>,
    <span style="color:var(--syntax1)">input</span>=input_messages,
    tools=tools,
)</code></span>
  • 模型决定调用函数 ------模型返回名称输入参数

响应.输出

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-json"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span><span style="color:var(--text-disabled)">7
</span></code>[{
    <span style="color:var(--syntax4)">"type"</span>: <span style="color:var(--syntax3)">"function_call"</span>,
    <span style="color:var(--syntax4)">"id"</span>: <span style="color:var(--syntax3)">"fc_12345xyz"</span>,
    <span style="color:var(--syntax4)">"call_id"</span>: <span style="color:var(--syntax3)">"call_12345xyz"</span>,
    <span style="color:var(--syntax4)">"name"</span>: <span style="color:var(--syntax3)">"get_weather"</span>,
    <span style="color:var(--syntax4)">"arguments"</span>: <span style="color:var(--syntax3)">"{\"latitude\":48.8566,\"longitude\":2.3522}"</span>
}]</code></span>

步骤3:执行get_weather函数
Python

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-python"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span></code>tool_call = response.output[<span style="color:var(--syntax4)">0</span>]
args = json.loads(tool_call.arguments)

result = get_weather(args[<span style="color:var(--syntax3)">"latitude"</span>], args[<span style="color:var(--syntax3)">"longitude"</span>])</code></span>
  • 提供结果模型------以便可以将其纳入最终响应中。

步骤 4:提供结果并再次调用模型
Python

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-python"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span><span style="color:var(--text-disabled)">7
</span><span style="color:var(--text-disabled)">8
</span><span style="color:var(--text-disabled)">9
</span><span style="color:var(--text-disabled)">10
</span><span style="color:var(--text-disabled)">11
</span><span style="color:var(--text-disabled)">12
</span><span style="color:var(--text-disabled)">13
</span></code>input_messages.append(tool_call)  <span style="color:rgba(var(--sh-fg),.5)"># append model's function call message</span>
input_messages.append({                               <span style="color:rgba(var(--sh-fg),.5)"># append result message</span>
    <span style="color:var(--syntax3)">"type"</span>: <span style="color:var(--syntax3)">"function_call_output"</span>,
    <span style="color:var(--syntax3)">"call_id"</span>: tool_call.call_id,
    <span style="color:var(--syntax3)">"output"</span>: <span style="color:var(--syntax1)">str</span>(result)
})

response_2 = client.responses.create(
    model=<span style="color:var(--syntax3)">"gpt-4o"</span>,
    <span style="color:var(--syntax1)">input</span>=input_messages,
    tools=tools,
)
<span style="color:var(--syntax1)">print</span>(response_2.output_text)</code></span>
  • 模型响应------将结果纳入其输出中。

响应2.输出文本

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-json"><span style="color:var(--syntax3)">"The current temperature in Paris is 14°C (57.2°F)."</span></code></span>

定义函数

tools可以在每个API请求的参数中设置功能。

函数由其架构定义,架构告知模型其功能以及其所需的输入参数。它包含以下字段:

场地 描述
type 这应该始终function
name 函数的名称(例如get_weather
description 有关何时以及如何使用该功能的详细信息
parameters 定义函数输入参数的JSON 模式
strict 是否对函数调用强制执行严格模式

请查看此示例或在下面(或在我们的游乐场)生成您自己的示例。
产生
示例函数架构

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-json"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span><span style="color:var(--text-disabled)">7
</span><span style="color:var(--text-disabled)">8
</span><span style="color:var(--text-disabled)">9
</span><span style="color:var(--text-disabled)">10
</span><span style="color:var(--text-disabled)">11
</span><span style="color:var(--text-disabled)">12
</span><span style="color:var(--text-disabled)">13
</span><span style="color:var(--text-disabled)">14
</span><span style="color:var(--text-disabled)">15
</span><span style="color:var(--text-disabled)">16
</span><span style="color:var(--text-disabled)">17
</span><span style="color:var(--text-disabled)">18
</span><span style="color:var(--text-disabled)">19
</span><span style="color:var(--text-disabled)">20
</span><span style="color:var(--text-disabled)">21
</span><span style="color:var(--text-disabled)">22
</span><span style="color:var(--text-disabled)">23
</span><span style="color:var(--text-disabled)">24
</span><span style="color:var(--text-disabled)">25
</span><span style="color:var(--text-disabled)">26
</span><span style="color:var(--text-disabled)">27
</span><span style="color:var(--text-disabled)">28
</span><span style="color:var(--text-disabled)">29
</span><span style="color:var(--text-disabled)">30
</span></code>{
    <span style="color:var(--syntax4)">"type"</span>: <span style="color:var(--syntax3)">"function"</span>,
    <span style="color:var(--syntax4)">"function"</span>: {
        <span style="color:var(--syntax4)">"name"</span>: <span style="color:var(--syntax3)">"get_weather"</span>,
        <span style="color:var(--syntax4)">"description"</span>: <span style="color:var(--syntax3)">"Retrieves current weather for the given location."</span>,
        <span style="color:var(--syntax4)">"parameters"</span>: {
            <span style="color:var(--syntax4)">"type"</span>: <span style="color:var(--syntax3)">"object"</span>,
            <span style="color:var(--syntax4)">"properties"</span>: {
                <span style="color:var(--syntax4)">"location"</span>: {
                    <span style="color:var(--syntax4)">"type"</span>: <span style="color:var(--syntax3)">"string"</span>,
                    <span style="color:var(--syntax4)">"description"</span>: <span style="color:var(--syntax3)">"City and country e.g. Bogotá, Colombia"</span>
                },
                <span style="color:var(--syntax4)">"units"</span>: {
                    <span style="color:var(--syntax4)">"type"</span>: <span style="color:var(--syntax3)">"string"</span>,
                    <span style="color:var(--syntax4)">"enum"</span>: [
                        <span style="color:var(--syntax3)">"celsius"</span>,
                        <span style="color:var(--syntax3)">"fahrenheit"</span>
                    ],
                    <span style="color:var(--syntax4)">"description"</span>: <span style="color:var(--syntax3)">"Units the temperature will be returned in."</span>
                }
            },
            <span style="color:var(--syntax4)">"required"</span>: [
                <span style="color:var(--syntax3)">"location"</span>,
                <span style="color:var(--syntax3)">"units"</span>
            ],
            <span style="color:var(--syntax4)">"additionalProperties"</span>: <span style="color:var(--syntax2)">false</span>
        },
        <span style="color:var(--syntax4)">"strict"</span>: <span style="color:var(--syntax2)">true</span>
    }
}</code></span>

因为它们parameters是由JSON 模式定义的,所以您可以利用它的许多丰富的功能,如属性类型、枚举、描述、嵌套对象和递归对象。

定义函数的最佳实践

  1. 写出清晰详细的函数名称、参数描述和说明。

    • 明确描述函数和每个参数的目的(及其格式)以及输出代表什么。
    • 使用系统提示来描述何时(以及何时不使用)使用每个功能。 通常,告诉模型确切要做什么。
    • 包括示例和边缘情况 ,特别是为了纠正任何重复出现的故障。(注意: 添加示例可能会损害推理模型的性能。)
  2. 应用软件工程最佳实践。

    • 使功能明显且直观 。(最小惊喜原则
    • 使用枚举 和对象结构使无效状态无法表示。(例如toggle_light(on: bool, off: bool)允许无效调用)
    • **通过实习生测试。**实习生/人类是否可以在只给出你给模型的内容的情况下正确使用该功能?(如果不能,他们会问你什么问题?将答案添加到提示中。)
  3. 减轻模型的负担并尽可能使用代码。

    • 不要让模型填充您已知的参数。 例如,如果您已经有order_id基于上一个菜单的模型,则不要使用order_id参数 - 相反,不要使用参数submit_refund()并传递order_id代码。
    • 合并始终按顺序调用的函数。 例如,如果您始终mark_location()在之后调用query_location(),则只需将标记逻辑移到查询函数调用中。
  4. 保持函数数量较少以获得更高的准确性。

    • 使用不同数量的函数来评估您的表现。
    • 尽管这只是一个软建议,但目标是每次执行少于 20 个函数。
  5. 利用 OpenAI 资源。

代币使用

在底层,函数以模型训练所用的语法注入到系统消息中。这意味着函数会计入模型的上下文限制,并被视为输入标记。如果您遇到标记限制,我们建议限制函数数量或您为函数参数提供的描述的长度。

如果您的工具规范中定义了许多功能,那么也可以使用微调来减少使用的标记数量。

处理函数调用

当模型调用函数时,您必须执行该函数并返回结果。由于模型响应可能包含零个、一个或多个调用,因此最佳做法是假设存在多个调用。

响应数组包含一个值为 的output条目。每个条目都有一个(稍后用于提交函数结果)、和 JSON 编码的。type``function_call``call_id``name``arguments
具有多个函数调用的示例响应

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-json"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span><span style="color:var(--text-disabled)">7
</span><span style="color:var(--text-disabled)">8
</span><span style="color:var(--text-disabled)">9
</span><span style="color:var(--text-disabled)">10
</span><span style="color:var(--text-disabled)">11
</span><span style="color:var(--text-disabled)">12
</span><span style="color:var(--text-disabled)">13
</span><span style="color:var(--text-disabled)">14
</span><span style="color:var(--text-disabled)">15
</span><span style="color:var(--text-disabled)">16
</span><span style="color:var(--text-disabled)">17
</span><span style="color:var(--text-disabled)">18
</span><span style="color:var(--text-disabled)">19
</span><span style="color:var(--text-disabled)">20
</span><span style="color:var(--text-disabled)">21
</span><span style="color:var(--text-disabled)">22
</span><span style="color:var(--text-disabled)">23
</span></code>[
    {
        <span style="color:var(--syntax4)">"id"</span>: <span style="color:var(--syntax3)">"fc_12345xyz"</span>,
        <span style="color:var(--syntax4)">"call_id"</span>: <span style="color:var(--syntax3)">"call_12345xyz"</span>,
        <span style="color:var(--syntax4)">"type"</span>: <span style="color:var(--syntax3)">"function_call"</span>,
        <span style="color:var(--syntax4)">"name"</span>: <span style="color:var(--syntax3)">"get_weather"</span>,
        <span style="color:var(--syntax4)">"arguments"</span>: <span style="color:var(--syntax3)">"{\"location\":\"Paris, France\"}"</span>
    },
    {
        <span style="color:var(--syntax4)">"id"</span>: <span style="color:var(--syntax3)">"fc_67890abc"</span>,
        <span style="color:var(--syntax4)">"call_id"</span>: <span style="color:var(--syntax3)">"call_67890abc"</span>,
        <span style="color:var(--syntax4)">"type"</span>: <span style="color:var(--syntax3)">"function_call"</span>,
        <span style="color:var(--syntax4)">"name"</span>: <span style="color:var(--syntax3)">"get_weather"</span>,
        <span style="color:var(--syntax4)">"arguments"</span>: <span style="color:var(--syntax3)">"{\"location\":\"Bogotá, Colombia\"}"</span>
    },
    {
        <span style="color:var(--syntax4)">"id"</span>: <span style="color:var(--syntax3)">"fc_99999def"</span>,
        <span style="color:var(--syntax4)">"call_id"</span>: <span style="color:var(--syntax3)">"call_99999def"</span>,
        <span style="color:var(--syntax4)">"type"</span>: <span style="color:var(--syntax3)">"function_call"</span>,
        <span style="color:var(--syntax4)">"name"</span>: <span style="color:var(--syntax3)">"send_email"</span>,
        <span style="color:var(--syntax4)">"arguments"</span>: <span style="color:var(--syntax3)">"{\"to\":\"[email protected]\",\"body\":\"Hi bob\"}"</span>
    }
]</code></span>

执行函数调用并附加结果
Python

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-python"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span><span style="color:var(--text-disabled)">7
</span><span style="color:var(--text-disabled)">8
</span><span style="color:var(--text-disabled)">9
</span><span style="color:var(--text-disabled)">10
</span><span style="color:var(--text-disabled)">11
</span><span style="color:var(--text-disabled)">12
</span><span style="color:var(--text-disabled)">13
</span></code><span style="color:var(--syntax2)">for</span> tool_call <span style="color:var(--syntax2)">in</span> response.output:
    <span style="color:var(--syntax2)">if</span> tool_call.<span style="color:var(--syntax1)">type</span> != <span style="color:var(--syntax3)">"function_call"</span>:
        <span style="color:var(--syntax2)">continue</span>

    name = tool_call.name
    args = json.loads(tool_call.arguments)

    result = call_function(name, args)
    input_messages.append({
        <span style="color:var(--syntax3)">"type"</span>: <span style="color:var(--syntax3)">"function_call_output"</span>,
        <span style="color:var(--syntax3)">"call_id"</span>: tool_call.call_id,
        <span style="color:var(--syntax3)">"output"</span>: <span style="color:var(--syntax1)">str</span>(result)
    })</code></span>

在上面的例子中,我们假设call_function要路由每个呼叫。以下是一种可能的实现:
执行函数调用并附加结果
Python

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-python"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span></code><span style="color:var(--syntax2)">def</span> <span style="color:var(--syntax5)">call_function</span>(name, args):
    <span style="color:var(--syntax2)">if</span> name == <span style="color:var(--syntax3)">"get_weather"</span>:
        <span style="color:var(--syntax2)">return</span> get_weather(**args)
    <span style="color:var(--syntax2)">if</span> name == <span style="color:var(--syntax3)">"send_email"</span>:
        <span style="color:var(--syntax2)">return</span> send_email(**args)</code></span>

格式化结果

结果必须是字符串,但格式由您决定(JSON、错误代码、纯文本等)。模型将根据需要解释该字符串。

如果您的函数没有返回值(例如send_email),则只需返回一个字符串来指示成功或失败。(例如"success"

将结果纳入响应

将结果附加到您的之后input,您可以将它们发送回模型以获得最终响应。
将结果发送回模型
Python

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-python"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span></code>response = client.responses.create(
    model=<span style="color:var(--syntax3)">"gpt-4o"</span>,
    <span style="color:var(--syntax1)">input</span>=input_messages,
    tools=tools,
)</code></span>

最终回应

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-json"><span style="color:var(--syntax3)">"It's about 15°C in Paris, 18°C in Bogotá, and I've sent that email to Bob."</span></code></span>

其他配置

工具选择

默认情况下,模型将确定何时使用以及使用多少工具。您可以使用tool_choice参数强制执行特定行为。

  1. 自动:( 默认*)* 调用零个、一个或多个函数。tool_choice: "auto"
  2. 必需: 调用一个或多个函数。 tool_choice: "required"
  1. 强制函数: 只调用一个特定函数。 tool_choice: {"type": "function", "name": "get_weather"}

您还可以设置tool_choice"none"模仿不传递任何函数的行为。

并行函数调用

模型可能会选择在一次调用中调用多个函数。您可以通过设置parallel_tool_calls为 来防止这种情况false,这可确保恰好调用零个或一个工具。

注意: 目前,如果模型一次调用多个函数,那么这些调用的严格模式将被禁用。

严格模式

设置stricttrue将确保函数调用可靠地遵循函数架构,而不是尽力而为。我们建议始终启用严格模式。

在底层,严格模式通过利用我们的结构化输出功能来工作,因此引入了几个要求:

  1. additionalProperties``false必须为 中的每个对象设置为parameters
  2. 中的所有字段都properties必须标记为required

您可以通过添加选项来表示可选字段nulltype见下面的示例)。
已启用严格模式已禁用严格模式

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-json"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span><span style="color:var(--text-disabled)">7
</span><span style="color:var(--text-disabled)">8
</span><span style="color:var(--text-disabled)">9
</span><span style="color:var(--text-disabled)">10
</span><span style="color:var(--text-disabled)">11
</span><span style="color:var(--text-disabled)">12
</span><span style="color:var(--text-disabled)">13
</span><span style="color:var(--text-disabled)">14
</span><span style="color:var(--text-disabled)">15
</span><span style="color:var(--text-disabled)">16
</span><span style="color:var(--text-disabled)">17
</span><span style="color:var(--text-disabled)">18
</span><span style="color:var(--text-disabled)">19
</span><span style="color:var(--text-disabled)">20
</span><span style="color:var(--text-disabled)">21
</span><span style="color:var(--text-disabled)">22
</span></code>{
    <span style="color:var(--syntax4)">"type"</span>: <span style="color:var(--syntax3)">"function"</span>,
    <span style="color:var(--syntax4)">"name"</span>: <span style="color:var(--syntax3)">"get_weather"</span>,
    <span style="color:var(--syntax4)">"description"</span>: <span style="color:var(--syntax3)">"Retrieves current weather for the given location."</span>,
<span style="background-color:var(--pill-success-bg)">    <span style="color:var(--syntax4)">"strict"</span>: <span style="color:var(--syntax2)">true</span>,
</span>    <span style="color:var(--syntax4)">"parameters"</span>: {
        <span style="color:var(--syntax4)">"type"</span>: <span style="color:var(--syntax3)">"object"</span>,
        <span style="color:var(--syntax4)">"properties"</span>: {
            <span style="color:var(--syntax4)">"location"</span>: {
                <span style="color:var(--syntax4)">"type"</span>: <span style="color:var(--syntax3)">"string"</span>,
                <span style="color:var(--syntax4)">"description"</span>: <span style="color:var(--syntax3)">"City and country e.g. Bogotá, Colombia"</span>
            },
            <span style="color:var(--syntax4)">"units"</span>: {
<span style="background-color:var(--pill-success-bg)">                <span style="color:var(--syntax4)">"type"</span>: [<span style="color:var(--syntax3)">"string"</span>, <span style="color:var(--syntax3)">"null"</span>],
</span>                <span style="color:var(--syntax4)">"enum"</span>: [<span style="color:var(--syntax3)">"celsius"</span>, <span style="color:var(--syntax3)">"fahrenheit"</span>],
                <span style="color:var(--syntax4)">"description"</span>: <span style="color:var(--syntax3)">"Units the temperature will be returned in."</span>
            }
        },
<span style="background-color:var(--pill-success-bg)">        <span style="color:var(--syntax4)">"required"</span>: [<span style="color:var(--syntax3)">"location"</span>, <span style="color:var(--syntax3)">"units"</span>],
</span><span style="background-color:var(--pill-success-bg)">        <span style="color:var(--syntax4)">"additionalProperties"</span>: <span style="color:var(--syntax2)">false</span>
</span>    }
}</code></span>

操场上生成的所有模式都启用了严格模式。

虽然我们建议您启用严格模式,但它有一些限制:

  1. JSON 模式的某些功能不受支持。(请参阅支持的模式。)
  2. 架构在第一次请求时会经过额外处理(然后被缓存)。如果您的架构因请求而异,这可能会导致更高的延迟。
  3. 为了提高性能,模式会被缓存,并且不符合零数据保留的条件。

流媒体

流式传输可用于显示进度,通过显示在模型填充其参数时调用哪个函数,甚至实时显示参数。

流式函数调用与流式常规响应非常相似:您设置streamtrue获取不同的event对象。
流式函数调用
Python

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-python"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span><span style="color:var(--text-disabled)">7
</span><span style="color:var(--text-disabled)">8
</span><span style="color:var(--text-disabled)">9
</span><span style="color:var(--text-disabled)">10
</span><span style="color:var(--text-disabled)">11
</span><span style="color:var(--text-disabled)">12
</span><span style="color:var(--text-disabled)">13
</span><span style="color:var(--text-disabled)">14
</span><span style="color:var(--text-disabled)">15
</span><span style="color:var(--text-disabled)">16
</span><span style="color:var(--text-disabled)">17
</span><span style="color:var(--text-disabled)">18
</span><span style="color:var(--text-disabled)">19
</span><span style="color:var(--text-disabled)">20
</span><span style="color:var(--text-disabled)">21
</span><span style="color:var(--text-disabled)">22
</span><span style="color:var(--text-disabled)">23
</span><span style="color:var(--text-disabled)">24
</span><span style="color:var(--text-disabled)">25
</span><span style="color:var(--text-disabled)">26
</span><span style="color:var(--text-disabled)">27
</span><span style="color:var(--text-disabled)">28
</span><span style="color:var(--text-disabled)">29
</span><span style="color:var(--text-disabled)">30
</span><span style="color:var(--text-disabled)">31
</span><span style="color:var(--text-disabled)">32
</span></code><span style="color:var(--syntax2)">from</span> openai <span style="color:var(--syntax2)">import</span> OpenAI

client = OpenAI()

tools = [{
    <span style="color:var(--syntax3)">"type"</span>: <span style="color:var(--syntax3)">"function"</span>,
    <span style="color:var(--syntax3)">"name"</span>: <span style="color:var(--syntax3)">"get_weather"</span>,
    <span style="color:var(--syntax3)">"description"</span>: <span style="color:var(--syntax3)">"Get current temperature for a given location."</span>,
    <span style="color:var(--syntax3)">"parameters"</span>: {
        <span style="color:var(--syntax3)">"type"</span>: <span style="color:var(--syntax3)">"object"</span>,
        <span style="color:var(--syntax3)">"properties"</span>: {
            <span style="color:var(--syntax3)">"location"</span>: {
                <span style="color:var(--syntax3)">"type"</span>: <span style="color:var(--syntax3)">"string"</span>,
                <span style="color:var(--syntax3)">"description"</span>: <span style="color:var(--syntax3)">"City and country e.g. Bogotá, Colombia"</span>
            }
        },
        <span style="color:var(--syntax3)">"required"</span>: [
            <span style="color:var(--syntax3)">"location"</span>
        ],
        <span style="color:var(--syntax3)">"additionalProperties"</span>: <span style="color:var(--syntax2)">False</span>
    }
}]

stream = client.responses.create(
    model=<span style="color:var(--syntax3)">"gpt-4o"</span>,
    <span style="color:var(--syntax1)">input</span>=[{<span style="color:var(--syntax3)">"role"</span>: <span style="color:var(--syntax3)">"user"</span>, <span style="color:var(--syntax3)">"content"</span>: <span style="color:var(--syntax3)">"What's the weather like in Paris today?"</span>}],
    tools=tools,
    stream=<span style="color:var(--syntax2)">True</span>
)

<span style="color:var(--syntax2)">for</span> event <span style="color:var(--syntax2)">in</span> stream:
    <span style="color:var(--syntax1)">print</span>(event)</code></span>

输出事件

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-json"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span><span style="color:var(--text-disabled)">7
</span><span style="color:var(--text-disabled)">8
</span><span style="color:var(--text-disabled)">9
</span><span style="color:var(--text-disabled)">10
</span></code>{<span style="color:var(--syntax4)">"type"</span>:<span style="color:var(--syntax3)">"response.output_item.added"</span>,<span style="color:var(--syntax4)">"response_id"</span>:<span style="color:var(--syntax3)">"resp_1234xyz"</span>,<span style="color:var(--syntax4)">"output_index"</span>:<span style="color:var(--syntax4)">0</span>,<span style="color:var(--syntax4)">"item"</span>:{<span style="color:var(--syntax4)">"type"</span>:<span style="color:var(--syntax3)">"function_call"</span>,<span style="color:var(--syntax4)">"id"</span>:<span style="color:var(--syntax3)">"fc_1234xyz"</span>,<span style="color:var(--syntax4)">"call_id"</span>:<span style="color:var(--syntax3)">"call_1234xyz"</span>,<span style="color:var(--syntax4)">"name"</span>:<span style="color:var(--syntax3)">"get_weather"</span>,<span style="color:var(--syntax4)">"arguments"</span>:<span style="color:var(--syntax3)">""</span>}}
{<span style="color:var(--syntax4)">"type"</span>:<span style="color:var(--syntax3)">"response.function_call_arguments.delta"</span>,<span style="color:var(--syntax4)">"response_id"</span>:<span style="color:var(--syntax3)">"resp_1234xyz"</span>,<span style="color:var(--syntax4)">"item_id"</span>:<span style="color:var(--syntax3)">"fc_1234xyz"</span>,<span style="color:var(--syntax4)">"output_index"</span>:<span style="color:var(--syntax4)">0</span>,<span style="color:var(--syntax4)">"delta"</span>:<span style="color:var(--syntax3)">"{\""</span>}
{<span style="color:var(--syntax4)">"type"</span>:<span style="color:var(--syntax3)">"response.function_call_arguments.delta"</span>,<span style="color:var(--syntax4)">"response_id"</span>:<span style="color:var(--syntax3)">"resp_1234xyz"</span>,<span style="color:var(--syntax4)">"item_id"</span>:<span style="color:var(--syntax3)">"fc_1234xyz"</span>,<span style="color:var(--syntax4)">"output_index"</span>:<span style="color:var(--syntax4)">0</span>,<span style="color:var(--syntax4)">"delta"</span>:<span style="color:var(--syntax3)">"location"</span>}
{<span style="color:var(--syntax4)">"type"</span>:<span style="color:var(--syntax3)">"response.function_call_arguments.delta"</span>,<span style="color:var(--syntax4)">"response_id"</span>:<span style="color:var(--syntax3)">"resp_1234xyz"</span>,<span style="color:var(--syntax4)">"item_id"</span>:<span style="color:var(--syntax3)">"fc_1234xyz"</span>,<span style="color:var(--syntax4)">"output_index"</span>:<span style="color:var(--syntax4)">0</span>,<span style="color:var(--syntax4)">"delta"</span>:<span style="color:var(--syntax3)">"\":\""</span>}
{<span style="color:var(--syntax4)">"type"</span>:<span style="color:var(--syntax3)">"response.function_call_arguments.delta"</span>,<span style="color:var(--syntax4)">"response_id"</span>:<span style="color:var(--syntax3)">"resp_1234xyz"</span>,<span style="color:var(--syntax4)">"item_id"</span>:<span style="color:var(--syntax3)">"fc_1234xyz"</span>,<span style="color:var(--syntax4)">"output_index"</span>:<span style="color:var(--syntax4)">0</span>,<span style="color:var(--syntax4)">"delta"</span>:<span style="color:var(--syntax3)">"Paris"</span>}
{<span style="color:var(--syntax4)">"type"</span>:<span style="color:var(--syntax3)">"response.function_call_arguments.delta"</span>,<span style="color:var(--syntax4)">"response_id"</span>:<span style="color:var(--syntax3)">"resp_1234xyz"</span>,<span style="color:var(--syntax4)">"item_id"</span>:<span style="color:var(--syntax3)">"fc_1234xyz"</span>,<span style="color:var(--syntax4)">"output_index"</span>:<span style="color:var(--syntax4)">0</span>,<span style="color:var(--syntax4)">"delta"</span>:<span style="color:var(--syntax3)">","</span>}
{<span style="color:var(--syntax4)">"type"</span>:<span style="color:var(--syntax3)">"response.function_call_arguments.delta"</span>,<span style="color:var(--syntax4)">"response_id"</span>:<span style="color:var(--syntax3)">"resp_1234xyz"</span>,<span style="color:var(--syntax4)">"item_id"</span>:<span style="color:var(--syntax3)">"fc_1234xyz"</span>,<span style="color:var(--syntax4)">"output_index"</span>:<span style="color:var(--syntax4)">0</span>,<span style="color:var(--syntax4)">"delta"</span>:<span style="color:var(--syntax3)">" France"</span>}
{<span style="color:var(--syntax4)">"type"</span>:<span style="color:var(--syntax3)">"response.function_call_arguments.delta"</span>,<span style="color:var(--syntax4)">"response_id"</span>:<span style="color:var(--syntax3)">"resp_1234xyz"</span>,<span style="color:var(--syntax4)">"item_id"</span>:<span style="color:var(--syntax3)">"fc_1234xyz"</span>,<span style="color:var(--syntax4)">"output_index"</span>:<span style="color:var(--syntax4)">0</span>,<span style="color:var(--syntax4)">"delta"</span>:<span style="color:var(--syntax3)">"\"}"</span>}
{<span style="color:var(--syntax4)">"type"</span>:<span style="color:var(--syntax3)">"response.function_call_arguments.done"</span>,<span style="color:var(--syntax4)">"response_id"</span>:<span style="color:var(--syntax3)">"resp_1234xyz"</span>,<span style="color:var(--syntax4)">"item_id"</span>:<span style="color:var(--syntax3)">"fc_1234xyz"</span>,<span style="color:var(--syntax4)">"output_index"</span>:<span style="color:var(--syntax4)">0</span>,<span style="color:var(--syntax4)">"arguments"</span>:<span style="color:var(--syntax3)">"{\"location\":\"Paris, France\"}"</span>}
{<span style="color:var(--syntax4)">"type"</span>:<span style="color:var(--syntax3)">"response.output_item.done"</span>,<span style="color:var(--syntax4)">"response_id"</span>:<span style="color:var(--syntax3)">"resp_1234xyz"</span>,<span style="color:var(--syntax4)">"output_index"</span>:<span style="color:var(--syntax4)">0</span>,<span style="color:var(--syntax4)">"item"</span>:{<span style="color:var(--syntax4)">"type"</span>:<span style="color:var(--syntax3)">"function_call"</span>,<span style="color:var(--syntax4)">"id"</span>:<span style="color:var(--syntax3)">"fc_1234xyz"</span>,<span style="color:var(--syntax4)">"call_id"</span>:<span style="color:var(--syntax3)">"call_2345abc"</span>,<span style="color:var(--syntax4)">"name"</span>:<span style="color:var(--syntax3)">"get_weather"</span>,<span style="color:var(--syntax4)">"arguments"</span>:<span style="color:var(--syntax3)">"{\"location\":\"Paris, France\"}"</span>}}</code></span>

content但是,您不是将各块聚合成单个字符串,而是将各块聚合成编码的argumentsJSON 对象。

当模型调用一个或多个函数时,response.output_item.added每个函数调用都会发出一个包含以下字段的事件:

场地 描述
response_id 函数调用所属的响应的 id
output_index 响应中输出项的索引。这表示响应中的各个函数调用。
item 正在进行的函数调用项包括nameargumentsid字段

之后,您将收到一系列response.function_call_arguments.delta包含deltaarguments字段的类型的事件。这些事件包含以下字段:

场地 描述
response_id 函数调用所属的响应的 id
item_id delta 所属的函数调用项的 id
output_index 响应中输出项的索引。这表示响应中的各个函数调用。
delta 该字段的增量arguments

下面的代码片段演示了如何将deltas 聚合成最终tool_call对象。
累积 tool_call 增量
Python

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-python"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span><span style="color:var(--text-disabled)">7
</span><span style="color:var(--text-disabled)">8
</span><span style="color:var(--text-disabled)">9
</span><span style="color:var(--text-disabled)">10
</span></code>final_tool_calls = {}

<span style="color:var(--syntax2)">for</span> event <span style="color:var(--syntax2)">in</span> stream:
    <span style="color:var(--syntax2)">if</span> event.<span style="color:var(--syntax1)">type</span> === <span style="color:var(--syntax3)">'response.output_item.added'</span>:
        final_tool_calls[event.output_index] = event.item;
    <span style="color:var(--syntax2)">elif</span> event.<span style="color:var(--syntax1)">type</span> === <span style="color:var(--syntax3)">'response.function_call_arguments.delta'</span>:
        index = event.output_index

        <span style="color:var(--syntax2)">if</span> final_tool_calls[index]:
            final_tool_calls[index].arguments += event.delta</code></span>

累计 final_tool_calls[0]

code-sample-pre 复制代码
<span style="color:var(--text-default)"><code class="language-json"><code><span style="color:var(--text-disabled)">1
</span><span style="color:var(--text-disabled)">2
</span><span style="color:var(--text-disabled)">3
</span><span style="color:var(--text-disabled)">4
</span><span style="color:var(--text-disabled)">5
</span><span style="color:var(--text-disabled)">6
</span><span style="color:var(--text-disabled)">7
</span></code>{
    <span style="color:var(--syntax4)">"type"</span>: <span style="color:var(--syntax3)">"function_call"</span>,
    <span style="color:var(--syntax4)">"id"</span>: <span style="color:var(--syntax3)">"fc_1234xyz"</span>,
    <span style="color:var(--syntax4)">"call_id"</span>: <span style="color:var(--syntax3)">"call_2345abc"</span>,
    <span style="color:var(--syntax4)">"name"</span>: <span style="color:var(--syntax3)">"get_weather"</span>,
    <span style="color:var(--syntax4)">"arguments"</span>: <span style="color:var(--syntax3)">"{\"location\":\"Paris, France\"}"</span>
}</code></span>

当模型完成函数调用时,response.function_call_arguments.done将发出类型为的事件。此事件包含整个函数调用,包括以下字段:

场地 描述
response_id 函数调用所属的响应的 id
output_index 响应中输出项的索引。这表示响应中的各个函数调用。
item name包含、arguments和字段的函数调用项id

响应

相关推荐
夜晚中的人海12 分钟前
【C语言】初阶数据结构相关习题(二)
c语言·开发语言·数据结构
武昌库里写JAVA25 分钟前
MacOS Python3安装
java·开发语言·spring boot·学习·课程设计
Dxy123931021628 分钟前
python如何设置excel单元格边框样式
开发语言·python·excel
chaodaibing1 小时前
Python解析Excel入库如何做到行的拆分
开发语言·python·excel
程序员拂雨1 小时前
Angular 知识框架
前端·javascript·angular.js
dudly1 小时前
Python类的力量:第五篇:魔法方法与协议——让类拥有Python的“超能力”
开发语言·python
GoodStudyAndDayDayUp1 小时前
gitlab+portainer 实现Ruoyi Vue前端CI/CD
前端·vue.js·gitlab
ghost1431 小时前
C#学习第22天:网络编程
开发语言·学习·c#
程序员阿明1 小时前
vite运行只能访问localhost解决办法
前端·vue
前端 贾公子1 小时前
uniapp -- 验证码倒计时按钮组件
前端·vue.js·uni-app