跨主流LLM提供商(OpenAI、Gemini、Anthropic、Mistral和AWS Bedrock)的结构化输出对比

略有不同的 API 需要特殊处理。

目录

以下是结构化输出在主流大语言模型(LLM)提供商之间的对比,以及一些Python示例:

彩色条形图

我们已经查看了如何从在Ollama上托管的LLM请求结构化输出。在这里,我们将回顾如何从其他提供商请求相同的输出。

TL;DR 矩阵

提供商 本机“JSON模式” JSON 模式强制执行 典型旋钮 备注
OpenAI 是(第一类) response_format={"type":"json_schema", ...} 通过响应API或聊天完成实现;也可以进行函数调用。
Google Gemini 是(第一类) response_schema= + response_mime_type="application/json" 设置模式后返回严格验证的JSON。
Anthropic (Claude) 间接 是(通过工具使用与JSON模式) tools=[{input_schema=...}] + tool_choice 强制模型“调用”您定义的模式工具;生成符合模式的参数。
Mistral 部分(仅JSON;无服务器端模式) response_format={"type":"json_object"} 确保JSON,但您需在客户端验证模式。
AWS Bedrock(平台) 根据模型而定 是(通过工具/Converse模式) toolConfig.tools[].toolSpec.inputSchema Bedrock的Converse API根据JSON模式验证工具输入。

LLM结构化输出 - 一般信息

LLM结构化输出指的是大型语言模型(LLMs)生成响应的能力,这些响应严格遵循预定义的特定格式或结构,而不是生成自由形式的文本。这种结构化输出可以是JSON、XML、表格或模板等格式,使数据可被机器读取、保持一致,并且易于软件解析,以便在各种应用中使用。

结构化输出与传统的LLM输出不同,后者通常生成开放式的自然语言文本。相反,结构化输出强制执行模式或格式,例如具有定义键和值类型的JSON对象,或输出中的特定类(例如多项选择答案、情感类别或数据库行格式)。这种方法提高了可靠性,减少了错误和幻觉,并简化了与数据库、API或工作流程等系统的集成。

LLM中结构化输出的生成通常涉及以下技术:

  • 指定详细的提示指令,以指导模型以所需格式生成输出。
  • 使用验证和解析工具,如Python中的Pydantic,以确保输出与模式匹配。
  • 有时根据语法或有限状态机强制解码约束,以确保在格式上的标记级合规性。

结构化LLM输出的优点包括:

  • 机器可读性和易于集成。
  • 减少变异性与错误。
  • 对需要一致数据格式的任务提高可预测性和可验证性。

挑战包括设计有效的模式、处理复杂的嵌套数据,以及与自由形式文本生成相比可能存在的推理能力限制。

总体而言,结构化输出使LLM在需要精确格式化数据的应用中更加有用,而不仅仅是人类可读的文本。

结构化输出 Python 示例

所有代码片段都提取事件信息为JSON:{title, date, location}。您可以根据需要替换键/模型。

1) OpenAI — JSON Schema(严格)

from openai import OpenAI
import json

client = OpenAI()

schema = {
    "name": "Event",
    "schema": {
        "type": "object",
        "properties": {
            "title": {"type": "string"},
            "date":  {"type": "string", "description": "YYYY-MM-DD"},
            "location": {"type": "string"}
        },
        "required": ["title", "date", "location"],
        "additionalProperties": False
    },
    "strict": True
}

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "user", "content": "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}
    ],
    response_format={"type": "json_schema", "json_schema": schema},
)

data = json.loads(resp.choices[0].message.content)
print(data)

OpenAI的结构化输出功能在服务器端强制执行此模式。


2) Google Gemini — 响应模式 + JSON MIME

import google.generativeai as genai
from google.genai import types

# 使用您的API密钥进行配置
# genai.configure(api_key="your-api-key")

