OpenAI的结构化输出:如何用JSON实现安全与灵活性的完美平衡?
- Rifx.Online
- Programming , Technology , Generative AI
- 11 Jan, 2025
过去,在使用OpenAI的JSON模式时,模型输出与指定和预定义的JSON架构不匹配并没有保证。在我看来,这确实使得这个功能在生产环境中不可靠,因为一致性非常重要……
然而,这一切随着OpenAI所称的结构化输出而改变,他们将其描述为JSON模式的演变。
如下面的图片所示,旧的JSON模式仍然可用,与较新的结构化输出并行。然而,正如我在2023年11月已经提到的,缺乏强制/确保模型遵循结构的可能性,其他途径会更有效。
因此,OpenAI建议用户始终使用结构化输出而不是JSON模式。
JSON是全球应用程序交换数据最广泛使用的格式之一。
结构化输出提供了几个关键好处。它们通过消除验证或重试格式不正确的响应的需要来增强类型安全性。
此外,基于安全性的模型拒绝现在可以通过编程方式检测,使得处理这些情况变得更容易。
此外,它们简化了提示,因为在不需要强或特定提示的情况下实现了一致的格式。
函数调用
函数调用也是创建结构化输出的一种途径……这里有一些背景……
自主性级别
在使用语言模型进行函数调用时,模型通过确定是否调用特定函数或依赖其默认处理方式来获得一定的自主性。
当模型识别到需要一个函数时,它会自主切换到更结构化的模式,为函数调用准备必要的数据和参数。
这种能力使语言模型能够充当中介,有效地处理函数,同时在处理请求时保持灵活性。
AI的自主性可以视为一个光谱,其中独立程度取决于系统的设计方式。
通过将函数调用纳入生成式AI应用程序,我们不仅引入了结构,还引入了初步的自主层,使模型能够评估请求并决定是使用函数还是基于其默认能力提供答案。
随着AI技术的发展,这种自主性预计会增加,模型将变得更加独立,能够独立处理越来越复杂的任务。
这种演变增强了AI系统承担更复杂责任的能力,所需的人类干预最小化。
JSON模式演变为结构化输出
正如我之前提到的,结构化输出是JSON模式演变的下一步。
虽然两者都保证生成有效的JSON,但只有 结构化输出确保严格遵循定义的模式。
结构化输出和JSON模式都在聊天完成API、助手API、微调API和批处理API中得到支持。
思维链
下面是一个完整的 Python 工作示例,您可以将其复制并粘贴到 Notebook 中。代码将提示您输入您的 OpenAI API 密钥…
这是一个使用 gpt-4o-2024–08–06
模型的示例……该模型被指示以结构化的方式输出答案,并逐步引导用户完成过程。
您可以要求模型以结构化的逐步方式输出答案,以引导用户找到解决方案。
请注意,这段代码仅展示了思维链的实现,以及推理顺序的展现。在这个示例中,没有给模型提供 JSON 模式以遵循。
## Install the necessary packages
!pip install openai pydantic
## Import the modules
from pydantic import BaseModel
from openai import OpenAI
import getpass
import json
## Prompt the user for their OpenAI API key
api_key = getpass.getpass("Enter your OpenAI API key: ")
## Initialize the OpenAI client with the provided API key
client = OpenAI(api_key=api_key)
## Define the Step and MathReasoning classes using Pydantic
class Step(BaseModel):
explanation: str
output: str
class MathReasoning(BaseModel):
steps: list[Step]
final_answer: str
## Use the OpenAI client to parse a chat completion for a math problem
completion = client.beta.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=[
{"role": "system", "content": "You are a helpful math tutor. Guide the user through the solution step by step."},
{"role": "user", "content": "how can I solve 8x + 7 = -23"}
],
response_format=MathReasoning,
)
## Extract the parsed math reasoning from the completion
math_reasoning = completion.choices[0].message.parsed
## Convert the math reasoning to a JSON string and print it
print(json.dumps(math_reasoning.dict(), indent=4))
以及响应…
{
"steps": [
{
"explanation": "给定的方程是 8x + 7 = -23。要解出 x,我们首先需要将含有 x 的项隔离到一边。我们应该通过从两边减去 7,将左边的常数移到右边。",
"output": "8x + 7 - 7 = -23 - 7"
},
{
"explanation": "从两边减去 7 简化了方程。左边变为 8x,因为 7 - 7 为 0,右边变为 -30。",
"output": "8x = -30"
},
{
"explanation": "现在我们已经隔离了项 8x,我们需要解出 x。由于 8x 意味着 8 乘以 x,我们将方程的两边都除以 8 来找出 x 的值。",
"output": "x = -30 / 8"
},
{
"explanation": "将 -30 除以 8 得到 -3.75。这是满足方程的 x 的值。",
"output": "x = -3.75"
}
],
"final_answer": "x = -3.75"
}
使用结构化输出与 response_format
以下是完全可用的示例代码,可以直接在 Notebook 中使用。
请注意,在此示例中,定义了模型输出必须遵循的 JSON 架构。
!pip install openai
import openai
import json
class OpenAIClient:
def __init__(self, api_key: str):
"""
使用提供的 API 密钥初始化 OpenAI 客户端。
"""
openai.api_key = api_key
def get_structured_output_with_schema(self, prompt: str, schema: dict):
"""
调用 OpenAI API,并根据给定的提示和架构请求结构化输出。
"""
try:
# 调用 OpenAI API,response_format 设置为 'structured',并提供架构
# 在提示中包含架构
prompt_with_schema = f"{prompt} \n\n 响应应符合此架构的 JSON 格式: {json.dumps(schema)}"
response = openai.chat.completions.create(
model="gpt-4", # 使用支持结构化输出的模型
messages=[
{"role": "user", "content": prompt_with_schema}
],
max_tokens=150,
)
return response.choices[0].message.content.strip() # 提取并返回响应
except Exception as e:
return f"发生错误: {e}"
@staticmethod
def prompt_for_api_key():
"""
提示用户输入他们的 OpenAI API 密钥。
"""
api_key = input("请输入您的 OpenAI API 密钥: ")
return api_key
## 示例用法:
## 定义结构化输出的 JSON 架构
schema = {
"type": "object",
"properties": {
"benefits": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"maxItems": 5
}
},
"required": ["benefits"]
}
## 提示用户输入 API 密钥
api_key = OpenAIClient.prompt_for_api_key()
## 初始化 OpenAI 客户端
client = OpenAIClient(api_key)
## 使用示例提示测试函数
prompt = "提供 3-5 个使用结构化输出在 AI 应用中的好处。"
result = client.get_structured_output_with_schema(prompt, schema)
## 打印结果
print("结构化输出响应:")
if result.startswith("发生错误"):
print(result) # 如果发生错误则打印错误信息
else:
print(json.dumps(json.loads(result), indent=2)) # 美化打印 JSON 响应
查询结果如下……
{
"type": "object",
"properties": {
"benefits": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"maxItems": 5,
"default": [
"结构化输出可以处理输出元素内部和之间的复杂关系和依赖。",
"结构化输出预测可以更精细地控制,提供更准确和具体的结果。",
"结构化输出有助于更好地表示和抽象 AI 中复杂的问题和任务。",
"利用结构化输出可以减少 AI 系统不同组件之间沟通中的误解和错误。",
"结构化输出可以更好地解释和理解 AI 过程及其结论。"
]
}
},
"required": [
"benefits"
]
}
最后
语言模型现在提供了高级功能,如函数调用、结构化输出和推理,使开发人员能够将复杂任务直接委托给模型。
这种转变使工作流程更加流畅,但也要求开发者仔细决定他们希望将多少功能委托给模型,而不是在其应用逻辑中实现。
过多地将任务委托给模型可能导致业务应用程序与特定模型及其独特能力紧密耦合,从而使未来的更新或更改变得更加困难。
随着模型的演变,这种耦合可能会妨碍应用程序的灵活性并限制其适应性。另一方面,通过保持应用逻辑的模块化,开发人员可以设计出与模型无关的系统,能够协调多个模型以完成多样化的任务。
这种方法能够提供更大的灵活性,使企业能够在新模型出现时整合多种模型,并根据未来需求进行调整,而不必锁定在单一解决方案中。