在今天,OpenAI 的 CEO 山姆·奥特曼宣布推出了一项新的特性:支持 JSON 格式化输出。这一功能的引入将大大提升在实际业务场景中使用模型输出结构化数据的能力。
去年 DevDay 上,OpenAI 推出了 JSON 模式。这是一种对希望通过模型构建可靠应用程序的开发者非常有用的工具。虽然 JSON 模式提高了模型生成有效 JSON 输出的可靠性,但它不能保证响应完全符合特定的 schema。为了解决这个问题,OpenAI 推出了 API 的结构化输出功能,确保模型输出完全匹配开发者提供的 JSON Schema。
从非结构化输入生成结构化数据是当今应用程序中 AI 的核心应用场景之一。开发者利用 OpenAI API 构建强大的助手,这些助手能够通过函数调用获取数据并回答问题,提取结构化数据以进行数据录入,并构建多步骤的代理工作流程,使LLMs能够采取行动。长期以来,开发者通过开源工具、提示工程和反复重试请求来克服LLMs在这一领域的局限性,以确保模型输出符合与其系统互操作所需的格式。结构化输出通过约束 OpenAI 模型匹配开发者提供的模式,并通过训练我们的模型更好地理解复杂的模式,解决了这一问题。
在最近的评估中,新模型 gpt-4o-2024-08-06 凭借结构化输出获得了完美的 100%评分。相比之下,gpt-4-0613 的得分不足 40%。
示例请求
POST/v1/chat/completions{"model":"gpt-4o-2024-08-06","messages":[{"role":"system","content":"Youareahelpfulassistant.ThecurrentdateisAugust6,2024.Youhelpusersqueryforthedatatheyarelookingforbycallingthequeryfunction."},{"role":"user","content":"lookupallmyordersinmayoflastyearthatwerefulfilledbutnotdeliveredontime"}],"tools":[{"type":"function","function":{"name":"query","description":"Executeaquery.","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}}}]}示例输出 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"}
开发者现在可以通过 `json_schema` 为 `response_format` 参数提供一个 JSON Schema。当模型不调用工具,而是以结构化方式响应用户时,这一功能尤为有用。此功能适用于我们最新的 gpt-4o 系列模型:今日发布的 gpt-4o-2024-08-06 和 gpt-4o-mini-2024-07-18。当 `response_format` 设置为 `strict: true` 时,模型输出将匹配提供的 Schema。
示例请求
POST/v1/chat/completions{"model":"gpt-4o-2024-08-06","messages":[{"role":"system","content":"Youareahelpfulmathtutor."},{"role":"user","content":"solve8x+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}}}}示例输出 JSON
{"steps":[{"explanation":"Subtract31frombothsidestoisolatethetermwithx.","output":"8x+31-31=2-31"},{"explanation":"Thissimplifiesto8x=-29.","output":"8x=-29"},{"explanation":"Dividebothsidesby8tosolveforx.","output":"x=-29/8"}],"final_answer":"x=-29/8"}安全性始终是 OpenAI 的首要任务。新推出的结构化输出功能严格遵循现有的安全政策,并允许模型在遇到不安全请求时进行拒绝。为了方便开发者检测模型是否生成了拒绝而非与 schema 匹配的输出,API 响应中新增了一个拒绝字符串值。
当模型的响应不包含拒绝,并且响应没有因任何原因被过早中断(如通过 finish_reason 指示),则模型的响应将可靠地产生与提供的 schema 完全匹配的有效 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"}
OpenAI 的 Python 和 Node SDK 已更新以原生支持结构化输出。通过将 schema 作为工具或响应格式提供,开发者可以轻松地使用 Pydantic 或 Zod 对象。这使得 SDK 能够自动将数据类型转换为支持的 JSON schema,并将 JSON 响应反序列化为类型化的数据结构。
以下是如何通过函数调用实现结构化输出的示例:
from enum import Enumfrom typing import Unionfrom pydantic import BaseModelimport openaifrom openai import OpenAIclass Table(str, Enum):orders = "orders"customers = "customers"products = "products"class Column(str, Enum):id = "id"status = "status"expected_delivery_date = "expected_delivery_date"delivered_at = "delivered_at"shipped_at = "shipped_at"ordered_at = "ordered_at"canceled_at = "canceled_at"class Operator(str, Enum):eq = "="gt = ">"lt = "<"le = "<="ge = ">="ne = "!="class OrderBy(str, Enum):asc = "asc"desc = "desc"class DynamicValue(BaseModel):column_name: strclass Condition(BaseModel):column: stroperator: Operatorvalue: Union[str, int, DynamicValue]class Query(BaseModel):table_name: Tablecolumns: list[Column]conditions: list[Condition]order_by: OrderByclient = OpenAI()completion = client.beta.chat.completions.parse(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=[openai.pydantic_function_tool(Query),],)print(completion.choices[0].message.tool_calls[0].function.parsed_arguments)
原生结构化输出支持也可用于 `response_format`。
from pydantic import BaseModelfrom openai import OpenAIclass Step(BaseModel):explanation: stroutput: strclass MathResponse(BaseModel):steps: list[Step]final_answer: strclient = OpenAI()completion = client.beta.chat.completions.parse(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=MathResponse,)message = completion.choices[0].messageif message.parsed:print(message.parsed.steps)print(message.parsed.final_answer)else:print(message.refusal)
为模型提供一个单独的“思考链”字段,有助于提升最终回复的质量。
{"model":"gpt-4o-2024-08-06","messages":[{"role":"system","content":"Youareahelpfulassistant"},{"role":"user","content":"9.11and9.9--whichisbigger?"}],"response_format":{"type":"json_schema","json_schema":{"name":"reasoning_schema","strict":true,"schema":{"type":"object","properties":{"reasoning_steps":{"type":"array","items":{"type":"string"},"description":"Thereasoningstepsleadingtothefinalconclusion."},"answer":{"type":"string","description":"Thefinalanswer,takingintoaccountthereasoningsteps."}},"required":["reasoning_steps","answer"],"additionalProperties":false}}}}输出
{"reasoning_steps":["Firststepistocomparethenumbers9.11and9.9.","Bothnumbershavethesamewholenumberpart,whichis9.","Tocomparethedecimalparts,convertthemtothesamenumberofdecimalplaces.","9.11hastwodecimalplaces:itis9.11.","9.9hasonedecimalplace:itcanberewrittenas9.90.","Now,compare9.11and9.90bylookingatthedecimalparts.","Compare11with90.","90isgreaterthan11,so9.90isgreaterthan9.11."],"answer":"9.9isbiggerthan9.11."}| 欢迎光临 链载Ai (https://www.lianzai.com/) | Powered by Discuz! X3.5 |