Vai al contenuto
Output strutturati

Output strutturati

Richiedi la risposta come JSON: un qualsiasi oggetto JSON, oppure JSON conforme a uno schema che invii. Usalo quando a leggere la risposta è un programma, non una persona.

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)

Il JSON è il testo della risposta, 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}
  }
}

Le modalità di response_format

response_format è un campo di /v1/chat/completions. Senza di esso la risposta è un normale testo.

Modalità Valore Cosa ottieni
Oggetto JSON {"type": "json_object"} La risposta è JSON senza una forma prescritta. Indica nel prompt quali chiavi vuoi.
Schema JSON {"type": "json_schema", "json_schema": {"name": "…", "schema": {…}}} La risposta segue lo schema che invii: le sue chiavi, i tipi e i campi obbligatori.
Strict "strict": true Un campo di json_schema, non una terza modalità. È true a meno che tu non invii false.
Campo Tipo Default Descrizione Applicato da
type string json_object o json_schema. Obbligatorio dentro response_format. text è accettato e dà una normale risposta di testo. Ogni modello che accetta la modalità
json_schema.schema object Il JSON Schema che la risposta segue. Invialo ogni volta che type è json_schema. Ogni modello che accetta la modalità
json_schema.name string Un'etichetta per lo schema, come nel formato OpenAI. Modelli open-weight ospitati
json_schema.strict boolean true Indica se la risposta deve seguire esattamente lo schema. I modelli Shannon applicano ogni schema come strict. Modelli open-weight ospitati

La modalità oggetto JSON non richiede uno schema. Indica le chiavi nel prompt:

Corpo della richiesta
{
  "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"}
}

Supporto per modello

Modello json_object json_schema
Ogni modello Shannon (shannon-*) Sì Sì
Modelli open-weight ospitati, tranne quelli indicati qui sotto Sì Sì
Laguna-S-2.1-W4A16-AUTOROUND-REAP — —
inkling-W4A16-AUTOROUND-REAP Sì —

GET /v1/models riporta lo stesso per ogni id: capabilities.json_schema su ogni modello, e capabilities.response_format sui modelli open-weight ospitati. Modelli e prezzi

Parole chiave di schema supportate

Ciò che un modello riceve del tuo schema dipende dal modello e dall'endpoint:

Modelli /v1/chat/completions /v1/responses
Modelli Shannon Il sottoinsieme di parole chiave qui sotto, applicato come strict. Lo schema come lo invii, applicato come strict.
Modelli open-weight ospitati Lo schema come lo invii. strict è true a meno che tu non lo invii. Lo schema come lo invii. strict è true a meno che tu non lo invii.

Il sottoinsieme di parole chiave dei modelli Shannon su /v1/chat/completions:

Parola chiave Come viene letto
Parole chiave lette type, format, title, description, nullable, enum, items, properties, required, minItems, maxItems, minimum, maximum, minLength, maxLength, pattern, anyOf, default
$ref Risolto da $defs o definitions al livello superiore dello schema. Le parole chiave scritte accanto a $ref, come description, vengono mantenute. Un riferimento senza una definizione corrispondente viene letto come {"type": "object"}.
allOf I membri vengono fusi in un unico schema. Dove due membri impostano la stessa parola chiave, conta il successivo.
oneOf Letto come anyOf.
Schemi che si riferiscono a sé stessi Espansi fino a 24 livelli. Un livello più profondo viene letto come {"type": "object"}.
Fuori dal sottoinsieme Ogni altra parola chiave, per esempio additionalProperties, const, multipleOf, uniqueItems, exclusiveMinimum, exclusiveMaximum, patternProperties, prefixItems, minProperties, maxProperties, not e if / then / else. Non fanno parte dello schema che il modello riceve.

Su /v1/responses: text.format

/v1/responses scrive la stessa richiesta come text.format. Lo schema sta direttamente in format, accanto a name e strict, non sotto una chiave json_schema. Per la modalità oggetto JSON invia {"format": {"type": "json_object"}}.

Corpo della richiesta
{
  "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"]
      }
    }
  }
}

Il JSON è il text della parte output_text dell'elemento 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": []
        }
      ]
    }
  ]
}

Il supporto per modello e gli errori sono gli stessi di /v1/chat/completions. Responses API

Su /v1/messages: un tool come schema

Il formato Messages non ha un campo per l'output strutturato. Per ottenere JSON dagli stessi modelli, chiama /v1/chat/completions o /v1/responses con la stessa chiave.

Per restare su /v1/messages, descrivi l'oggetto come tool: metti il tuo schema in input_schema e indica il tool in tool_choice. L'input del blocco tool_use è allora il tuo oggetto, già analizzato. Un tool_choice indicato per nome viene applicato dai modelli open-weight ospitati.

Corpo della richiesta
{
  "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"}
    }
  ]
}

Verifica che stop_reason sia tool_use prima di leggere il blocco. Chiamata di funzioni

Come arriva il JSON

  • Il JSON è una stringa. La risposta non ha accanto un oggetto già analizzato: esegui il tuo parser JSON su message.content.
  • Con stream: true il JSON arriva a pezzi in delta.content. Uniscili e analizza una volta sola a stream terminato; un pezzo da solo non è JSON valido.
  • Un modello open-weight ospitato risponde a una richiesta con response_format senza testo di ragionamento: reasoning_content è null.

Controlla ciò che ricevi

Lo schema guida il modo in cui il modello scrive. L'API non confronta la risposta finita con il tuo schema, quindi il controllo finale spetta al tuo codice:

  • Esegui il parsing dentro un gestore di errori, come fa l'esempio in cima.
  • Convalida l'oggetto analizzato con lo stesso schema nel tuo codice, per esempio con una libreria JSON Schema, Pydantic o Zod.
  • Una risposta lunga può terminare prima che il JSON sia completo. Una risposta senza streaming riporta finish_reason solo come stop o tool_calls, quindi il segnale è un errore di parsing. Richiedi di nuovo, oppure chiedi un oggetto più piccolo.

Errori

Stato Tipo Messaggio Quando
400 invalid_request_error <id> does not accept response_format Il modello non accetta nessuna delle due modalità.
400 invalid_request_error <id> does not accept response_format json_schema; use json_object Il modello accetta json_object e hai inviato json_schema.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … response_format non ha type, oppure non è un oggetto JSON.

Le due risposte 400 vengono inviate prima che venga prelevato qualcosa dal tuo saldo. Gestione errori