Porównanie strukturalnego wyjścia wśród popularnych dostawców LLM – OpenAI, Gemini, Anthropic, Mistral i AWS Bedrock
Slightly different APIs require special approach. Slightly different APIs require special approach.
Oto porównanie wsparcia w formie obok siebie dla strukturalnego wyjścia (otrzymywanie niezawodnego JSON) wśród popularnych dostawców LLM, wraz z minimalnymi przykładami w Pythonie
Już wcześniej zajmowaliśmy się tematem, jak żądać strukturalnego wyjścia z LLM hostowanego na Ollama. Tu omówimy, jak żądać tego samego od innych dostawców.
TL;DR macierz
Dostawca | Natywne „tryb JSON” | Wymuszanie JSON Schema | Typowy pokrętło | Uwagi |
---|---|---|---|---|
OpenAI | Tak | Tak (pierwszorzędne) | response_format={"type":"json_schema", ...} |
Działa poprzez API odpowiedzi lub Chat Completions; można również wykonywać wywołania funkcji. |
Google Gemini | Tak | Tak (pierwszorzędne) | response_schema= + response_mime_type="application/json" |
Zwraca ściśle zweryfikowany JSON, gdy jest ustawiony schemat. |
Anthropic (Claude) | Pośrednie | Tak (poprzez Użycie Narzędzia z JSON schema) | tools=[{input_schema=...}] + tool_choice |
Wymuszanie modelu, aby „wywołał” narzędzie zdefiniowane przez schemat; daje argumenty zgodne ze schematem. |
Mistral | Tak | Częściowe (tylko JSON; brak schematu serwerowego) | response_format={"type":"json_object"} |
Zapewnia JSON, ale walidacja odbywa się po stronie klienta. |
AWS Bedrock (platforma) | Zależy od modelu | Tak (poprzez schemat Narzędzia/Converse) | toolConfig.tools[].toolSpec.inputSchema |
API Converse Bedrocka waliduje wejście narzędzia względem JSON schema. |
Strukturalne wyjście z LLM — Ogólne informacje
Strukturalne wyjście z LLM odnosi się do możliwości dużych modeli językowych (LLMs) generowania odpowiedzi, które ściśle przestrzegają określonego, zdefiniowanego wcześniej formatu lub struktury zamiast generowania wolnej formy tekstu. To strukturalne wyjście może być w formatach takich jak JSON, XML, tabele lub szablony, co sprawia, że dane są czytelne dla maszyn, spójne i łatwo parsowalne przez oprogramowanie do użycia w różnych aplikacjach.
Strukturalne wyjścia różnią się od tradycyjnych wyjść LLM, które zwykle generują otwarte, naturalne teksty. Zamiast tego, strukturalne wyjścia wymuszają schemat lub format, taki jak obiekty JSON z zdefiniowanymi kluczami i typami wartości, lub konkretne klasy w wyjściu (np. odpowiedzi wielokrotnego wyboru, klasy sentymentu lub formaty wierszy bazy danych). Ten podejście poprawia niezawodność, zmniejsza błędy i halucynacje oraz ułatwia integrację do systemów takich jak bazy danych, API lub przepływów pracy.
Generowanie strukturalnych wyjść w LLM często obejmuje techniki takie jak:
- Określanie szczegółowych instrukcji w promptach, aby kierować modelem do generowania wyjścia w pożądanym formacie.
- Użycie narzędzi walidacji i parsowania, takich jak Pydantic w Pythonie, aby upewnić się, że wyjście odpowiada schematowi.
- Czasami wymuszanie ograniczeń dekodowania opartych na gramatyce lub maszynach stanów skończonych, aby zapewnić zgodność na poziomie tokenów z formatem.
Zalety strukturalnych wyjść LLM obejmują:
- Czytelność dla maszyn i łatwość integracji.
- Zmniejszenie zmienności i błędów.
- Poprawna przewidywalność i weryfikowalność dla zadań wymagających spójnych formatów danych.
Wyzwania obejmują projektowanie skutecznych schematów, obsługa złożonych danych zagnieżdżonych oraz potencjalne ograniczenia w możliwościach rozumowania w porównaniu do generowania wolnej formy tekstu.
Wszystkim razem, strukturalne wyjście umożliwia LLM, aby były bardziej przydatne w aplikacjach wymagających precyzyjnych, sformatowanych danych, a nie tylko tekstu czytelnego dla człowieka.
Przykłady strukturalnego wyjścia w Pythonie
Wszystkie fragmenty kodu wyodrębniają zdarzenie jako JSON: {title, date, location}
. Można zmieniać klucze/modeli według własnego uznania.
1) OpenAI — JSON Schema (ś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": "Wyodrębnij zdarzenie z: 'PyData Sydney odbędzie się 2025-11-03 w Darling Harbour.'"}
],
response_format={"type": "json_schema", "json_schema": schema},
)
data = json.loads(resp.choices[0].message.content)
print(data)
Funkcja Strukturalnych Wyjść w OpenAI wymusza ten schemat po stronie serwera.
2) Google Gemini — schemat odpowiedzi + MIME JSON
import google.generativeai as genai
from google.genai import types
# Skonfiguruj z własnym kluczem 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="Wyodrębnij zdarzenie z: 'PyData Sydney odbędzie się 2025-11-03 w Darling Harbour.'",
generation_config=genai.GenerationConfig(
response_mime_type="application/json",
response_schema=schema,
),
)
print(resp.text) # już poprawny JSON zgodny ze schematem
Gemini zwróci ściśle określony JSON, który będzie zgodny z response_schema
.
3) Anthropic (Claude) — Użycie Narzędzia z JSON schema
from anthropic import Anthropic
import json
client = Anthropic()
tool = {
"name": "extract_event",
"description": "Zwróć szczegóły zdarzenia.",
"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"}, # wymuszanie schematu
messages=[{"role": "user", "content":
"Wyodrębnij zdarzenie z: 'PyData Sydney odbędzie się 2025-11-03 w Darling Harbour.'"}],
)
# Claude „wywoła” narzędzie; pobierz argumenty (które odpowiadają Twojemu schematowi)
tool_use = next(b for b in msg.content if b.type == "tool_use")
print(json.dumps(tool_use.input, indent=2))
Claude nie ma ogólnego przełącznika „tryb JSON”; zamiast tego Użycie Narzędzia z input_schema
daje Ci zweryfikowane, zgodne ze schematem argumenty (i 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":
"Zwróć JSON z kluczami title, date (YYYY-MM-DD), location dla: "
"'PyData Sydney odbędzie się 2025-11-03 w Darling Harbour.'"}],
response_format={"type": "json_object"} # gwarantuje poprawny JSON
)
data = json.loads(resp.choices[0].message.content)
print(data)
# Wskazówka: waliduj `data` lokalnie względem swojego schematu Pydantic/JSON.
Tryb json_object
w Mistralu wymusza kształt JSON (nie konkretny schemat) — walidacja odbywa się po stronie klienta.
5) AWS Bedrock — API Converse Schemat Narzędzia (model-agnostyczny)
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"}}, # wymuszanie schematu
messages=[{"role":"user","content":[{"text":
"Wyodrębnij zdarzenie z: 'PyData Sydney odbędzie się 2025-11-03 w Darling Harbour.'"}]}],
)
# Pobierz zawartość 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))
Bedrock waliduje wejście narzędzia względem Twojego JSON schema i wiele hostowanych modeli (np. Claude) obsługuje to poprzez Converse.
Praktyczne wskazówki i walidacja
- Jeśli chcesz najsilniejszych gwarancji po stronie serwera: strukturalne wyjścia z OpenAI lub schemat odpowiedzi w Gemini.
- Jeśli korzystasz już z Claude/Bedrock: zdefiniuj Narzędzie z JSON schema i wymuś jego użycie; odczytaj argumenty narzędzia jako swój obiekt typu.
- Jeśli korzystasz z Mistrala: włącz
json_object
i waliduj lokalnie (np. z użyciem 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` z dowolnego dostawcy
except ValidationError as e:
# obsłuż / ponów próbę / poproś model, aby naprawił z 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ć strukturalnego wyjścia z LLM hostowanego na Ollama
- Python Cheat sheet
- AWS SAM + AWS SQS + Python PowerTools
- Porównanie wydajności AWS Lambda: JavaScript vs Python vs Golang