AI在线 AI在线

一文读懂LLM基于JSON Schema的结构化输出

什么是基于JSON Schema的结构化输出大语言模型通常会生成无特定结构的自由格式文本,在能够有效使用之前需要进行大量的后期处理。 这种不可预测性会导致错误、浪费时间并增加成本。 OpenAI推出基于JSON Schema的结构化输出以解决这一问题。

一文读懂LLM基于JSON Schema的结构化输出

什么是基于JSON Schema的结构化输出

大语言模型通常会生成无特定结构的自由格式文本,在能够有效使用之前需要进行大量的后期处理。这种不可预测性会导致错误、浪费时间并增加成本。

OpenAI推出基于JSON Schema的结构化输出以解决这一问题。结构化输出确保模型响应遵循严格的格式,减少错误,并使将大语言模型集成到需要一致的、机器可读数据的应用程序中变得更加容易,对于一致性和准确性至关重要的任务其输出更为可靠。

通常情况下,大语言模型基于概率预测逐个生成文本标记。不过,如果需要以特定格式生成文本,这种方法就不太适用了。结构化输出通过预定义的规则或模式来引导这一过程,使每个标记都符合所需的结构。

如何使用基于JSON Schema的结构化输出

并非所有的模型都支持基于JSON Schema的结构化输出。经测试,文心一言支持结构化输出。通义千问、豆包、deepseek还不支持。

下面以输出方程求解过程的结构化输出为例,阐述OpenAI Python SDK使用结构化输出的两种方法。

先准备好开发环境,以windows开发环境为例:

设置Python开发环境

安装uv。uv是一个用Rust编写的极其快速的Python包和项目管理器。

复制
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

创建python虚拟环境(假设项目目录为structured-output)

复制
# Create a new directory for our project
uv init structured-output
cd structured-output

# Create virtual environment and activate it
uv venv
.venv\Scripts\activate

# Install dependencies
uv add openai python-dotenv

设置环境变量

创建.env,.env内容如下(注意修改OPENAI_API_KEY为您的key)

复制
OPENAI_API_KEY=your_api_key_here
OPENAI_BASE_URL=https://qianfan.baidubce.com/v2
MODEL_NAME=ernie-3.5-128k

把.env添加到.gitignore

结构化输出方法1:手工定义Schema

通过设置chat completion的response_format打开结构化输出。response_format的格式为:

复制
{
    type: "json_schema", 
    json_schema: {
        "strict": true, 
        "schema": ...
    } 
}

完整例子如下:

复制
import os
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()  # load environment variables from .env


client = OpenAI()
chat_completion = client.chat.completions.create(
    messages=[
        {
            "role": "system",
            "content": "你是一位数学老师。一步步引导用户完成解题过程"
        },
        {
            "role": "user",
            "content": "我该如何解7x + 6 = 41这个方程"
        }
    ],
    model=os.getenv("MODEL_NAME"),
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "math_response",
            "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
            },
            "strict": True
        }
    },
)
content = chat_completion.choices[0].message.content
print(content)

输出结果如下:

复制
{
    "final_answer":"x = 5",
    "steps":[
        {
            "explanation":"首先,我们需要将方程中的常数项移至等式的另一边,使方程左侧只剩下未知数x的系数和x本身。",
            "output":"7x = 41 - 6"
        },
        {
            "explanation":"进行减法运算,简化方程。",
            "output":"7x = 35"
        },
        {
            "explanation":"接下来,我们需要将x的系数化为1,以求解x的值。为此,我们将方程两边同时除以7。",
            "output":"x = 35 ÷ 7"
        },
        {
            "explanation":"进行除法运算,得出x的值。",
            "output":"x = 5"
        }
    ]
}

结构化输出方法2:使用自定义的pydantic模型

通过设置chat completion的response_format为自定义的pydantic模型MathReasoning

完整例子如下:

复制
import os
from openai import OpenAI
from dotenv import load_dotenv
from pydantic import BaseModel


class Step(BaseModel):
    explanation: str
    output: str


class MathReasoning(BaseModel):
    steps: list[Step]
    final_answer: str


load_dotenv()  # load environment variables from .env


client = OpenAI()
chat_completion = client.beta.chat.completions.parse(
    messages=[
        {
            "role": "system",
            "content": "你是一位乐于助人的数学老师。一步步引导用户完成解题过程"
        },
        {
            "role": "user",
            "content": "我该如何解7x + 6 = 41这个方程"
        }
    ],
    model=os.getenv("MODEL_NAME"),
    response_format=MathReasoning,
)
math_reasoning = chat_completion.choices[0].message.parsed
print(math_reasoning.model_dump_json(indent=4))

输出结果为:

复制
{
    "steps":[
        {
            "explanation":"首先,我们需要将方程中的常数项移至等式的另一边。从7x + 6 = 41开始,我们可以从两边同时减去6。",
            "output":"7x + 6 - 6 = 41 - 6"
        },
        {
            "explanation":"简化上一步的等式,得到7x = 35。",
            "output":"7x = 35"
        },
        {
            "explanation":"接下来,我们需要解出x的值。为此,我们可以将方程两边同时除以7。",
            "output":"7x / 7 = 35 / 7"
        },
        {
            "explanation":"简化上一步的等式,得到x = 5。",
            "output":"x = 5"
        }
    ],
    "final_answer":"x = 5"
}

JSON Schema结构化输出 VS JSON模式

JSON Schema结构化输出是JSON模式的进阶版本。JSON模式是通过设置response_format为{ "type": "json_object" }打开。使用JSON模式时,你必须始终通过对话中的某些消息(例如系统消息)指示模型生成JSON。JSON 模式不能保证输出符合任何特定的模式。

总结

JSON Schema结构化输出提供了一个强大的解决方案,可确保您的大语言模型生成可靠、可预测且机器可读的回复。结构化输出有助于您在不同应用程序中保持一致的数据格式,从而更轻松地管理复杂的工作流程。

相关资讯

大语言模型(LLM)是如何思考的?讲讲推动下一代人工智能推理的五种途径

译者 | 张哲刚审校 | 重楼大语言模型(LLMs)最早时期只是具备自动完成的功能,迄今为止,进步巨大,与当初已经不可同日而语。 然而,仅仅是生成流畅的文本并不足以体现真正的智能——真正的智能是需要推理能力的。 这意味着,大语言模型需要能够解决数学问题、能够调试代码、能够得出合乎逻辑的结论,还要能够检查和改正自身的错误。
4/8/2025 8:18:38 AM
张哲刚

揭秘 RAG:为什么说它是让大语言模型(LLM)更聪明的秘密武器?

现在人工智能(AI)很火,尤其是像 ChatGPT 这样的大语言模型(LLM),它们能聊天、写文章、写代码,感觉无所不能。 但有时候,它们也会犯一些小错误,比如信息过时了,或者一本正经地胡说八道(这叫“幻觉”),或者你问它一些你们公司内部的事情,它就完全不知道了。 为了解决这些问题,科学家们想出了一个聪明的办法,叫做RAG。
4/25/2025 10:03:12 AM
用户007

如何估算大语言模型LLM 的 GPU 内存:用于本地运行 LLM 的 GPU 内存

随着 DeepSeek、GPT、Llama、Mistral 等大规模 LLM 的兴起,AI 从业者面临的最大挑战之一是确定需要多少 GPU 内存才能高效地服务于这些模型。 GPU 资源昂贵且稀缺,因此优化内存分配至关重要。 本指南将引导您使用一个简单而有效的公式来估算服务 LLM 所需的 GPU 内存。
5/9/2025 1:00:00 AM
晓晓
  • 1