Déterminisme, par construction

IA déterministe,
par construction.

Posez deux fois la même question à un modèle et vous pouvez obtenir deux réponses différentes. C'est l'IA non déterministe — acceptable pour la prose, fatal pour les chiffres. SQAI retire le calcul au modèle : chaque computation s'exécute sur un runtime float64 ancré, mono-thread, et imprime le hash qui la rejoue à l'identique.

IILe replay

Deux certificats, à des mois d'intervalle.

Une seule computation — finance.npv à un taux d'actualisation de 10 % sur cinq flux de trésorerie — exécutée une fois, puis rejouée des mois plus tard. Le déterminisme comme promesse demande votre confiance. Comme hash, il demande une comparaison.

Run 001première exécution

enveloppe de déterminisme

capability
finance.npv
runtime_bundle
0.1.0 · 4d64142e…
platform
darwin-arm64
precision_mode
float64
thread_count
1
value
505.020148896933

computation_hashb74f67d0d7a594aa…

Run 002des mois plus tard

enveloppe de déterminisme

capability
finance.npv
runtime_bundle
0.1.0 · 4d64142e…
platform
darwin-arm64
precision_mode
float64
thread_count
1
value
505.020148896933

computation_hashb74f67d0d7a594aa…

Identique. Pas similaire — identique.

computation_hash partagéb74f67d0d7a594aa7ac91f6291612452aa8ccdf603351ebc8d801a6fddd91bc8

Deux langages, un flux d'octets

TypeScriptcanonicalJson(result.value)

Pythoncanonical_json(result.value)

octets identiques, quel que soit le langage505.020148896933

mêmes octets en entrée → même sha256 en sortie → le même certificat

canonicalJson en TypeScript et canonical_json en Python émettent les mêmes octets par construction : −0 devient 0, les clés sont triées, l'échappement unicode est fixé. L'égalité des hachages entre langages n'est pas une coïncidence à espérer — c'est un contrat de sérialisation.

IIILes détails

Déterministe — dans le périmètre déclaré.

« Déterministe » est facile à afficher et difficile à tenir. SQAI ne prétend pas que votre résultat est identique sur toutes les machines de l'univers. Il déclare un périmètre d'exécution, l'enregistre dans l'enveloppe et garantit l'identité à l'intérieur de ce périmètre.

Consigner l'environnement vaut mieux que le surestimer. Tout ce qui pourrait modifier le résultat est soit épinglé, soit consigné.

déclaré sur chaque résultatdeterministic_scope: "local_registered_source"

runtime_bundle_version
la version du moteur utilisée — 0.1.0 aujourd'hui, épinglée
runtime_bundle_sha256
le hachage de contenu de la version — vérifié avant toute exécution
platform
l'environnement d'exécution — darwin-arm64 ou linux-x64, consigné, jamais supposé
architecture
la famille de CPU, consignée pour la même raison
precision_mode
float64 — un seul régime numérique pour chaque capacité
thread_count
1 — aucune concurrence d'ordonnancement dans vos calculs
seed
optionnel — requis par exactement 10 capacités de simulation
input_hash
les données telles qu'elles étaient, horodatées avant l'exécution

IVProvenance à domaines séparés

Trois hachages, trois questions.

La provenance n'est pas ici une ligne de journal. Ce sont trois constructions sha256, chacune répondant à une question différente, chacune calculée sur des octets canoniques.

plan_hashf87610d8afeb…

Ce qui s'exécutera.

Le plan résolu, haché avant toute exécution. La même question produit le même plan — decision_path: exact_spec — ainsi un plan examiné une fois l'est pour toujours.

invocation_hash

Ce qui a été demandé.

L'identité de l'appel — la capacité et ses arguments canonicalisés — sous son propre préfixe versionné. explainQuery l'affiche en aperçu à blanc ; le hachage exécuté est estampillé indépendamment à l'exécution.

computation_hashb74f67d0d7a594aa…

Ce qui a été retourné.

Intègre l'invocation_hash avant les octets canoniques de la valeur. La réponse est cryptographiquement chaînée à sa question — ce hachage ne peut pas être apposé sur un résultat différent.

invocation_hash  = sha256("sqai:invocation:v1\0" + canonicalJson(identity))
computation_hash = sha256("sqai:computation:v1\0" + invocation_hash + canonicalJson(value))

