Naar de inhoud
Gestructureerde outputs

Gestructureerde outputs

Vraag het antwoord als JSON: een willekeurig JSON-object, of JSON die een schema volgt dat je meestuurt. Gebruik het wanneer een programma, geen mens, het antwoord leest.

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)

De JSON is de tekst van het antwoord, in 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}
  }
}

De modi van response_format

response_format is een veld van /v1/chat/completions. Zonder dit veld is het antwoord gewone tekst.

Modus Waarde Wat je krijgt
JSON-object {"type": "json_object"} Het antwoord is JSON zonder voorgeschreven vorm. Zeg in de prompt welke sleutels je wilt.
JSON-schema {"type": "json_schema", "json_schema": {"name": "…", "schema": {…}}} Het antwoord volgt het schema dat je meestuurt: zijn sleutels, typen en verplichte velden.
Strict "strict": true Een veld van json_schema, geen derde modus. Het is true tenzij je false meestuurt.
Veld Type Standaard Beschrijving Toegepast door
type string json_object of json_schema. Vereist binnen response_format. text wordt geaccepteerd en geeft een gewoon tekstantwoord. Elk model dat de modus accepteert
json_schema.schema object Het JSON Schema dat het antwoord volgt. Stuur het mee zodra type json_schema is. Elk model dat de modus accepteert
json_schema.name string Een label voor het schema, zoals in het OpenAI-formaat. Gehoste open-weight modellen
json_schema.strict boolean true Of het antwoord het schema exact moet volgen. De Shannon-modellen passen elk schema als strict toe. Gehoste open-weight modellen

De JSON-objectmodus heeft geen schema nodig. Noem de sleutels in de prompt:

Aanvraagbody
{
  "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"}
}

Ondersteuning per model

Model json_object json_schema
Elk Shannon-model (shannon-*) Ja Ja
Gehoste open-weight modellen, behalve de hieronder genoemde Ja Ja
Laguna-S-2.1-W4A16-AUTOROUND-REAP — —
inkling-W4A16-AUTOROUND-REAP Ja —

GET /v1/models meldt hetzelfde per id: capabilities.json_schema bij elk model, en capabilities.response_format bij de gehoste open-weight modellen. Modellen en prijzen

Ondersteunde schematrefwoorden

Wat een model van je schema ontvangt, hangt af van het model en van het endpoint:

Modellen /v1/chat/completions /v1/responses
Shannon-modellen De subset trefwoorden hieronder, als strict toegepast. Het schema zoals je het stuurt, als strict toegepast.
Gehoste open-weight modellen Het schema zoals je het stuurt. strict is true tenzij je het meestuurt. Het schema zoals je het stuurt. strict is true tenzij je het meestuurt.

De subset trefwoorden van de Shannon-modellen op /v1/chat/completions:

Trefwoord Hoe het wordt gelezen
Gelezen trefwoorden type, format, title, description, nullable, enum, items, properties, required, minItems, maxItems, minimum, maximum, minLength, maxLength, pattern, anyOf, default
$ref Opgelost vanuit $defs of definitions op het hoogste niveau van het schema. Trefwoorden die naast de $ref staan, zoals description, blijven behouden. Een verwijzing zonder bijbehorende definitie wordt gelezen als {"type": "object"}.
allOf De leden worden samengevoegd tot één schema. Waar twee leden hetzelfde trefwoord instellen, telt het latere.
oneOf Gelezen als anyOf.
Schema's die naar zichzelf verwijzen Uitgebreid tot 24 niveaus. Een dieper niveau wordt gelezen als {"type": "object"}.
Buiten de subset Elk ander trefwoord, bijvoorbeeld additionalProperties, const, multipleOf, uniqueItems, exclusiveMinimum, exclusiveMaximum, patternProperties, prefixItems, minProperties, maxProperties, not en if / then / else. Deze maken geen deel uit van het schema dat het model ontvangt.

Op /v1/responses: text.format

/v1/responses schrijft dezelfde aanvraag als text.format. Het schema staat direct in format, naast name en strict, niet onder een json_schema-sleutel. Voor de JSON-objectmodus stuur je {"format": {"type": "json_object"}}.

Aanvraagbody
{
  "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"]
      }
    }
  }
}

De JSON is de text van het output_text-deel van het message-item:

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": []
        }
      ]
    }
  ]
}

De ondersteuning per model en de fouten zijn dezelfde als op /v1/chat/completions. Responses API

Op /v1/messages: een tool als schema

Het Messages-formaat heeft geen veld voor gestructureerde output. Voor JSON van dezelfde modellen roep je /v1/chat/completions of /v1/responses aan met dezelfde sleutel.

Om op /v1/messages te blijven, beschrijf je het object als tool: zet je schema in input_schema en noem de tool in tool_choice. De input van het tool_use-blok is dan je object, al geparseerd. Een benoemde tool_choice wordt toegepast door de gehoste open-weight modellen.

Aanvraagbody
{
  "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"}
    }
  ]
}

Controleer of stop_reason tool_use is voordat je het blok leest. Function calling

Hoe de JSON binnenkomt

  • De JSON is een string. Het antwoord bevat er geen geparseerd object naast: laat je JSON-parser los op message.content.
  • Met stream: true komt de JSON binnen in stukjes van delta.content. Voeg ze samen en parse pas als de stream is geëindigd; een los stukje is geen geldige JSON.
  • Een gehost open-weight model beantwoordt een response_format-aanvraag zonder redeneertekst: reasoning_content is null.

Controleer wat je ontvangt

Het schema stuurt hoe het model schrijft. De API vergelijkt het voltooide antwoord niet met je schema, dus je code doet de eindcontrole:

  • Parse binnen een foutafhandelaar, zoals het voorbeeld bovenaan doet.
  • Valideer het geparseerde object in je eigen code met hetzelfde schema, bijvoorbeeld met een JSON Schema-bibliotheek, Pydantic of Zod.
  • Een lang antwoord kan eindigen voordat de JSON compleet is. Een antwoord zonder streaming meldt finish_reason alleen als stop of tool_calls, dus een parsefout is het signaal. Vraag opnieuw, of vraag om een kleiner object.

Fouten

Status Type Melding Wanneer
400 invalid_request_error <id> does not accept response_format Het model accepteert geen van beide modi.
400 invalid_request_error <id> does not accept response_format json_schema; use json_object Het model accepteert json_object en jij hebt json_schema gestuurd.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … response_format heeft geen type, of is geen JSON-object.

De twee 400-antwoorden worden verstuurd voordat er iets van je saldo wordt afgeschreven. Foutafhandeling