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

colorised bars standing

Já analisamos como solicitar saída estruturada do LLM hospedado no Ollama. Uma vez que o JSON está disponível na resposta, validação de saída estruturada de LLM em Python que é robusta percorre a análise, verificações do Pydantic, tentativas novamente 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 Parâmetro Típico Observações
OpenAI Sim Sim (nativo) 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 (nativo) response_schema= + response_mime_type="application/json" Retorna JSON estritamente validado quando o schema está definido.
Anthropic (Claude) Indireto Sim (via Uso de Ferramenta com schema JSON) tools=[{input_schema=...}] + tool_choice Força o modelo a “chamar” sua ferramenta definida por schema; gera 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 de Ferramenta/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 de grandes modelos de linguagem (LLMs) de gerar respostas que aderem estritamente a um formato ou estrutura predefinida, 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 tipicamente geram texto de linguagem natural aberto. 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). 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 geralmente envolve técnicas como:

  • Especificar instruções detalhadas no prompt 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.
  • Às vezes, impor restrições de decodificação baseadas 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.
  • Melhoria na 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 limitações potenciais 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 trechos extraem informações do 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": "AAAA-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": "Extraia o evento de: 'PyData Sydney é em 2025-11-03 no Darling Harbour.'"}
    ],
    response_format={"type": "json_schema", "json_schema": schema},
)

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

O recurso Structured Outputs do 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="sua-chave-de-api")

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="Extraia o evento de: 'PyData Sydney é em 2025-11-03 no 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 com response_schema.


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

from anthropic import Anthropic
import json

client = Anthropic()

tool = {
    "name": "extract_event",
    "description": "Retorna 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ça schema
    messages=[{"role": "user", "content":
        "Extraia o evento de: 'PyData Sydney é em 2025-11-03 no Darling Harbour.'"}],
)

# O Claude irá "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 Ferramenta 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":
        "Retorne JSON com chaves title, date (AAAA-MM-DD), location para: "
        "'PyData Sydney é em 2025-11-03 no 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 a estrutura JSON (nã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 schema
    messages=[{"role":"user","content":[{"text":
        "Extraia o evento de: 'PyData Sydney é em 2025-11-03 no 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ê deseja as garantias mais fortes no lado do servidor: Saídas estruturadas do 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 / tentar novamente / pedir ao modelo para corrigir com e.errors()
    print(e)

Assinar

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