Les préfixes sont l'essentiel. « sqai:invocation:v1 » et « sqai:computation:v1 » sont des univers d'octets disjoints : une invocation ne peut jamais entrer en collision avec un calcul, et un futur v2 ne peut jamais usurper l'identité de v1. La séparation de domaines fait des hachages des preuves, non des ornements.

Sous ces trois hachages, la surface elle-même est épinglée. Le contrat de capacités qui définit ce qui peut s'exécuter est livré avec son propre hachage :contract_hash sha256:79f1c5a6c716…

Température 0
n'est pas du déterminisme.

l'échantillonnage n'est pas l'exécution — le modèle ne calcule jamais ici

VÉchantillonnage vs exécution

Le modèle choisit les tokens. Le moteur calcule.

temperature: 0un paramètre de décodage

  • Le décodage glouton restreint le token suivant. Le nombre est toujours prédit, non calculé.
  • La même question peut toujours produire un SQL différent — et une réponse différente — sans rien pour le signaler.
  • Rien n'est enregistré : ni le runtime, ni le hachage d'entrée, rien à rejouer.

computation_hashune propriété d'exécution

  • Le modèle soumet un plan typé. Le moteur l'exécute — float64, un thread, bundle épinglé.
  • L'environnement accompagne le résultat, à l'intérieur de l'enveloppe de déterminisme.
  • Chaque réponse affiche un computation_hash. Le rejeu est une comparaison, non un argument.
0/16 → 16/16
le même modèle sur seize questions quantitatives — avant et après que le moteur effectue les calculsLe moteur lui-même est audité : 2 744 vérifications d'exactitude, 0 écart, erreur numérique maximale 1,8e-15.

VIOù le déterminisme pourrait céder

Dix graines. Un déclencheur.

seed_required

Dix des 4 574 capacités exposées simulent l'aléatoire. Sans graine, elles ne s'exécutent pas du tout — l'appel est rejeté avant l'exécution. Avec une graine, elles se rejouent comme tout le reste. Aucune entropie cachée, aucune exception silencieuse.

l'une des dixdistributions.sample_normal

schema_revision_mismatch

Chaque source enregistrée porte une révision de schéma. Rejouez un plan sur des données modifiées et le moteur refuse avec une erreur structurée — non un nombre silencieusement différent que rien ne signalerait jamais.

déclarée sur chaque sourceschema_revision

4 564 déterministes telles quelles · 10 déterministes une fois initialisées · 0 qui supposent

VIIQuestions

L'IA déterministe, sans détour.

Qu'est-ce que l'IA déterministe ?

Un système dont les réponses se reproduisent à l'identique : même entrée, même sortie, de façon prouvable. SQAI l'implémente par construction — les calculs s'exécutent sur un runtime float64 épinglé, en mono-thread, et chaque résultat porte un computation_hash qui le rejoue octet par octet.

Qu'est-ce que l'IA non déterministe ?

Un système dont la sortie peut varier entre des requêtes identiques. Les modèles de langage échantillonnent des tokens : la même question peut produire un raisonnement différent, un SQL différent, des chiffres différents — sans aucun signal qu'il s'est passé quoi que ce soit. Un hash rejouable est l'antidote à cette dérive.

Une température à 0 ne rend-elle pas un LLM déterministe ?

La température réduit seulement la façon dont le token suivant est choisi. Le modèle prédit toujours votre chiffre au lieu de le calculer, et rien de l'exécution n'est enregistré ni rejouable. Le déterminisme de SQAI est une propriété de l'exécution, non du décodage : le modèle dépose un plan typé et le moteur effectue les calculs.

Comment vérifier que deux exécutions ont bien retourné la même réponse ?

Comparez le computation_hash de chaque résultat. Il s'agit d'un sha256 à domaine séparé sur l'identité d'invocation et les octets canoniques de la valeur : des hashes identiques signifient des réponses identiques octet par octet — l'exemple finance.npv affiche b74f67d0… aussi bien en TypeScript qu'en Python.

Comment des simulations peuvent-elles être déterministes ?

En refusant d'être aléatoires en secret. Exactement 10 des 4 574 capacités exposées de SQAI simulent l'aléatoire ; appelées sans graine, elles sont rejetées avec seed_required ; avec une graine, elles se rejouent exactement comme toute autre capacité.

Que se passe-t-il si les données ont changé entre la première exécution et le rejeu ?

Le rejeu échoue explicitement. Chaque source enregistrée porte une révision de schéma ; un plan rejoué contre des données modifiées retourne schema_revision_mismatch — une erreur structurée, jamais un chiffre silencieusement différent.