schema = types.Schema(
    type=types.Type.OBJECT,
    properties={
        "title": types.Schema(type=types.Type.STRING),
        "date": types.Schema(type=types.Type.STRING),
        "location": types.Schema(type=types.Type.STRING),
    },
    required=["title", "date", "location"],
    additional_properties=False,
)

resp = genai.generate_content(
    model="gemini-2.0-flash",
    contents="Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'",
    generation_config=genai.GenerationConfig(
        response_mime_type="application/json",
        response_schema=schema,
    ),
)

print(resp.text)  # 已经是符合模式的JSON

Gemini将返回严格符合response_schema的JSON。


3) Anthropic (Claude) — 工具使用与JSON模式

from anthropic import Anthropic
import json

client = Anthropic()

tool = {
    "name": "extract_event",
    "description": "返回事件详情。",
    "input_schema": {
        "type": "object",
        "properties": {
            "title": {"type": "string"},
            "date": {"type": "string"},
            "location": {"type": "string"}
        },
        "required": ["title", "date", "location"],
        "additionalProperties": False
    }
}

msg = client.messages.create(
    model="claude-3-5-sonnet-20241022",
    max_tokens=256,
    tools=[tool],
    tool_choice={"type": "tool", "name": "extract_event"},  # 强制使用模式
    messages=[{"role": "user", "content":
        "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
)

# Claude将“调用”工具;获取参数(符合您的模式)
tool_use = next(b for b in msg.content if b.type == "tool_use")
print(json.dumps(tool_use.input, indent=2))

Claude没有通用的“JSON模式”开关;相反,工具使用与**input_schema**为您提供验证过的、符合模式的参数(您可以强制使用它)。


4) Mistral — JSON模式(客户端验证)

from mistralai import Mistral
import json

client = Mistral()

resp = client.chat.complete(
    model="mistral-large-latest",
    messages=[{"role":"user","content":
        "Return JSON with keys title, date (YYYY-MM-DD), location for: "
        "'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
    response_format={"type": "json_object"}  # 保证有效JSON
)

data = json.loads(resp.choices[0].message.content)
print(data)
# 提示:使用Pydantic/JSON Schema在本地验证`data`。

Mistral的json_object强制执行JSON形状(不是您的精确模式)——在客户端进行验证。


5) AWS Bedrock — Converse API 工具模式(模型无关)

import boto3, json

bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
model_id = "anthropic.claude-3-5-sonnet-20240620-v1:0"

tools = [{
    "toolSpec": {
        "name": "extract_event",
        "inputSchema": {
            "json": {
                "type": "object",
                "properties": {
                    "title": {"type": "string"},
                    "date": {"type": "string"},
                    "location": {"type": "string"}
                },
                "required": ["title","date","location"],
                "additionalProperties": False
            }
        }
    }
}]

resp = bedrock.converse(
    modelId=model_id,
    toolConfig={"tools": tools},
    toolChoice={"tool": {"name": "extract_event"}},  # 强制使用模式
    messages=[{"role":"user","content":[{"text":
        "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}]}],
)

# 提取toolUse内容
tool_use = next(
    c["toolUse"] for c in resp["output"]["message"]["content"] if "toolUse" in c
)
print(json.dumps(tool_use["input"], indent=2))

Bedrock根据您的JSON模式验证工具输入,并且许多托管模型(例如Claude)通过Converse支持它。


实用指南和验证

  • 如果您想要最强的服务器端保证: 使用OpenAI结构化输出或Gemini响应模式。
  • 如果您已经在使用Claude/Bedrock: 定义一个带有JSON模式的工具并强制使用它;将工具的参数读取为您的类型对象。
  • 如果您使用Mistral: 启用json_object并在本地进行验证(例如使用Pydantic)。

验证模式(适用于所有)

from pydantic import BaseModel, ValidationError

class Event(BaseModel):
    title: str
    date: str
    location: str

try:
    event = Event.model_validate(data)  # `data`来自任何提供商
except ValidationError as e:
    # 处理/重试/让模型修复,使用e.errors()
    print(e)

有用的链接