Comparação de saída estruturada entre provedores populares de LLMs - 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 do suporte para saída estruturada (obter JSON confiável de volta) em provedores populares de LLMs, além de exemplos mínimos em Python

barras coloridas em pé

Já olhamos como solicitar saída estruturada do LLM hospedado no Ollama. Quando o JSON retorna pela rede, a validação de saída estruturada de LLM em Python que se sustenta percorre a análise, verificações Pydantic, novas tentativas e testes no seu serviço. Aqui, revisamos como solicitar o mesmo de outros provedores.

Matriz TL;DR

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

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

A saída estruturada de LLM refere-se à capacidade dos modelos de linguagem de grande porte (LLMs) de gerar respostas que aderem estritamente a um formato ou estrutura predefinido e específico, em vez de produzir texto livre. Esta saída estruturada pode estar em formatos como JSON, XML, tabelas ou modelos, tornando os dados legíveis por máquina, consistentes e facilmente analisáveis por software para uso em várias aplicações.

As saídas estruturadas diferem das saídas tradicionais de LLM, que tipicamente geram texto aberto em linguagem natural. Em vez disso, as saídas estruturadas aplicam um schema ou formato, como objetos JSON com chaves e tipos de valores definidos, ou classes específicas na saída (por exemplo, respostas de múltipla escolha, classes de sentimento ou formatos de linhas de banco de dados). Esta 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 de prompt para guiar o modelo a produzir saída no formato desejado.
  • Usar ferramentas de validação e análise como Pydantic em Python para garantir que a saída corresponda ao schema.
  • Às vezes, aplicar restrições de decodificação baseadas em gramática ou máquinas de estados finitos para garantir conformidade no nível de tokens com o formato.

Os benefícios das saídas estruturadas de LLM incluem:

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

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

No 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 Python para Saída Estruturada

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

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)

O recurso Structured Outputs da OpenAI aplica este schema no lado do servidor.


2) Google Gemini — schema de resposta + JSON MIME

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

# Configure com sua chave de 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)  # já é um JSON válido conforme o schema

O Gemini retornará JSON estrito que está em conformidade com o response_schema.


3) Anthropic (Claude) — Tool Use com schema JSON

from anthropic import Anthropic
import json

client = Anthropic()

tool = {
    "name": "extract_event",
    "description": "Return event details.",
    "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ça o schema
    messages=[{"role": "user", "content":
        "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
)

# O Claude "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 genérico de “modo JSON”; em vez disso, o Tool Use com um input_schema lhe dá argumentos validados e no formato do schema (e você pode forçar seu uso).


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

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"}  # 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 da Mistral aplica a forma do JSON (não o seu schema exato) — valide no lado do cliente.


5) AWS Bedrock — schema de ferramenta da API Converse (agnóstico ao modelo)

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

# Extraia 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 o seu schema JSON e muitos modelos hospedados (por exemplo, Claude) suportam isso através do Converse.


Orientação Prática e Validação

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

Padrão de Validação (funciona para todos)

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:
    # tratar / nova tentativa / pedir ao modelo para corrigir com e.errors()
    print(e)

Subscrever

Receba novos artigos sobre sistemas, infraestrutura e engenharia de IA.