Pour les agents — l'outil de données gouverné

Outils pour agents IA
qui répondent avec preuve.

SQAI donne à un modèle à appel d'outils un accès en lecture seule aux données structurées via trois outils gouvernés. Le modèle formule une intention typée. Un contrat et votre politique la vérifient. Un moteur déterministe l'exécute. Chaque réponse est accompagnée d'un hachage qui permet de la rejouer.

IUn tour de boucle

la requête entreQuelle région a enregistré le chiffre d'affaires total le plus élevé ?
tout modèle à appel d'outilsLe modèle

Planifie les étapes. Formule l'intention. Ne touche jamais aux données.

appel d'outil — intention typée, jamais SQL{ version:"1", kind:"query", spec:{ metric:"revenue", aggregation:"sum", group_by:"region", source:"sales" } }
l'outil gouvernéSQAI
  1. contractcontrat de capacité épinglé par hachage
  2. policyvos listes d'autorisation, vérifiées avant exécution
  3. engineexécution déterministe en lecture seule
statut typé — jamais une exceptionstatus: ok · needs_clarification · rejected · error
la réponse sort — avec son hachageeast — 2,130.50 · plan_hash f87610d8afeb…
ok

Sort de la boucle. Les lignes ou la valeur — et le hachage qui permet de les rejouer.

needs_clarification ↺

Réintègre la boucle. Une question et les candidats trouvés — le modèle affine la spec et rappelle. Il ne devine jamais une colonne.

rejet et erreur empruntent le même chemin de retour — des résultats typés que le modèle peut lire, pas des exceptions qui interrompent l'exécution.

IILes outils

Trois outils. Un seul exécute.

sqai.tools() retourne exactement trois outils — une surface délibérément réduite. La découverte et les simulations n'exécutent jamais ; l'exécution n'a lieu qu'en un seul endroit.

listSources

n'exécute jamais

Découverte. Sources connectées avec champs typés, modules de capacités, signatures de fonctions — trois modes depuis une seule entrée, pour que les specs utilisent les noms exacts.

sources · capabilitySearch · module
ops: sum avg count min max eq in gt gte lt lte is_null is_not_null

queryData

celui qui exécute

Une entrée versionnée — une union discriminée sur kind : une requête ou un calcul. Quatre résultats, toujours typés, jamais d'exception.

version "1" · kind: query | computation
ok · needs_clarification · rejected · error

explainQuery

simulation — n'exécute jamais

Résout et valide une intention sans l'exécuter. Le modèle l'utilise pour déboguer des clarifications ; vous l'utilisez pour prévisualiser un plan.

preview invocation_hash ≠ executed hash

L'ensemble s'intègre directement dans generateText ou streamText — typé, assignable sans cast. Configuration du Vercel AI SDK

IIILe contrat d'erreur

Les outils ne lèvent jamais.

Une exception interrompt l'exécution d'un agent. Rien ici ne lève donc d'exception : ambiguïté, refus et échec reviennent sous forme de statuts typés que le modèle peut lire — et corriger — dans son budget d'étapes.

retryable marque les transitoires — network_error · timeout · rate_limited · service_unavailable

queryData — les quatre résultats

okLe résultat : lignes ou valeur, hachages de provenance, troncature déclarée.plan_hash · invocation_hash · computation_hash · truncated
needs_clarificationL'intention était ambiguë. Une question avec les candidats — jamais une supposition.question · candidates · explanation
rejectedLe résolveur a refusé l'intention. Rien n'a été exécuté.rejection_reason · candidates · explanation
errorUn échec structuré avec un code stable — le modèle le lit et s'ajuste.code · message · retryable · nearest_matches?

Chaque branche est une donnée. La boucle conserve son tour.

Le principe

Traiter le modèle comme
un client non fiable.

politique dans le code · aucun champ de politique dans les entrées d'outil · restriction uniquement

IVLe principe, appliqué

L'industrie l'a appris en production — un agent de codage autonome a supprimé une base de données en production, fait désormais célèbre. La réponse de SQAI est structurelle, non comportementale : la surface exposée est en lecture seule par construction. Les catégories d'écriture et non déterministes n'y sont jamais générées, et aucun indicateur, politique ou entrée de modèle ne les réactive.

Ce que le modèle envoie
Une intention typée uniquement — une spec versionnée. Pas de chaîne SQL, pas de code, pas de handle de connexion.
Ce qu'il ne peut jamais envoyer
La politique. allowedSources, allowedFields et allowedFunctions sont fixés dans la configuration de createSQAI() — aucun schéma d'entrée d'outil ne contient de champ de politique, donc une requête peut restreindre la surface mais jamais l'élargir.
Quand il demande quand même
Un refus structuré — policy_denied_source, policy_denied_field, policy_denied_function. Non réessayable, lisible par le modèle, et l'exécution continue.
Modèle de politique complet

