Porównanie strukturalnych wyjść u popularnych dostawców LLM – OpenAI, Gemini, Anthropic, Mistral i AWS Bedrock
Lekko różne API wymagają specjalnego podejścia.
Oto porównanie wsparcia dla ustrukturyzowanego wyjścia (podejmowanie wiarygodnego JSON z powrotem) między popularnymi dostawcami LLM, oraz minimalistyczne przykłady w Pythonie

Już wcześniej sprawdziliśmy, jak żądać ustrukturyzowanego wyjścia od LLM hostowanego na Ollama. Gdy JSON wróci w sieci, walidacja ustrukturyzowanego wyjścia LLM w Pythonie, która się sprawdza omawia parsowanie, sprawdzenia Pydantic, ponowne próby i testy w Twojej usłudze. Tutaj sprawdzamy, jak żądać tego samego od innych dostawców.
Macierz TL;DR
| Dostawca | Natywny „tryb JSON” | Egzekucja Schematu JSON | Typowy parametr | Uwagi |
|---|---|---|---|---|
| OpenAI | Tak | Tak (pierwszoklasowy) | response_format={"type":"json_schema", ...} |
Działa przez Responses API lub Chat Completions; może również wykonywać wywoływanie funkcji. |
| Google Gemini | Tak | Tak (pierwszoklasowy) | response_schema= + response_mime_type="application/json" |
Zwraca ściśle zwalidowany JSON, gdy schemat jest ustawiony. |
| Anthropic (Claude) | Pośrednio | Tak (przez Tool Use ze schematem JSON) | tools=[{input_schema=...}] + tool_choice |
Wymuś model na „wołanie” Twojego narzędzia zdefiniowanego schematem; zwraca argumenty w kształcie schematu. |
| Mistral | Tak | Częściowo (tylko JSON; brak schematu po stronie serwera) | response_format={"type":"json_object"} |
Gwarantuje JSON, ale walidujesz w swoim schemacie po stronie klienta. |
| AWS Bedrock (platforma) | Zależy od modelu | Tak (przez Tool/Converse schema) | toolConfig.tools[].toolSpec.inputSchema |
API Converse w Bedrocku waliduje wejście narzędzia względem schematu JSON. |
LLM Ustrukturyzowane Wyjście - Informacje ogólne
Ustrukturyzowane wyjście LLM odnosi się do zdolności dużych modeli językowych (LLM) do generowania odpowiedzi, które ściśle adhere do zdefiniowanego z góry, konkretnego formatu lub struktury, zamiast generowania tekstu wolnego. To ustrukturyzowane wyjście może mieć formę JSON, XML, tabel lub szablonów, co czyni dane maszynowo czytanymi, spójnymi i łatwymi do sparsowania przez oprogramowanie do użytku w różnych aplikacjach.
Ustrukturyzowane wyjścia różnią się od tradycyjnych wyjść LLM, które typowo generują otwarty, naturalny tekst językowy. Zamiast tego, ustrukturyzowane wyjścia egzekwują schemat lub format, taki jak obiekty JSON z zdefiniowanymi kluczami i typami wartości, lub konkretne klasy w wyjściu (np. odpowiedzi testowe z wielokrotnym wyborem, klasy sentymentu lub formaty wierszy bazy danych). To podejście poprawia wiarygodność, redukuje błędy i halucynacje oraz upraszcza integrację z systemami takimi jak bazy danych, API lub przepływy pracy.
Generowanie ustrukturyzowanych wyjść w LLM często obejmuje techniki takie jak:
- Określanie szczegółowych instrukcji w promptach, aby skierować model do wygenerowania wyjścia w pożądanym formacie.
- Używanie narzędzi do walidacji i parsowania, takich jak Pydantic w Pythonie, aby upewnić się, że wyjście pasuje do schematu.
- Czasami egzekwowanie ograniczeń dekodowania opartych na gramatyce lub maszynach stanów skończonych, aby zapewnić zgodność tokenów z formatem.
Korzyści z ustrukturyzowanych wyjść LLM obejmują:
- Maszynową czytelność i łatwość integracji.
- Zmniejszoną zmienność i błędy.
- Poprawioną przewidywalność i weryfikowalność dla zadań wymagających spójnych formatów danych.
Wyzwania obejmują projektowanie efektywnych schematów, obsługę złożonych, zagnieżdżonych danych oraz potencjalne ograniczenia w zdolnościach rozumowania w porównaniu z generowaniem swobodnego tekstu.
Ogólnie rzecz biorąc, ustrukturyzowane wyjście pozwala LLMom być bardziej użytecznymi w aplikacjach wymagających precyzyjnych, sformatowanych danych, a nie tylko tekstu czytelnego dla człowieka.
Przykłady Ustrukturyzowanego Wyjścia w Pythonie
Wszystkie fragmenty kodu wyodrębniają informacje o wydarzeniu jako JSON: {title, date, location}. Zamieniaj klucze/modeli według uznania.
1) OpenAI — Schemat JSON (ściśle)
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)
Funkcja Structured Outputs firmy OpenAI egzekwuje ten schemat po stronie serwera.
2) Google Gemini — schemat odpowiedzi + 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) # already valid JSON per schema
Gemini zwróci ściśle JSON, który odpowiada response_schema.
3) Anthropic (Claude) — Użycie narzędzi (Tool Use) ze schematem 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 will "call" the tool; grab the args (which match your schema)
tool_use = next(b for b in msg.content if b.type == "tool_use")
print(json.dumps(tool_use.input, indent=2))
Claude nie posiada ogólnego przełącznika „trybu JSON”; zamiast tego Tool Use z input_schema daje Ci zwalidowane, w kształcie schematu argumenty (a Ty możesz wymusić jego użycie).
4) Mistral — Tryb JSON (walidacja po stronie klienta)
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"} # guarantees valid JSON
)
data = json.loads(resp.choices[0].message.content)
print(data)
# Tip: validate `data` against your Pydantic/JSON Schema locally.
json_object Mistrala egzekwuje kształt JSON (nie dokładny Twój schemat) — waliduj po stronie klienta.
5) AWS Bedrock — Schemat narzędzi API Converse (niezależny od modelu)
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.'"}]}],
)
# Pull toolUse content
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 waliduje wejście narzędzia względem Twojego schematu JSON, a wiele hostowanych modeli (np. Claude) wspiera to przez Converse.
Praktyczne wskazówki i Walidacja
- Jeśli chcesz najsilniejszych gwarancji po stronie serwera: ustrukturyzowane wyjścia OpenAI lub schemat odpowiedzi Gemini.
- Jeśli już korzystasz z Claude/Bedrock: zdefiniuj Tool ze schematem JSON i wymuś jego użycie; odczytaj argumenty narzędzia jako swój obiekt typowany.
- Jeśli używasz Mistral: włącz
json_objecti waliduj lokalnie (np. z Pydantic).
Wzorzec walidacji (działa dla wszystkich)
from pydantic import BaseModel, ValidationError
class Event(BaseModel):
title: str
date: str
location: str
try:
event = Event.model_validate(data) # `data` from any provider
except ValidationError as e:
# handle / retry / ask model to fix with e.errors()
print(e)
Przydatne linki
- https://platform.openai.com/docs/guides/structured-outputs
- https://ai.google.dev/gemini-api/docs/structured-output
- https://docs.mistral.ai/capabilities/structured-output/json_mode/
- https://aws.amazon.com/blogs/machine-learning/structured-data-response-with-amazon-bedrock-prompt-engineering-and-tool-use
- https://github.com/aws-samples/anthropic-on-aws/blob/main/complex-schema-tool-use/README.md
- https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages.html
- Jak żądać Ustrukturyzowanego Wyjścia od LLM hostowanego na Ollama
- Ściągawka Pythona