MLM之GPT-4o:在GPT-4o的806版本的 API 中引入结构化输出—可以可靠地遵循开发人员提供的 JSON 模式

MLM之GPT-4o:在GPT-4o的806版本的 API 中引入结构化输出---可以可靠地遵循开发人员提供的 JSON 模式

导读 :2024年8月6日,OpenAI推出了新的API功能"结构化输出",旨在更好地帮助人们理解和与大型语言模型的输出进行交互。这种新功能可以为输出提供更多上下文和注释,使其更加结构化和可理解。
什么是结构化输出? 结构化输出是将大型语言模型的自然语言输出与JSON数据结构相结合的一种方式。它允许模型在回答时提供额外的元数据和注释,使输出更易于解析和理解。通过使用结构化输出,开发人员可以更好地控制和定制模型输出。
结构化输出的用途

提高输出的可解释性和透明度

更好地控制输出格式和内容

支持更复杂的用例,如任务分解和自动化流程
使用示例

文章提供了一个分解任务的示例,展示了如何使用结构化输出分步完成一个复杂的任务。

该示例说明了结构化输出在提高输出质量和可用性方面的优势。
如何使用

开发人员可以通过OpenAI的API来开启和使用结构化输出功能。

文章提供了相关代码示例,说明如何在API调用中指定结构化输出。
总结

OpenAI新推出的结构化输出功能,让开发人员能够更好地控制和定制大型语言模型的输出。通过提供额外的元数据和注释,这种新功能提高了输出的可解释性和可用性。结构化输出在任务分解、自动化流程等复杂用例中具有重要应用前景。

目录

[在 API 中引入了"结构化输出"功能](#在 API 中引入了“结构化输出”功能)

如何使用结构化输出

函数调用

Request

[Output JSON](#Output JSON)

[response_format 参数的新选项](#response_format 参数的新选项)

Request

[Output JSON](#Output JSON)

安全的结构化输出

[原生 SDK 支持](#原生 SDK 支持)

其他使用场景

根据用户意图动态生成用户界面

将最终答案与支持性推理或附加评论分开

从非结构化数据中提取结构化数据

底层机制

受限解码

替代方法

限制和注意事项


在 API 中引入了"结构化输出"功能

去年在 DevDay 上,我们推出了 JSON 模式,这为希望使用我们模型构建可靠应用程序的开发者提供了一个有用的构建模块。尽管 JSON 模式提高了生成有效 JSON 输出的模型可靠性,但它并不能保证模型的响应会符合特定的架构。今天,我们在 API 中引入了"结构化输出"功能,这是一项新功能,旨在确保模型生成的输出将完全匹配开发者提供的 JSON 架构。

从非结构化输入生成结构化数据是当今应用程序中 AI 的核心用例之一。开发者使用 OpenAI API 构建功能强大的助手,这些助手能够通过函数调用获取数据并回答问题、提取用于数据输入的结构化数据,以及构建允许大型语言模型(LLM)采取行动的多步代理工作流程。开发者长期以来一直通过开源工具、提示和反复重试请求来解决 LLM 在这一领域的局限性,以确保模型输出符合其系统所需的格式。结构化输出通过限制 OpenAI 模型匹配开发者提供的架构,并通过训练我们的模型更好地理解复杂的架构,解决了这个问题。

在我们对复杂 JSON 架构跟随的评估中,我们的新模型 gpt-4o-2024-08-06 在使用结构化输出时得分为 100%。相比之下,gpt-4-0613 的得分不到 40%。

使用结构化输出时,gpt-4o-2024-08-06 在我们的评估中达到了 100% 的可靠性,完美匹配输出架构。

官网地址https://openai.com/index/introducing-structured-outputs-in-the-api/

如何使用结构化输出

我们在 API 中以两种形式引入了结构化输出:

函数调用

通过设置 strict: true 来实现通过工具的结构化输出。此功能适用于所有支持工具的模型,包括 gpt-4-0613 和 gpt-3.5-turbo-0613 及以后的所有模型。当启用结构化输出时,模型输出将匹配提供的工具定义。

Request
POST /v1/chat/completions
{
  "model": "gpt-4o-2024-08-06",
  "messages": [
    {
      "role": "system",
      "content": "You are a helpful assistant. The current date is August 6, 2024. You help users query for the data they are looking for by calling the query function."
    },
    {
      "role": "user",
      "content": "look up all my orders in may of last year that were fulfilled but not delivered on time"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "query",
        "description": "Execute a query.",
        "strict": true,
        "parameters": {
          "type": "object",
          "properties": {
            "table_name": {
              "type": "string",
              "enum": ["orders"]
            },
            "columns": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "id",
                  "status",
                  "expected_delivery_date",
                  "delivered_at",
                  "shipped_at",
                  "ordered_at",
                  "canceled_at"
                ]
              }
            },
            "conditions": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "column": {
                    "type": "string"
                  },
                  "operator": {
                    "type": "string",
                    "enum": ["=", ">", "<", ">=", "<=", "!="]
                  },
                  "value": {
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "number"
                      },
                      {
                        "type": "object",
                        "properties": {
                          "column_name": {
                            "type": "string"
                          }
                        },
                        "required": ["column_name"],
                        "additionalProperties": false
                      }
                    ]
                  }
                },
                "required": ["column", "operator", "value"],
                "additionalProperties": false
              }
            },
            "order_by": {
              "type": "string",
              "enum": ["asc", "desc"]
            }
          },
          "required": ["table_name", "columns", "conditions", "order_by"],
          "additionalProperties": false
        }
      }
    }
  ]
}
Output JSON
{
  "table_name": "orders",
  "columns": ["id", "status", "expected_delivery_date", "delivered_at"],
  "conditions": [
    {
      "column": "status",
      "operator": "=",
      "value": "fulfilled"
    },
    {
      "column": "ordered_at",
      "operator": ">=",
      "value": "2023-05-01"
    },
    {
      "column": "ordered_at",
      "operator": "<",
      "value": "2023-06-01"
    },
    {
      "column": "delivered_at",
      "operator": ">",
      "value": {
        "column_name": "expected_delivery_date"
      }
    }
  ],
  "order_by": "asc"
}