VLe câblage

Trois lignes. Borné par défaut.

Un package encapsule le client en outils. Les sources se connectent paresseusement au premier appel ; le premier calcul provisionne le runtime une fois, puis reste chaud — 0,83 ms mesuré.

import { generateText } from "ai";
import { createSQAI } from "@thyn-ai/sqai-ai-sdk";

const sqai = createSQAI({
  sources: [{ data: "./data/sales.csv", name: "sales" }],
});

const { text, steps } = await generateText({
  model,                  // any AI SDK model
  tools: sqai.tools(),    // listSources · queryData · explainQuery
  prompt: "Which region had the highest total revenue?",
});
ai ^7.0.0zod ^4.0.0node ≥ 20runtime = "nodejs"

Côté serveur uniquement — sur Next.js, conservez le runtime Node, pas Edge.

Ce qui parvient au modèle

maxRowsToModel
25lignes visibles par le modèle, sur l'ensemble exécuté par le moteur
maxCellsToModel
250budget de cellules — des lignes entières sont supprimées pour s'adapter ; une ligne partielle n'est jamais affichée
maxBytesToModel
32,000budget en octets pour la valeur visible par le modèle
maxExecutionRows
1,000plafond dur exécuté par le moteur — defaultLimit 100 quand une spec omet limit

La troncature est toujours déclarée — truncated: true, returned_rows < total_rows. Jamais silencieuse. Les résultats complets restent accessibles dans le code applicatif via result_id.

VIAnalytique agentique

Une analyse qu'un agent peut défendre.

L'analytique agentique échoue de manières connues : appels d'outils malformés, modèles effectuant leur propre arithmétique, chiffres plausibles que personne ne peut vérifier. Chacun reçoit une réponse structurelle, non un meilleur prompt.

01Appels d'outils invalides

Une entrée versionnée, validée avant toute exécution. Une intention malformée ou ambiguë retourne un statut typé — la boucle continue au lieu de planter.

02Le modèle fait le calcul

Pas ici. Le moteur calcule. Sur un ensemble de 16 questions quantitatives, le même modèle est passé de 0/16 à 16/16 dès que le moteur a pris en charge le calcul.

03Chiffres invérifiables

Chaque réponse porte son hash. Rejouez la même intention sur les mêmes données et le hash correspond — octet identique en TypeScript et en Python.

04Empilement de latence

Une boucle multiplie la latence. Le plan de requête s'exécute en processus en sous-milliseconde ; le calcul chaud mesuré à 0,83 ms.

VIIQuestions

Pour les agents — les questions

Comment donner à un agent IA un accès en lecture seule à une base de données ?

Ne filtrez pas le SQL — ne le générez pas. Connectez des sources à createSQAI() et transmettez au modèle sqai.tools() : la surface accessible est 4 574 capacités en lecture seule plus vos sources, sans chemin d'écriture par construction. Il n'existe aucune catégorie d'écriture à bloquer, et aucune entrée de modèle ne peut en réactiver une.

Que se passe-t-il lorsque la requête de l'agent est ambiguë ?

queryData retourne needs_clarification avec une question et les champs candidats identifiés. Il ne devine jamais une colonne. Le modèle répond à la question et rappelle — un tour de boucle supplémentaire.

Les outils lèvent-ils des exceptions ?

Non. Chaque échec est un résultat structuré avec un code stable, un message et un indicateur de réessai. Ambiguïté, refus, blocage de politique et erreurs transitoires reviennent tous sous forme de données lisibles par le modèle.

Le modèle peut-il élargir ses propres permissions ?

Non. allowedSources, allowedFields et allowedFunctions sont définis dans le code, fixés à la création de createSQAI() et vérifiés avant toute exécution. Aucun schéma d'entrée d'outil ne contient de champ de politique ; nommer une capacité refusée retourne une erreur structurée policy_denied.

Est-ce compatible avec le Vercel AI SDK ?

Oui — @thyn-ai/sqai-ai-sdk fournit les trois outils comme ensemble d'outils typés pour generateText et streamText, avec ai ^7.0.0 et zod ^4.0.0 en pairs, Node 20 ou supérieur, côté serveur. Le client sous-jacent est le même SDK que vous pouvez intégrer dans n'importe quelle boucle d'agent.