OpenAPI函数调用教程:让AI自动调用REST API

本文介绍如何将OpenAPI规范转换为函数定义,使GPT模型能够根据用户指令自动调用外部API。通过解析OpenAPI规范中的operationId、描述和参数,生成符合Chat Completions API要求的函数列表。模型通过工具调用机制返回结构化参数,开发者据此执行实际API调用。文章提供了完整的Python实现,包括JSON引用解析、函数定义生成、链式调用处理,并讨论了最佳实践、常见错误及生产环境优化方案。

技术背景

OpenAPI规范(OAS)是描述RESTful API的机器可读标准,广泛用于API文档和客户端生成。将OAS与函数调用结合,可让AI模型理解API结构并自动生成调用参数,从而无需手动编写接口调用逻辑。这解决了传统AI应用中API集成繁琐、难以扩展的问题,适用于需要动态调用多个服务的场景,如智能助手、自动化工作流。主要限制包括模型可能生成无效参数、需要处理API错误、以及规范复杂度影响解析准确性。

核心原理

核心原理是将OpenAPI规范中的每个操作(路径+方法)映射为函数定义,包含名称(operationId)、描述和参数schema。模型根据用户指令和函数定义,通过工具调用(tool_calls)返回一个JSON对象,其中包含函数名和参数。开发者解析该JSON并执行实际API调用,然后将结果作为工具消息返回给模型,以便模型生成最终回复。链式调用通过循环处理多个工具调用实现,直到模型不再请求调用或达到最大次数。

架构分析

系统分为三个主要组件:1) OpenAPI规范解析器:使用jsonref解析$ref引用,提取操作信息生成函数列表;2) 模型交互层:通过Chat Completions API发送消息和函数定义,接收模型响应;3) 执行与反馈循环:解析工具调用,执行API,将结果追加到消息历史,继续对话。设计决策包括使用operationId作为函数名以保证唯一性,将请求体和参数分别封装为parameters对象,以及设置MAX_CALLS防止无限循环。

完整实战教程

使用OpenAPI规范进行函数调用

OpenAPI规范(以前称为Swagger规范)是一种用于描述HTTP API的机器可读格式。通过将OpenAPI规范与函数调用结合,你可以让AI模型根据用户请求自动调用外部API。

为什么使用OpenAPI规范?

设置步骤

1. 定义OpenAPI规范

首先,你需要创建一个OpenAPI规范文件(通常为YAML或JSON格式),描述你的API。例如:

openapi: 3.0.0
info:
  title: 天气API
  version: 1.0.0
paths:
  /weather:
    get:
      summary: 获取天气信息
      parameters:
        - name: city
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 成功

2. 将规范传递给模型

在调用模型时,将OpenAPI规范作为上下文的一部分传递给模型。这样,模型就能理解可用的函数及其参数。

3. 解析模型输出

模型会生成一个函数调用请求,你需要解析该请求并执行相应的API调用。

代码示例

以下是一个使用Python和OpenAI API的示例:

import openai
import json
# 定义OpenAPI规范
openapi_spec = """
openapi: 3.0.0
info:
  title: 天气API
  version: 1.0.0
paths:
  /weather:
    get:
      summary: 获取天气信息
      parameters:
        - name: city
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 成功
"""
# 调用模型
response = openai.ChatCompletion.create(
    model="gpt-4",
    messages=[
        {"role": "system", "content": "你是一个助手,可以调用API获取天气信息。"},
        {"role": "user", "content": "北京今天天气怎么样?"},
    ],
    functions=[{
        "name": "get_weather",
        "description": "获取天气信息",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
        },
    }],
    function_call="auto",
)
# 解析模型输出
if response.choices[0].message.get("function_call"):
    function_call = response.choices[0].message.function_call
    arguments = json.loads(function_call.arguments)
    city = arguments["city"]
    # 执行API调用
    # ...

最佳实践

结论

使用OpenAPI规范进行函数调用,可以显著提升AI应用的交互能力。通过标准化API描述,模型能够自动调用外部服务,实现更丰富的功能。

