siati.ai docs

API reference

JSON garantito e chiamata di funzioni

Imporre il formato della risposta invece di sperarci: response_format, json_schema e tools. Per chi estrae campi da documenti.

Last updated: 2026-08-16

Risposte in JSON e chiamata di funzioni

Se dovete estrarre campi da un documento e riversarli in un gestionale, questa è la pagina che vi serve. Non dovete scrivere un parser tollerante e non dovete sperare che il modello risponda nel formato giusto: lo si impone.

Entrambe le funzioni sono attive su tutti i modelli di conversazione del catalogo e seguono la stessa forma dell'interfaccia di OpenAI, quindi funzionano con le librerie che usate già.


JSON garantito

Con response_format il motore vincola la generazione: la risposta è JSON valido, non «di solito» JSON valido.

bash
curl https://api.siati.ai/v1/chat/completions \
  -H "Authorization: Bearer $SIATI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemma-4-26b",
    "messages": [{"role": "user", "content": "Estrai i campi da questa fattura: ..."}],
    "response_format": {"type": "json_object"}
  }'

Con uno schema, se volete anche i campi giusti

json_object garantisce che sia JSON. Se volete garantire quali chiavi ci sono e di che tipo, passate lo schema:

json
{
  "model": "gemma-4-26b",
  "messages": [{"role": "user", "content": "…"}],
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "fattura",
      "schema": {
        "type": "object",
        "properties": {
          "numero_documento": {"type": "string"},
          "data":             {"type": "string"},
          "totale":           {"type": "number"},
          "aliquota_iva":     {"type": "number"}
        },
        "required": ["numero_documento", "data", "totale"]
      }
    }
  }
}

Il modello non può produrre un documento che non rispetti lo schema. Le chiavi richieste ci sono sempre, e i tipi sono quelli dichiarati.


Chiamata di funzioni

Passate tools e il modello risponde con tool_calls invece che con del testo, esattamente come con l'interfaccia di OpenAI.

json
{
  "model": "gemma-4-26b",
  "messages": [{"role": "user", "content": "Registra la fattura 2026-114 da 1'250 franchi"}],
  "tools": [{
    "type": "function",
    "function": {
      "name": "registra_fattura",
      "description": "Crea una bozza di fattura fornitore",
      "parameters": {
        "type": "object",
        "properties": {
          "numero":  {"type": "string"},
          "importo": {"type": "number"}
        },
        "required": ["numero", "importo"]
      }
    }
  }]
}

La risposta contiene choices[0].message.tool_calls, con function.name e function.arguments come stringa JSON.


Fino a quando non funzionava

Dal 16 al 18 agosto 2026 il gateway non inoltrava response_format al motore: chi lo passava riceveva prosa libera, o un oggetto avvolto in un recinto markdown, e questa pagina prometteva il contrario. Corretto il 18 agosto. Se avete scritto una validazione a valle per aggirarlo, potete tenerla — non fa male — ma non vi serve più.

Con stream: true il difetto è durato due giorni in più: il formato veniva inoltrato sul percorso normale e non su quello a pezzi, quindi chi chiedeva JSON in streaming riceveva ancora prosa. Corretto anche quello il 18 agosto; adesso response_format vale su entrambe le strade.

Nello stesso giro è stato corretto tool_choice: "required", che rispondeva 502. La causa non era il valore: era che un "properties": {} nello schema arrivava al motore come [], e il motore rifiutava la grammatica.

Quello che non garantiamo, e va detto

I numeri restano da ricalcolare. Il modello legge bene, ma un totale letto non è un totale verificato: sommate le righe e confrontate. Vale per qualunque modello, non solo per i nostri, ed è il motivo per cui il risultato dovrebbe sempre finire in una bozza da confermare e mai direttamente a giornale.

Lo schema vincola la forma, non la verità. Se il campo data è richiesto, nella risposta c'è; che sia la data giusta lo dice il vostro controllo, non noi.

Gli enum dentro tools non sono vincolati. Nello schema di response_format sì; nei parametri di una funzione no, perché lì il vincolo non passa dalla grammatica. Il modello tende a rispondere con la parola italiana: "urgente" invece di "urgent". Due cose che funzionano, e ce le ha insegnate chi integra: mettere la mappatura nella description della proprietà («urgente/urgentissimo=urgent, alta=high») alza molto l'aderenza, e validare a valle resta necessario.

Il modello a volte scrive la stringa "null". Su un campo che ammette null, invece del valore JSON può arrivare la parola di quattro lettere. Chi integra dovrebbe trattare "null", "none", "nessuno" e la stringa vuota come assenza.

Su una fattura svizzera, leggete prima il codice QR. Se il documento ha la sezione di pagamento con il codice, IBAN, riferimento, importo e creditore si leggono in modo deterministico, senza modello e senza margine di errore. Usate il modello per quello che il codice non contiene: numero del documento, date, righe, aliquote. È l'ordine giusto, e vi costa meno.


Ricerca sui vostri documenti

La ricerca sull'archivio (caricate i documenti, fate una domanda, ottenete la risposta con il passaggio da cui viene) non è attiva in questo momento: l'archivio vettoriale non è in servizio. Se il vostro caso è l'estrazione di campi da fatture non vi serve — bastano le due funzioni qui sopra.

Se invece vi serve, scriveteci: è la richiesta che ne deciderebbe la priorità.