OpenAI 官宣结构化输出功能
根据广泛的用户需求,OpenAI 的 API 现已正式支持结构化输出(Structured Outputs)。这一功能允许模型输出遵循开发人员提供的 JSON Schema,从而将自然语言转换为具有明确格式和结构的数据。
什么是结构化输出?
在大型语言模型(LLMs)的应用中,让模型进行结构化输出是一个重要目标。结构化输出指的是将自然语言转换成具有明确格式和结构的数据,如表格、数据库条目、JSON 对象等。通过实现这一点,不仅可以提高模型输出的可预测性和可用性,还能增强其在各种应用场景中的实用性。
结构化输出有助于减少误差,提高数据处理效率,并确保在与其他系统和应用程序集成时的一致性和兼容性。这一特性对于自动化工作流程、数据分析、自然语言处理任务以及智能助手等方面尤为重要。
结构化输出 vs JSON Mode
结构化输出是 JSON 模式的演变。虽然两者都确保生成有效的 JSON,但只有结构化输出确保架构合规性。
- JSON Mode: 强制模型返回 JSON 格式,但不保证符合特定的 Schema 定义。
- 结构化输出: 不仅要求 JSON 格式,还严格验证字段类型、必填项和嵌套结构,确保数据完全符合 Pydantic 模型或 JSON Schema 的定义。
Chat Completions API、Assistants API、Fine-tuning API 和 Batch API 均支持结构化输出和 JSON 模式。建议尽可能始终使用结构化输出而不是 JSON 模式,以获得更强的可靠性。
注意:目前仅 gpt-4o-mini、gpt-4o-mini-2024-07-18 和 gpt-4o-2024-08-06 模型快照及更高版本支持结构化输出。
代码示例:OpenAI SDK
1. 思维链数学辅导
此示例展示了如何使用结构化输出来引导模型逐步解决数学问题。
from pydantic import BaseModel
from openai import OpenAI
client = OpenAI()
class Step(BaseModel):
explanation: str
output: str
class MathReasoning(BaseModel):
steps: list[Step]
final_answer: str
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,
)
math_reasoning = completion.choices[0].message.parsed
print(math_reasoning)
返回结果示例:
{
"steps": [
{
"explanation": "Start with the equation 8x + 7 = -23.",
"output": "8x + 7 = -23"
},
{
"explanation": "Subtract 7 from both sides to isolate the term with the variable.",
"output": "8x = -30"
},
{
"explanation": "Divide both sides by 8 to solve for x.",
"output": "x = -30 / 8"
}
],
"final_answer": "x = -15 / 4"
}
2. 非结构化数据提取
定义结构化字段以从非结构化输入数据(例如检索论文)中提取信息。
from pydantic import BaseModel
from openai import OpenAI
client = OpenAI()
class ResearchPaperExtraction(BaseModel):
title: str
authors: list[str]
abstract: str
keywords: list[str]
completion = client.beta.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=[
{"role": "system", "content": "You are an expert at structured data extraction. You will be given unstructured text from a research paper and should convert it into the given structure."},
{"role": "user", "content": "..."}
],
response_format=ResearchPaperExtraction,
)
research_paper = completion.choices[0].message.parsed
print(research_paper)
生态系统集成:LangChain
LangChain 和 LlamaIndex 提供了大量结构化输出的方式,方便开发者快速集成。
1. Pydantic 声明
使用 Pydantic 声明你的数据模型。Pydantic 的 BaseModel 就像是 Python 的数据类,但具有实际的类型检查和强制转换。
from typing import List
from langchain.output_parsers import PydanticOutputParser
from langchain.prompts import PromptTemplate
from langchain_community.chat_models import ChatOpenAI
from langchain_core.pydantic_v1 import BaseModel, Field, validator
model = ChatOpenAI(temperature=0)
class Joke(BaseModel):
setup: str = Field(description="设立笑话的问题")
punchline: str = Field(description="解决笑话的答案")
@validator("setup")
def question_ends_with_question_mark(cls, field):
if field[-1] != "?":
raise ValueError("问题格式不正确!")
return field
joke_query = "给我讲个笑话。"
parser = PydanticOutputParser(pydantic_object=Joke)
prompt = PromptTemplate(
template="回答用户查询。\n{format_instructions}\n{query}\n",
input_variables=["query"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)
chain = prompt | model | parser
result = chain.invoke({"query": joke_query})
2. JSON 输出解析器
LangChain 支持通过特定格式和标签生成 JSON 格式的数据,方便后续处理和分析。
from typing import List
from langchain.prompts import PromptTemplate
from langchain_community.chat_models import ChatOpenAI
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field
model = ChatOpenAI(temperature=0)
class Joke(BaseModel):
setup: str = Field(description="问题以设置笑话")
punchline: str = Field(description="回答以解决笑话")
joke_query = "Tell me a joke."
parser = JsonOutputParser(pydantic_object=Joke)
prompt = PromptTemplate(
template="回答用户的查询。\n{format_instructions}\n{query}\n",
input_variables=["query"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)
chain = prompt | model | parser
chain.invoke({"query": joke_query})
3. 表格数据生成
可以生成 CSV 或 Excel 格式的表格数据,适用于各种数据分析和报告需求。
from langchain.output_parsers import CommaSeparatedListOutputParser
from langchain.prompts import PromptTemplate
from langchain_community.chat_models import ChatOpenAI
output_parser = CommaSeparatedListOutputParser()
format_instructions = output_parser.get_format_instructions()
prompt = PromptTemplate(
template="List five {subject}.\n{format_instructions}",
input_variables=["subject"],
partial_variables={"format_instructions": format_instructions}
)
model = ChatOpenAI(temperature=0)
_input = prompt.format(subject="ice cream flavors")
output = model(_input)
result = output_parser.parse(output)
最佳实践与注意事项
1. 错误处理
尽管结构化输出能极大提高稳定性,但在生产环境中仍需考虑网络超时或模型响应异常的情况。建议在调用 parse 方法后增加 try-except 块来捕获潜在的解析错误。
2. 成本考量
结构化输出通常比标准文本生成消耗更多的计算资源,因为模型需要同时生成文本并验证其是否符合 Schema。在实际应用中,需权衡精度提升带来的收益与 Token 成本的增加。
3. 模型选择
并非所有模型都支持结构化输出。在使用前,请确认所选模型版本(如 gpt-4o 系列)是否包含该功能。旧版模型可能仅支持 JSON Mode,无法保证 Schema 合规性。
总结
OpenAI 推出的结构化输出功能为开发者提供了更可靠的 API 交互体验。通过结合 Pydantic 和 LangChain 等工具,可以快速构建高可用性的 AI 应用。随着更多模型的适配,这一功能将成为构建企业级 AI 系统的基础设施之一。