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 do suporte a saída estruturada (obter JSON confiável) entre os principais provedores de LLM, além de exemplos mínimos em Python

barras coloridas em pé

Já analisamos como solicitar saída estruturada do LLM hospedado no Ollama. Aqui, revisamos como solicitar o mesmo de outros provedores.

Matriz TL;DR

Provedor Modo “JSON” nativo Aplicação de Schema JSON Controle típico Observações
OpenAI Sim Sim (classe primeira) response_format={"type":"json_schema", ...} Funciona via API de Respostas ou Chat Completions; também pode usar chamadas de função.
Google Gemini Sim Sim (classe primeira) response_schema= + response_mime_type="application/json" Retorna JSON estritamente validado quando o schema é definido.
Anthropic (Claude) Indireto Sim (via Uso de Ferramentas com schema JSON) tools=[{input_schema=...}] + tool_choice Força o modelo a “chamar” sua ferramenta definida por 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 no lado do cliente.
AWS Bedrock (plataforma) Varia conforme o 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 grandes modelos de linguagem (LLMs) de gerar respostas que aderem estritamente a um formato ou estrutura pré-definido e específico, 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á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 geralmente geram texto de linguagem natural aberto e sem fim. Em vez disso, as saídas estruturadas impõem 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). 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 geralmente envolve técnicas como:

  • Especificar instruções de prompt detalhadas para orientar o modelo a produzir a 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.
  • Por vezes, impor restrições de decodificação com base em gramática ou máquinas de estados finitos para garantir conformidade no nível de token 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 Saída Estruturada em Python

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

1) OpenAI — JSON Schema (estrito)

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 Structured Outputs da OpenAI aplica este schema no lado do servidor.


2) Google Gemini — schema de resposta + MIME JSON

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á é JSON válido conforme o schema

O Gemini retornará JSON estrito que conforma ao response_schema.


3) Anthropic (Claude) — Uso de Ferramentas 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"},  # force schema
    messages=[{"role": "user", "content":
        "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}],
)

# 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 Uso de Ferramentas com um input_schema fornece argumentos validados com formato de 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 schema Pydantic/JSON localmente.

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


5) AWS Bedrock — API Converse Tool schema (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"}},  # force schema
    messages=[{"role":"user","content":[{"text":
        "Extract the event from: 'PyData Sydney is on 2025-11-03 at Darling Harbour.'"}]}],
)

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


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

  • Se você quer as garantias mais fortes no lado do servidor: Saídas estruturadas da OpenAI ou schema de resposta do Gemini.
  • Se você já usa Claude/Bedrock: defina uma Ferramenta com um schema JSON e force seu uso; leia os argumentos da ferramenta como seu objeto tipado.
  • Se você usa Mistral: ative 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:
    # lidar / recriar / pedir ao modelo para corrigir com e.errors()
    print(e)