Przejdź do treści
Ustrukturyzowane odpowiedzi

Ustrukturyzowane odpowiedzi

Poproś o odpowiedź jako JSON: dowolny obiekt JSON albo JSON zgodny ze schematem, który wyślesz. Używaj tego, gdy odpowiedź czyta program, a nie człowiek.

POST https://api.shannon-ai.com/v1/chat/completions

import json
from openai import OpenAI

client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.shannon-ai.com/v1")

response = client.chat.completions.create(
    model="Kimi-K3-3BIT-REAP",
    messages=[
        {"role": "user", "content": "Extract the person: John Doe, 30 years old, engineer."}
    ],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "person",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "age": {"type": "integer"},
                    "occupation": {"type": "string"},
                },
                "required": ["name", "age", "occupation"],
            },
        },
    },
)

# The JSON arrives as text in message.content: parse it, then check it.
try:
    person = json.loads(response.choices[0].message.content)
except json.JSONDecodeError:
    person = None  # ask again, or report the failure

print(person)

JSON to tekst odpowiedzi, w choices[0].message.content:

200 JSON
{
  "id": "chatcmpl-0c4e7a1b9d2f4e6a8b3c5d7e9f1a2b3c",
  "object": "chat.completion",
  "created": 1791590400,
  "model": "Kimi-K3-3BIT-REAP",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "{\"name\":\"John Doe\",\"age\":30,\"occupation\":\"engineer\"}",
        "reasoning_content": null
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 96,
    "completion_tokens": 19,
    "total_tokens": 115,
    "prompt_tokens_details": {"cached_tokens": 0},
    "completion_tokens_details": {"reasoning_tokens": 0}
  }
}

Tryby response_format

response_format to pole /v1/chat/completions. Bez niego odpowiedź jest zwykłym tekstem.

Tryb Wartość Co dostajesz
Obiekt JSON {"type": "json_object"} Odpowiedź to JSON bez narzuconego kształtu. Napisz w prompcie, jakich kluczy chcesz.
Schemat JSON {"type": "json_schema", "json_schema": {"name": "…", "schema": {…}}} Odpowiedź trzyma się wysłanego schematu: jego kluczy, typów i wymaganych pól.
Strict "strict": true Pole json_schema, a nie trzeci tryb. Ma wartość true, chyba że wyślesz false.
Pole Typ Domyślnie Opis Stosowane przez
type string json_object lub json_schema. Wymagane wewnątrz response_format. text jest akceptowane i daje zwykłą odpowiedź tekstową. Każdy model, który przyjmuje ten tryb
json_schema.schema object JSON Schema, którego trzyma się odpowiedź. Wyślij go zawsze, gdy type to json_schema. Każdy model, który przyjmuje ten tryb
json_schema.name string Etykieta schematu, jak w formacie OpenAI. Hostowane modele open-weight
json_schema.strict boolean true Czy odpowiedź musi dokładnie trzymać się schematu. Modele Shannon stosują każdy schemat jako strict. Hostowane modele open-weight

Tryb obiektu JSON nie potrzebuje schematu. Nazwij klucze w prompcie:

Treść zapytania
{
  "model": "shannon-3",
  "messages": [
    {
      "role": "user",
      "content": "Name the capital of France. Answer as JSON with the keys city and country."
    }
  ],
  "response_format": {"type": "json_object"}
}

Obsługa według modelu

Model json_object json_schema
Każdy model Shannon (shannon-*) Tak Tak
Hostowane modele open-weight, z wyjątkiem wymienionych niżej Tak Tak
Laguna-S-2.1-W4A16-AUTOROUND-REAP — —
inkling-W4A16-AUTOROUND-REAP Tak —

GET /v1/models zgłasza to samo dla każdego id: capabilities.json_schema w każdym modelu oraz capabilities.response_format w hostowanych modelach open-weight. Modele i ceny

Obsługiwane słowa kluczowe schematu

To, co model dostaje z Twojego schematu, zależy od modelu i od endpointu:

Modele /v1/chat/completions /v1/responses
Modele Shannon Podzbiór słów kluczowych poniżej, stosowany jako strict. Schemat tak, jak go wysyłasz, stosowany jako strict.
Hostowane modele open-weight Schemat tak, jak go wysyłasz. strict to true, chyba że go wyślesz. Schemat tak, jak go wysyłasz. strict to true, chyba że go wyślesz.

Podzbiór słów kluczowych modeli Shannon w /v1/chat/completions:

Słowo kluczowe Jak jest czytane
Czytane słowa kluczowe type, format, title, description, nullable, enum, items, properties, required, minItems, maxItems, minimum, maximum, minLength, maxLength, pattern, anyOf, default
$ref Rozwiązywane z $defs lub definitions na najwyższym poziomie schematu. Słowa kluczowe zapisane obok $ref, takie jak description, są zachowane. Odwołanie bez pasującej definicji jest czytane jako {"type": "object"}.
allOf Człony są scalane w jeden schemat. Gdy dwa człony ustawiają to samo słowo kluczowe, liczy się późniejszy.
oneOf Czytane jako anyOf.
Schematy odwołujące się do siebie Rozwijane do 24 poziomów. Głębszy poziom jest czytany jako {"type": "object"}.
Poza podzbiorem Każde inne słowo kluczowe, na przykład additionalProperties, const, multipleOf, uniqueItems, exclusiveMinimum, exclusiveMaximum, patternProperties, prefixItems, minProperties, maxProperties, not i if / then / else. Nie wchodzą w skład schematu, który dostaje model.