response_format 参数的新选项

开发者现在可以通过 response_format 参数的新选项 json_schema 提供 JSON 架构。当模型不调用工具时,但以结构化方式响应用户时,这非常有用。此功能适用于我们最新的 GPT-4o 模型:今天发布的 gpt-4o-2024-08-06 和 gpt-4o-mini-2024-07-18。当提供了 response_format 并设置 strict: true 时,模型输出将匹配提供的架构。

Request
POST /v1/chat/completions
{
  "model": "gpt-4o-2024-08-06",
  "messages": [
    {
      "role": "system",
      "content": "You are a helpful math tutor."
    },
    {
      "role": "user",
      "content": "solve 8x + 31 = 2"
    }
  ],
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "math_response",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "steps": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "explanation": {
                  "type": "string"
                },
                "output": {
                  "type": "string"
                }
              },
              "required": ["explanation", "output"],
              "additionalProperties": false
            }
          },
          "final_answer": {
            "type": "string"
          }
        },
        "required": ["steps", "final_answer"],
        "additionalProperties": false
      }
    }
  }
}
Output JSON
{
  "steps": [
    {
      "explanation": "Subtract 31 from both sides to isolate the term with x.",
      "output": "8x + 31 - 31 = 2 - 31"
    },
    {
      "explanation": "This simplifies to 8x = -29.",
      "output": "8x = -29"
    },
    {
      "explanation": "Divide both sides by 8 to solve for x.",
      "output": "x = -29 / 8"
    }
  ],
  "final_answer": "x = -29 / 8"
}

安全的结构化输出

安全性是 OpenAI 的首要任务------新的结构化输出功能将遵守我们现有的安全政策,并仍然允许模型拒绝不安全的请求。为了简化开发,API 响应中有一个新的拒绝字符串值,允许开发者通过编程检测模型是否生成了拒绝,而不是与架构匹配的输出。当响应不包含拒绝且模型的响应未被提前中断(由 finish_reason 指示)时,模型的响应将可靠地产生有效的与提供的架构匹配的 JSON。

{
  "id": "chatcmpl-9nYAG9LPNonX8DAyrkwYfemr3C8HC",
  "object": "chat.completion",
  "created": 1721596428,
  "model": "gpt-4o-2024-08-06",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "refusal": "I'm sorry, I cannot assist with that request."
      },
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 81,
    "completion_tokens": 11,
    "total_tokens": 92
  },
  "system_fingerprint": "fp_3407719c7f"
}

原生 SDK 支持

我们的 Python 和 Node SDK 已更新为原生支持结构化输出。为工具或响应格式提供架构就像提供 Pydantic 或 Zod 对象一样简单,我们的 SDK 将自动处理将数据类型转换为支持的 JSON 架构、将 JSON 响应反序列化为类型化数据结构,并在出现拒绝时进行解析。

以下示例展示了函数调用中对结构化输出的原生支持。

response_format 的原生结构化输出支持也可用。

其他使用场景

开发者经常使用 OpenAI 的模型为各种使用场景生成结构化数据。其他一些示例包括:

根据用户意图动态生成用户界面

例如,开发者可以使用结构化输出创建代码或 UI 生成应用程序。所有以下示例都使用相同的 response_format,并可用于根据用户输入生成不同的 UI。

将最终答案与支持性推理或附加评论分开

为模型提供一个独立的思维链字段以提高最终响应的质量可能会有所帮助。

从非结构化数据中提取结构化数据

例如,指示模型从会议记录中提取待办事项、截止日期和任务。

底层机制

我们采取了两部分的方法来提高与 JSON 架构匹配的模型输出的可靠性。首先,我们训练了最新的模型 gpt-4o-2024-08-06,以理解复杂的架构以及如何最好地生成与之匹配的输出。然而,模型行为本质上是非确定性的------尽管该模型的性能有所改进(我们的基准测试中为 93%),但它仍未达到开发者构建稳健应用程序所需的可靠性。因此,我们还采取了一种基于工程的确定性方法,限制模型的输出以实现 100% 的可靠性。