互联网的很大一部分由 RESTful API 驱动。让 GPT 能够调用它们将开启无限可能。本笔记本演示了如何利用 GPT 智能调用 API。它利用了 OpenAPI 规范和链式函数调用。

OpenAPI 规范(OAS) 是一种通用标准,用于以机器可读和可解释的格式描述 RESTful API 的详细信息。它使人类和计算机都能理解服务的能力,并且可以用来向 GPT 展示如何调用 API。

本笔记本分为两个主要部分:

  1. 如何将示例 OpenAPI 规范转换为聊天补全 API 的函数定义列表。
  2. 如何使用聊天补全 API 根据用户指令智能调用这些函数。

我们建议在继续之前熟悉函数调用。

!pip install -q jsonref # for resolving $ref's in the OpenAPI spec
!pip install -q openai
import os
import json
import jsonref
from openai import OpenAI
import requests
from pprint import pp
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY", "<your OpenAI API key if not set as env var>"))

如何将 OpenAPI 规范转换为函数定义

我们这里使用的示例 OpenAPI 规范是由 gpt-4 创建的。我们将把这个示例规范转换为一组函数定义,供聊天补全 API 使用。模型根据提供的用户指令,生成一个包含调用这些函数所需参数的 JSON 对象。

在继续之前,让我们检查一下这个生成的规范。OpenAPI 规范包含有关 API 端点、它们支持的操作、接受的参数、可以处理的请求以及返回的响应的详细信息。该规范以 JSON 格式定义。

规范中的端点包括以下操作:

规范中的每个操作都有一个 operationId,当我们解析规范为函数规范时,将使用它作为函数名称。规范还包括定义每个操作参数的数据类型和结构的模式。

您可以在这里看到模式:

with open('./data/example_events_openapi.json', 'r') as f:
    openapi_spec = jsonref.loads(f.read())  # it's important to load with jsonref, as explained below
display(openapi_spec)

现在我们对 OpenAPI 规范有了很好的理解,可以继续将其解析为函数规范。

我们可以编写一个简单的 openapi_to_functions 函数来生成定义列表,其中每个函数表示为一个包含以下键的字典:

对于架构中定义的每个端点,我们需要执行以下操作:

  1. 解析 JSON 引用:在 OpenAPI 规范中,通常使用 JSON 引用(也称为 $ref)来避免重复。这些引用指向在多个地方使用的定义。例如,如果多个 API 端点返回相同的对象结构,则该结构可以定义一次,然后在需要的地方引用。我们需要解析这些引用,并将其替换为它们指向的内容。
  1. 提取函数名称:我们将简单地使用 operationId 作为函数名称。或者,我们可以使用端点路径和操作作为函数名称。
  1. 提取描述和参数:我们将遍历 description、summary、requestBody 和 parameters 字段来填充函数的描述和参数。

以下是实现:

def openapi_to_functions(openapi_spec):
    functions = []
    for path, methods in openapi_spec["paths"].items():
        for method, spec_with_ref in methods.items():
            # 1. Resolve JSON references.
            spec = jsonref.replace_refs(spec_with_ref)
            # 2. Extract a name for the functions.
            function_name = spec.get("operationId")
            # 3. Extract a description and parameters.
            desc = spec.get("description") or spec.get("summary", "")
            schema = {"type": "object", "properties": {}}
            req_body = (
                spec.get("requestBody", {})
                .get("content", {})
                .get("application/json", {})
                .get("schema")
            )
            if req_body:
                schema["properties"]["requestBody"] = req_body
            params = spec.get("parameters", [])
            if params:
                param_properties = {
                    param["name"]: param["schema"]
                    for param in params
                    if "schema" in param
                }
                schema["properties"]["parameters"] = {
                    "type": "object",
                    "properties": param_properties,
                }
            functions.append({
                "type": "function",
                "function": {
                    "name": function_name,
                    "description": desc,
                    "parameters": schema,
                },
            })
    return functions
