Come funziona

Il modello propone.
SQAI dispone.

Un agente non scrive mai SQL e non emette mai codice da eseguire. Scrive una richiesta tipizzata — e ogni richiesta percorre la stessa linea: validata contro un contratto fissato, verificata rispetto alla tua policy, eseguita su un motore deterministico, restituita con gli hash che la riproducono.

Ogni richiesta — ask(), compute(), o una tool call dell'AI SDK — percorre la stessa linea. Nulla raggiunge il motore finché ogni controllo non è superato.

01Intento tipizzato

Una richiesta che il motore può analizzare. Non una stringa di cui fidarsi.

Il modello emette un oggetto tipizzato — mai SQL, mai codice. Un intento di query è un QuerySpec: una metrica da aggregare su una sorgente nominata. Un intento di calcolo è un ComputationSpec: una funzione nominata dal contratto, con argomenti e binding. Un'unione discriminata, due forme — e in nessuna delle due c'è spazio per nascondere una stringa eseguibile.

Questa è l'intera superficie di authoring. Ciò che la forma non può esprimere, il modello non può richiedere.

QuerySpecanatomia
{
"kind": "query",il tag dell'unione — query o computation
"version": "1",la versione dello spec, fissata
"source_name": "sales",una sorgente connessa, per nome esatto
"metric": "revenue",la colonna da aggregare
"aggregation": "sum",uno tra sum · avg · count · min · max
"group_by": "region"opzionale — suddivide il risultato per un campo
}

anch'esso opzionalefilter · limit · order

la forma computationmodule · function · args · kwargs · bindings · seed?

02Verifica contratto

Un contratto, hash fissato. L'ignoto viene rifiutato con indicazioni.

Lo spec viene validato contro il contratto di capability — un file generato e hash-fissato che elenca ogni operazione, la sua firma esatta e i suoi flag di determinismo. Una capability è raggiungibile solo se è in sola lettura e deterministica, o deterministica se inizializzata con un seed. Le operazioni con scrittura e non deterministiche non vengono bloccate a runtime; non sono mai state generate nella superficie.

Una funzione sconosciuta fallisce come unsupported_operation e risponde con nearest_matches dallo stesso indice — il modello si corregge invece di ciclare.

Contratto di capability

contract_hashsha256:79f1c5a6c7164e7e9e1750e70a5c03292fa87eb52d8148a740c06695924be9a1

4,778
operazioni elencate nel contratto
4,574
esposte agli SDK, sola lettura
4,564
completamente deterministiche
10
simulazioni con seed obbligatorio
204
escluse dalla superficie

idoneitàread_only && (deterministic || deterministic_when_seeded)

su un nome sconosciutounsupported_operation + nearest_matches

03Verifica policy

La tua allow-list decide se — e come — viene eseguito.

La policy viene fissata quando createSQAI() costruisce l'istanza e applicata in-process prima di qualsiasi esecuzione — sulla sorgente, su ogni metrica, raggruppamento, filtro e colonna vincolata, e sul nome della funzione. Può solo restringere il contratto: nominare una capability al di fuori della superficie idonea genera comunque unsupported_operation.

L'input dello strumento del modello non contiene alcun campo allowed*. Nulla nella richiesta può ampliare l'accesso — quindi non c'è nulla che un prompt injection possa allargare.

allowedSourcessorgenti che il modello può nominare

  • "sales"

allowedFieldscolonne che può leggere, per sorgente

  • sales.region
  • sales.revenue
  • sales.order_date

allowedFunctionsil default — ogni capability in sola lettura, niente di più

  • "all-readonly"

un rifiuto è preciso, attribuito, definitivo

  • policy_denied_source
  • policy_denied_field
  • policy_denied_function

source: "sqai" · non ripetibile

04Motore deterministico

Fissato prima dell'esecuzione: float64, un thread, un runtime.

Prima si risolvono i binding. Il modello ha nominato una sorgente e un campo; SQAI recupera i valori effettivi tramite la primitiva extractColumns del motore, allineata per riga, con i null gestiti a coppie. SQAI non concatena mai array autonomamente — così l'input che viene sottoposto a hash è esattamente l'input che è stato eseguito.

Solo ora la richiesta raggiunge il motore. Il runtime è firmato, versionato e fissato: precisione float64, un singolo thread. Il primo compute() lo inizializza una volta sola, in circa 110 secondi; dopodiché rimane residente — finance.npv misura 0,83–0,93 ms a caldo.

envelope di determinismo
runtime_bundle_version0.1.0
runtime_bundle_sha2564d64142e4c1ff63d299cfc8b172fdf97cb59169b545e1e02978e678a632ce6e1
platformdarwin
architecturearm64
precision_modefloat64
thread_count1
seed
input_hash2ea5ede72acd2912fe9e1230cef34afad4c9436bfa8a709bac2da02b478e3212

Registrato con ogni risultato — l'envelope dichiara l'ambito della garanzia invece di sovrastimarla.

05Risposta + provenienza

Due hash. Uno prima, uno dopo.

invocation_hash viene apposto prima dell'esecuzione — sul modulo, la funzione, gli argomenti, i binding risolti, il seed, il contratto e lo scope. computation_hash viene apposto dopo: l'invocation hash combinato con il risultato canonico. Riprodurre significa rieseguirlo e confrontare i byte.

Entrambi gli SDK condividono un unico serializzatore canonico, così lo stesso calcolo produce hash byte-identici in TypeScript e Python. Le risposte alle query seguono la stessa disciplina: un plan_hash sul piano risolto canonico, più il percorso decisionale e lo scope esatto in cui è stato eseguito.

3188.1687606249325finance.npv · vincolato a una colonna live · 0,83 ms a caldo

apposto prima dell'esecuzione

invocation_hash

8223a694250fc751fcf8a7777b8e1f524c44ff1f0e7e83451467f554a6123950

modulo · funzione · argomenti · binding risolti · seed · contratto · scope

apposto dopo l'esecuzione

computation_hash

ff5280ea128113f528dd1e9a28b9bc4a81469075ed7c981c7176fb172d98085d

l'hash di invocazione, combinato con il risultato canonico

Byte per byte identici in TypeScript e Python — un risultato calcolato in un linguaggio si riproduce e si verifica nell'altro.

entrambi calcolati rispetto acontract_hash sha256:79f1c5a6…

sul piano di queryplan_hash f87610d8afeb…decision_path "exact_spec"deterministic_scope "local_registered_source"

06Il ciclo di scoperta

Mai supporre. Scopri, simula, poi esegui.

I nomi dei campi e le firme delle funzioni vengono scoperti, non allucinati. L'AI SDK espone esattamente tre strumenti — e solo uno di essi esegue.

  1. 01listSources()

    Cosa posso toccare?

    Sorgenti connesse, con nomi di campo esatti, tipi e operazioni consentite per campo. Non esegue mai.

  2. 02listSources({ capabilitySearch: "npv" })

    Cosa posso calcolare?

    Lo stesso strumento, che interroga il catalogo deterministico — moduli corrispondenti, firme esatte e se è richiesto un seed.

  3. 03explainQuery({ … })

    Funzionerà?

    Una simulazione a secco. Restituisce il piano risolto, la confidenza e un invocation_hash di anteprima — un'anteprima, mai un hash eseguito.

  4. 04queryData({ … })

    Esegui.

    L'unico strumento che esegue. Restituisce il risultato con la sua provenienza completa; i risultati sovradimensionati rimangono recuperabili tramite result_id.

Gli strumenti non generano mai eccezioni — ogni esito è tipizzatook · needs_clarification · rejected · error

La meccanica, campo per campo.

Leggi la documentazione