受限解码

我们的方法基于一种称为受限采样或受限解码的技术。默认情况下,当对模型进行采样以生成输出时,它们完全不受限制,可以从词汇表中选择任何词元作为下一个输出。这种灵活性使模型可以犯错误;例如,即使这不会产生有效的 JSON,它们通常仍可以在任何时候自由采样出大括号词元。为了强制生成有效的输出,我们将模型限制为仅根据提供的架构有效的词元,而不是所有可用的词元。

在实践中实现这种限制可能具有挑战性,因为在模型输出过程中有效的词元会有所不同。假设我们有以下架构:

在输出开始时有效的词元包括 {、{"、{\n 等。然而,一旦模型已经采样了 {"val,则 { 不再是有效的词元。因此,我们需要实施动态受限解码,并在每个词元生成后确定哪些词元是有效的,而不是在响应开始时就预先确定。

为此,我们将提供的 JSON 架构转换为上下文无关文法(CFG)。文法是一组定义语言的规则,上下文无关文法是一种符合特定规则的文法。您可以将 JSON 和 JSON 架构视为具有规则定义其有效性的特定语言。正如在英语中没有动词的句子是不合法的,在 JSON 中有尾随逗号也是不合法的。

因此,对于每个 JSON 架构,我们计算出一个表示该架构的文法,并预处理其组件以便在模型采样过程中轻松访问。这就是为什么第一次使用新架构的请求会有延迟惩罚------我们必须预处理架构以生成此工件,供我们在采样期间有效使用。

在采样时,每个词元之后,我们的推理引擎将根据先前生成的词元和文法中指示哪些词元是下一个有效的规则,确定哪些词元是接下来可以生成的。然后我们使用这个词元列表来屏蔽下一步采样,从而将无效词元的概率有效地降低为 0。由于我们已预处理了架构,因此我们可以使用缓存的数据结构有效地执行此操作,并具有最小的延迟开销。

替代方法

解决此问题的替代方法通常使用有限状态机(FSM)或正则表达式(通常使用 FSM 实现)进行受限解码。这些方法类似,都是在每个词元生成后动态更新哪些词元有效,但与 CFG 方法有一些关键区别。值得注意的是,CFG 可以表达比 FSM 更广泛的语言类别。实际上,对于像上面显示的值架构这样的非常简单的架构,这并不重要。然而,我们发现这种差异对于涉及嵌套或递归数据结构的更复杂架构来说意义重大。举个例子,FSM 通常不能表达递归类型,这意味着基于 FSM 的方法可能难以在深度嵌套的 JSON 中匹配括号。以下是一个在 OpenAI API 中支持结构化输出的递归架构示例,而 FSM 无法表达:

请注意,每个 UI 元素可以有任意的子元素,这些子元素递归地引用根架构。这种灵活性是 CFG 方法提供的。

限制和注意事项

使用结构化输出时需注意的几点限制:

结构化输出仅允许使用我们文档中详细介绍的 JSON 架构子集。这有助于我们确保最佳性能。

第一次使用新架构的 API 响应将产生额外的延迟,但随后的响应将很快,无延迟惩罚。这是因为在第一次请求期间,我们按上述方式处理架构,然后缓存这些工件以供稍后快速重用。典型架构在首次请求时处理时间少于 10 秒,但更复杂的架构可能需要长达一分钟的时间。

如果模型选择拒绝不安全的请求,则模型可能无法遵循架构。如果它选择拒绝,返回消息将具有拒绝布尔值 true 以指示这一点。

如果生成达到 max_tokens 或其他停止条件之前未完成,则模型可能无法遵循架构。

结构化输出不能防止所有类型的模型错误。例如,模型可能仍会在 JSON 对象的值中犯错误(例如,在数学方程中出错)。

相关推荐
不惑_4 小时前
最佳实践 · 如何高效索引MySQL JSON字段
java·mysql·json
天上掉下来个程小白1 天前
请求响应-05.请求-日期参数&JSON参数
spring boot·json
敲代码不忘补水1 天前
Python Pickle 与 JSON 序列化详解:存储、反序列化与对比
开发语言·python·json
jackletter1 天前
c#:System.Text.Json 的使用四(如何忽略[JsonPropertyName])
c#·json·序列化
A 八方1 天前
Python JSON
开发语言·python·json
小故渊2 天前
JSON对象
运维·服务器·json
SelectDB技术团队2 天前
查询性能提升 10 倍、存储空间节省 65%,Apache Doris 半结构化数据分析方案及典型场景
数据结构·数据仓库·elasticsearch·log4j·json
深夜吞食3 天前
项目实现:云备份③(配置文件加载模块、数据管理模块的实现)
linux·c语言·c++·json
Amo Xiang3 天前
Python 常用模块(二):json模块
开发语言·python·json
howeres4 天前
Jackson
json