functions = openapi_to_functions(openapi_spec)
for function in functions:
    pp(function)
    print()

如何让GPT调用这些函数

现在我们有了这些函数定义,就可以利用 GPT 根据用户输入智能地调用它们。

需要注意的是,聊天补全 API 不会执行函数;相反,它会生成 JSON,你可以用这些 JSON 在自己的代码中调用函数。

关于函数调用的更多信息,请参阅我们专门的函数调用指南。

SYSTEM_MESSAGE = """
You are a helpful assistant.
Respond to the following prompt by using function_call and then summarize actions.
Ask for clarification if a user request is ambiguous.
"""
# Maximum number of function calls allowed to prevent infinite or lengthy loops
MAX_CALLS = 5
def get_openai_response(functions, messages):
    return client.chat.completions.create(
        model="gpt-3.5-turbo-16k",
        tools=functions,
        tool_choice="auto",  # "auto" means the model can pick between generating a message or calling a function.
        temperature=0,
        messages=messages,
    )
def process_user_instruction(functions, instruction):
    num_calls = 0
    messages = [
        {"content": SYSTEM_MESSAGE, "role": "system"},
        {"content": instruction, "role": "user"},
    ]
    while num_calls < MAX_CALLS:
        response = get_openai_response(functions, messages)
        message = response.choices[0].message
        print(message)
        try:
            print(f"\n>> Function call #: {num_calls + 1}\n")
            pp(message.tool_calls)
            messages.append(message)
            # For the sake of this example, we'll simply add a message to simulate success.
            # Normally, you'd want to call the function here, and append the results to messages.
            messages.append({
                "role": "tool",
                "content": "success",
                "tool_call_id": message.tool_calls[0].id,
            })
            num_calls += 1
        except:
            print("\n>> Message:\n")
            print(message.content)
            break
    if num_calls >= MAX_CALLS:
        print(f"Reached max chained function calls: {MAX_CALLS}")
USER_INSTRUCTION = """
Instruction: Get all the events.
Then create a new event named AGI Party.
Then delete event with id 2456.
"""
process_user_instruction(functions, USER_INSTRUCTION)

结论

我们已经演示了如何将 OpenAPI 规范转换为函数规范,这些规范可以提供给 GPT,使其能够智能地调用这些函数,并展示了如何将这些函数链接在一起以执行复杂的操作。

该系统的可能扩展包括:处理需要条件逻辑或循环的更复杂的用户指令,与真实 API 集成以执行实际操作,以及改进错误处理和验证,以确保指令可行且函数调用成功。

常见问题

常见错误:1) 未解析$ref导致schema不完整,应使用jsonref加载和替换引用;2) 函数名重复,需确保operationId唯一;3) 模型返回无效JSON参数,需增加验证和错误处理;4) 未处理工具调用结果,导致模型无法继续;5) 达到最大调用次数,需优化指令或增加循环上限。排查方法:打印模型响应和工具调用,检查参数是否符合schema,使用日志记录API调用。

企业应用扩展

生产环境优化:1) 使用异步API调用提高并发性能;2) 实现参数验证和错误重试机制;3) 缓存API响应以减少延迟;4) 监控模型调用和API调用成本;5) 支持更复杂的OpenAPI特性,如认证、分页、文件上传;6) 集成真实API并处理错误响应;7) 使用更强大的模型(如gpt-4)提高函数调用准确性。

总结

本文介绍如何将OpenAPI规范转换为函数定义,使GPT模型能够根据用户指令自动调用外部API。通过解析OpenAPI规范中的operationId、描述和参数,生成符合Chat Completions API要求的函数列表。模型通过工具调用机制返回结构化参数,开发者据此执行实际API调用。文章提供了完整的Python实现,包括JSON引用解析、函数定义生成、链式调用处理,并讨论了最佳实践、常见错误及生产环境优化方案。

内容来源与验证

继续系统学习

站内还有更多完整实战教程

加入会员,解锁全部教程、完整代码与持续更新内容。

加入会员
查看全部API 与工程实践教程