虽然提示词中可以通过json格式示例方式,指定模型的结构话输出。
然而这种方式比较容易出错,轻微的输出不规范,就会导致json解析失败。
目前使用OpenAI API进行JSON结构化输出,主要有两种推荐的方法:
1)Structured Outputs
2)Function Calling
其中,Structured Outputs是更新、更可靠的方式,能保证模型输出符合定义的JSON Schema。
这时尝试基于网络资料,给出具体的实现方法和代码示例。
1 Structured Outputs
1.1 功能描述
这是OpenAI在2024年8月推出的功能,可靠性最高。
在response_format中提供严格的JSON Schema,确保模型输出符合预期。
当然,该功能要求新一些的gpt模型,比如gpt-4o-2024-08-06。
现在已经是2026年,大部分的国内新模型应该也支持,比如本测试所用的Qwen3.5。
要求如下:
所有对象必须设置"additionalProperties": false
所有字段必须包含在required数组中,不支持可选字段。
1.2 代码示例
这里是基于OpenAI pythjon SDK的代码示例。
这里使用PyDantic,这是最简洁的方式,直接利用Pydantic模型定义数据结构。
整个过程不需要定义json结构。
import os
model_name = "qwen3.5-xxx"
os.environ['OPENAI_API_KEY'] = gpt_api_keyxxxx
os.environ['OPENAI_BASE_URL'] = gpt_api_urlxxxxx
from openai import OpenAI
from pydantic import BaseModel
from typing import List
# 1. 定义你的数据结构(Pydantic模型)
class City(BaseModel):
name: str
country: str
population: int
class CitiesData(BaseModel):
cities: List[City]
# 2. 初始化客户端
client = OpenAI()
# 3. 调用API,将模型传入 response_format
completion = client.beta.chat.completions.parse(
model=model_name,
messages=[
{"role": "system", "content": "提取文本中的城市信息。"},
{"role": "user", "content": "柏林是德国的首都,人口约385万。巴黎是法国首都,人口216万。"}
],
response_format=CitiesData, # 关键参数
)
# 4. 获取结果
result: CitiesData = completion.choices[0].message.parsed
print(result.cities[0].name) # 输出: 柏林
print(result.model_dump_json(indent=2)) # 输出格式化的JSON
输出示例如下所示,可见已正确结构话。
柏林
{
"cities": [
{
"name": "柏林",
"country": "德国",
"population": 385
}
]
}
1.3 原始api示例
Structured Outputs方式也支持通过在原始api请求中指定json schema的方式来结构话输出。
这里需要直接构造HTTP请求,准备一个严格的json schema。
示例如下。
{
"model": "qwen3.5xxx",
"messages": [
{"role": "system", "content": "提取城市信息。"},
{"role": "user", "content": "柏林是德国的首都..."}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "cities_response",
"strict": true, // 必须为 true
"schema": {
"type": "object",
"properties": {
"cities": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"country": {"type": "string"},
"population": {"type": "integer"}
},
"required": ["name", "country", "population"],
"additionalProperties": false
}
}
},
"required": ["cities"],
"additionalProperties": false
}
}
}
}
2 Function Calling
2.1 功能描述
Function Calling方法即工具函数调用犯法,也成为tools方法。
这是Structured Outputs推出前的标准做法,适用于需要模型同时输出文本和调用函的场景。
比如,调用函数处理复杂逻辑
Function Calling的特点是:
1)模型会决定是否调用某个函数。
2)返回的结果在tool_calls参数中。
3)相比Structured Outputs,它允许一定的灵活性,如可选字段,但可靠性略低。
2.2 代码示例
这里通过python sdk示例Function Calling方法。
from openai import OpenAI
client = OpenAI()
tools = [
{
"type": "function",
"function": {
"name": "get_city_info",
"description": "获取城市信息",
"parameters": {
"type": "object",
"properties": {
"name": {"type": "string"},
"country": {"type": "string"},
"population": {"type": "integer"}
},
"required": ["name", "country"],
"additionalProperties": False,
},
"strict": True, # 开启严格模式
}
}
]
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": "告诉我关于柏林的信息"}
],
tools=tools,
tool_choice="auto" # 让模型决定是否调用
)
# 提取函数调用的参数
tool_call = response.choices[0].message.tool_calls[0]
arguments = json.loads(tool_call.function.arguments)
print(arguments) # 输出: {'name': '柏林', 'country': '德国'}
输出如下所示
{'name': '柏林', 'country': '德国'}
3 JSON Mode
这是最早期的方法,仅保证输出是合法的JSON,不保证符合你的Schema。
使用时必须在prompt中包含"json"关键词。
response = client.chat.completions.create(
model="gpt-3.5-turbo", # 仅限部分旧模型
messages=[{"role": "user", "content": "返回JSON格式的数据。关键字:json"}],
response_format={"type": "json_object"} # 仅保证是JSON,不保证格式
)
4 关键注意事项
1)模型兼容性
不是所有模型都支持Structured Outputs。
如果遇到报错 `Invalid parameter: "response_format" of type "json_object" is not supported with this model`,说明当前模型不支持。
2)拒绝响应处理
当模型因安全策略拒绝回答时,返回的JSON中会包含refusal字段而不是你要的内容。
代码中需要处理这种情况。
3)成本与速度
使用`strict: true`时,第一个请求会因预计算语法树而稍慢,后续请求会恢复正常。
reference
Introducing Structured Outputs in the API
https://openai.com/index/introducing-structured-outputs-in-the-api/
Tutorial: Generating Structured Output with OpenAI
Structured Output Example
OpenAI 函数调用:上手示例大全
https://docs.kanaries.net/zh/articles/openai-function-calling