W /v1/responses: text.format

/v1/responses zapisuje to samo zapytanie jako text.format. Schemat leży bezpośrednio w format, obok name i strict, a nie pod kluczem json_schema. Dla trybu obiektu JSON wyślij {"format": {"type": "json_object"}}.

Treść zapytania
{
  "model": "Kimi-K3-3BIT-REAP",
  "input": "Extract the person: John Doe, 30 years old, engineer.",
  "text": {
    "format": {
      "type": "json_schema",
      "name": "person",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "name": {"type": "string"},
          "age": {"type": "integer"},
          "occupation": {"type": "string"}
        },
        "required": ["name", "age", "occupation"]
      }
    }
  }
}

JSON to text części output_text elementu message:

200 JSON
{
  "output": [
    {
      "id": "msg_7e1d3c5b9a2f4d6e8c0b1a3f5e7d9c2b",
      "type": "message",
      "role": "assistant",
      "status": "completed",
      "content": [
        {
          "type": "output_text",
          "text": "{\"name\":\"John Doe\",\"age\":30,\"occupation\":\"engineer\"}",
          "annotations": []
        }
      ]
    }
  ]
}

Obsługa według modelu i błędy są takie same jak w /v1/chat/completions. Responses API

W /v1/messages: narzędzie jako schemat

Format Messages nie ma pola ustrukturyzowanego wyjścia. Aby dostać JSON z tych samych modeli, wywołaj /v1/chat/completions lub /v1/responses tym samym kluczem.

Aby zostać w /v1/messages, opisz obiekt jako narzędzie: umieść swój schemat w input_schema i nazwij narzędzie w tool_choice. input bloku tool_use jest wtedy Twoim obiektem, już sparsowanym. Nazwany tool_choice stosują hostowane modele open-weight.

Treść zapytania
{
  "model": "Kimi-K3-3BIT-REAP",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": "Extract the person: John Doe, 30 years old, engineer."
    }
  ],
  "tools": [
    {
      "name": "record_person",
      "description": "Record the extracted person.",
      "input_schema": {
        "type": "object",
        "properties": {
          "name": {"type": "string"},
          "age": {"type": "integer"},
          "occupation": {"type": "string"}
        },
        "required": ["name", "age", "occupation"]
      }
    }
  ],
  "tool_choice": {"type": "tool", "name": "record_person"}
}
200 JSON
{
  "stop_reason": "tool_use",
  "content": [
    {
      "type": "tool_use",
      "id": "toolu_4b8d2f6a1c3e4a5b9d7f0e2c4a6b8d1f",
      "name": "record_person",
      "input": {"name": "John Doe", "age": 30, "occupation": "engineer"}
    }
  ]
}

Sprawdź, czy stop_reason to tool_use, zanim przeczytasz blok. Wywołanie funkcji

Jak przychodzi JSON

  • JSON jest ciągiem znaków. Odpowiedź nie ma obok siebie sparsowanego obiektu: uruchom swój parser JSON na message.content.
  • Z stream: true JSON przychodzi w kawałkach delta.content. Połącz je i sparsuj po zakończeniu streamu; pojedynczy kawałek nie jest poprawnym JSON.
  • Hostowany model open-weight odpowiada na zapytanie z response_format bez tekstu wnioskowania: reasoning_content to null.

Sprawdź to, co otrzymujesz

Schemat kieruje tym, jak model pisze. API nie porównuje gotowej odpowiedzi z Twoim schematem, więc ostateczną kontrolę robi Twój kod:

  • Parsuj wewnątrz obsługi błędów, jak w przykładzie na górze.
  • Zwaliduj sparsowany obiekt tym samym schematem we własnym kodzie, na przykład biblioteką JSON Schema, Pydantic lub Zod.
  • Długa odpowiedź może się skończyć, zanim JSON będzie kompletny. Odpowiedź bez streamingu zgłasza finish_reason tylko jako stop lub tool_calls, więc sygnałem jest błąd parsowania. Zapytaj ponownie albo poproś o mniejszy obiekt.

Błędy

Status Typ Komunikat Kiedy
400 invalid_request_error <id> does not accept response_format Model nie przyjmuje żadnego z tych trybów.
400 invalid_request_error <id> does not accept response_format json_schema; use json_object Model przyjmuje json_object, a wysłano json_schema.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … response_format nie ma type albo nie jest obiektem JSON.

Obie odpowiedzi 400 są wysyłane, zanim cokolwiek zostanie pobrane z Twojego salda. Obsługa błędów