Comparação de saída estruturada entre provedores populares de LLM - OpenAI, Gemini, Anthropic, Mistral e AWS Bedrock

APIs ligeiramente diferentes exigem uma abordagem especial.

Conteúdo da página

Aqui está uma comparação lado a lado de suporte para saída estruturada (obter JSON confiável de volta) entre provedores populares de LLM, juntamente com exemplos mínimos de Python

barras coloridas em pé

Já vimos como solicitar saída estruturada do LLM hospedado no Ollama. Aqui revisamos como solicitar a mesma coisa de outros provedores.

TL;DR matrix

Provedor Modo “JSON” nativo Enforceimento de JSON Schema Knob típico Notas
OpenAI Sim Sim (primeira classe) response_format={"type":"json_schema", ...} Funciona via a API de Respostas ou Chat Completions; também pode fazer chamadas de função.
Google Gemini Sim Sim (primeira classe) response_schema= + response_mime_type="application/json" Retorna JSON estritamente validado quando o schema é definido.
Anthropic (Claude) Indireto Sim (via Uso de Ferramenta com JSON schema) tools=[{input_schema=...}] + tool_choice Força o modelo a “chamar” sua ferramenta definida no schema; produz argumentos com formato de schema.
Mistral Sim Parcial (apenas JSON; sem schema no servidor) response_format={"type":"json_object"} Garante JSON, mas você valida contra seu schema do lado do cliente.
AWS Bedrock (plataforma) Varia por modelo Sim (via Tool/Converse schema) toolConfig.tools[].toolSpec.inputSchema A API Converse do Bedrock valida a entrada da ferramenta contra um JSON schema.

Saída Estruturada do LLM - Informações Gerais

A saída estruturada do LLM refere-se à capacidade dos modelos de linguagem grandes (LLMs) de gerar respostas que seguem estritamente um formato ou estrutura pré-definida, em vez de produzir texto livre. Essa saída estruturada pode estar em formatos como JSON, XML, tabelas ou modelos, tornando os dados legíveis por máquinas, consistentes e facilmente parseáveis por softwares para uso em várias aplicações.

As saídas estruturadas diferem das saídas tradicionais dos LLMs, que normalmente geram texto aberto e natural. Em vez disso, as saídas estruturadas impõem um schema ou formato, como objetos JSON com chaves definidas e tipos de valor, ou classes específicas na saída (por exemplo, respostas de múltipla escolha, classes de sentimento ou formatos de linha de banco de dados). Essa abordagem melhora a confiabilidade, reduz erros e alucinações e simplifica a integração em sistemas como bancos de dados, APIs ou fluxos de trabalho.

A geração de saídas estruturadas em LLMs frequentemente envolve técnicas como:

  • Especificar instruções detalhadas no prompt para guiar o modelo a produzir saída no formato desejado.
  • Usar ferramentas de validação e parse como Pydantic em Python para garantir que a saída corresponda ao schema.
  • Às vezes impor restrições de decodificação baseadas em gramática ou máquinas de estado finito para garantir a conformidade com o formato no nível de token.

Benefícios das saídas estruturadas dos LLMs incluem:

  • Legibilidade por máquina e facilidade de integração.
  • Redução da variabilidade e erros.
  • Maior previsibilidade e verificabilidade para tarefas que exigem formatos de dados consistentes.

Desafios incluem o design de schemas eficazes, lidar com dados aninhados complexos e possíveis limitações nas capacidades de raciocínio em comparação com a geração de texto livre.

Em geral, a saída estruturada permite que os LLMs sejam mais úteis em aplicações que exigem dados precisos e formatados, em vez de apenas texto legível por humanos.

Exemplos de Saída Estruturada em Python

Todos os trechos extraem informações de evento como JSON: {title, date, location}. Substitua as chaves/modelos conforme desejar.

1) OpenAI — JSON Schema (estricto)

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)

A funcionalidade de Saídas Estruturadas da OpenAI impõe esse schema do lado do servidor.


2) Google Gemini — schema de resposta + MIME JSON

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

# Configure with your API key
# 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)  # já é JSON válido conforme o schema

O Gemini retornará JSON estrito que conforma-se ao response_schema.


3) Anthropic (Claude) — Uso de Ferramenta com JSON schema

from anthropic import Anthropic
import json

client = Anthropic()

tool = {
    "name": "extract_event",
    "description": "Retornar detalhes do evento.",
    "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"},  # forçar schema
    messages=[{"role": "user", "content":
        "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
)

# O Claude vai "chamar" a ferramenta; pegue os argumentos (que correspondem ao seu schema)
tool_use = next(b for b in msg.content if b.type == "tool_use")
print(json.dumps(tool_use.input, indent=2))

O Claude não tem um interruptor de modo “JSON” genérico; em vez disso, o Uso de Ferramenta com um input_schema lhe dá argumentos validados com formato de schema (e você pode forçar seu uso).


4) Mistral — modo JSON (validação do lado do cliente)

from mistralai import Mistral
import json

client = Mistral()

resp = client.chat.complete(
    model="mistral-large-latest",
    messages=[{"role":"user","content":
        "Retorne JSON com chaves title, date (YYYY-MM-DD), location para: "
        "'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
    response_format={"type": "json_object"}  # garante JSON válido
)

data = json.loads(resp.choices[0].message.content)
print(data)
# Dica: valide `data` contra seu Pydantic/JSON Schema localmente.

O json_object do Mistral impõe forma JSON (não seu schema exato) — valide do lado do cliente.


5) AWS Bedrock — API Converse Tool schema (modelo-agnostic)

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"}},  # forçar schema
    messages=[{"role":"user","content":[{"text":
        "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}]}],
)

# Puxe o conteúdo de 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))

O Bedrock valida a entrada da ferramenta contra seu JSON schema e muitos modelos hospedados (por exemplo, Claude) suportam isso através da Converse.


Diretrizes práticas e Validação

  • Se você quiser as garantias mais fortes do lado do servidor: Saídas estruturadas da OpenAI ou schema de resposta do Gemini.
  • Se você já estiver no Claude/Bedrock: defina uma Ferramenta com um JSON schema e force seu uso; leia os argumentos da ferramenta como seu objeto tipado.
  • Se você usar o Mistral: ative json_object e valide localmente (por exemplo, com Pydantic).

Padrão de validação (funciona para todos eles)

from pydantic import BaseModel, ValidationError

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

try:
    event = Event.model_validate(data)  # `data` de qualquer provedor
except ValidationError as e:
    # lidar / reintentar / pedir ao modelo para corrigir com e.errors()
    print(e)