Как это работает

Модель предлагает.
SQAI решает.

Агент никогда не пишет SQL и не генерирует код для выполнения. Он формирует типизированный запрос — и каждый запрос проходит один и тот же путь: проверка соответствия зафиксированному контракту, проверка политики, выполнение на детерминированном движке, возврат с хешами для воспроизведения.

Каждый запрос — ask(), compute() или вызов инструмента AI SDK — проходит один и тот же путь. Ничто не достигает движка, пока не пройдены все проверки.

01Типизированный запрос

Запрос, который движок может разобрать. Не строка, которой нужно доверять.

Модель формирует типизированный объект — никакого SQL, никакого кода. Запрос данных — это QuerySpec: метрика для агрегации по именованному источнику. Запрос вычисления — это ComputationSpec: именованная функция из контракта с аргументами и привязками. Одно размеченное объединение, две формы — и нигде в них нет места для исполняемой строки.

Это вся поверхность авторинга. Что форма не может выразить — модель не может запросить.

QuerySpecанатомия
{
"kind": "query",тег объединения — query или computation
"version": "1",версия спецификации, зафиксированная
"source_name": "sales",подключённый источник, по точному имени
"metric": "revenue",столбец для агрегации
"aggregation": "sum",одна из: sum · avg · count · min · max
"group_by": "region"необязательно — разбить результат по полю
}

также необязательноfilter · limit · order

форма вычисленияmodule · function · args · kwargs · bindings · seed?

02Проверка контракта

Один контракт, зафиксированный хешем. Неизвестное отклоняется с пояснением.

Спецификация проверяется по контракту возможностей — одному сгенерированному файлу с зафиксированным хешем, перечисляющему каждую операцию, её точную сигнатуру и флаги детерминизма. Возможность доступна только если она доступна только для чтения и детерминирована, либо детерминирована при заданном начальном значении. Операции с записью и недетерминированные не блокируются во время выполнения — они никогда не попадали в поверхность.

Неизвестная функция завершается ошибкой unsupported_operation и возвращает nearest_matches из того же индекса — модель исправляет себя сама, не зацикливаясь.

Контракт возможностей

contract_hashsha256:79f1c5a6c7164e7e9e1750e70a5c03292fa87eb52d8148a740c06695924be9a1

4,778
операций, перечисленных в контракте
4,574
доступно через SDK, только чтение
4,564
полностью детерминированные
10
симуляции с обязательным начальным значением
204
исключены из поверхности

критерий допускаread_only && (deterministic || deterministic_when_seeded)

при неизвестном имениunsupported_operation + nearest_matches

03Проверка политики

Ваш список разрешений определяет — выполнять ли и как.

Политика фиксируется при создании экземпляра через createSQAI() и применяется внутри процесса до любого выполнения — по источнику, каждой метрике, группировке, фильтру и привязанному столбцу, а также по имени функции. Она может только сужать контракт: указание возможности вне допустимой поверхности по-прежнему вызывает unsupported_operation.

Входные данные инструмента модели не содержат поля allowed*. Ничто в запросе не может расширить доступ — и расширять при инъекции в промпт нечего.

allowedSourcesисточники, которые модель может называть

  • "sales"

allowedFieldsстолбцы, доступные для чтения, по источнику

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

allowedFunctionsпо умолчанию — все возможности только для чтения, не более

  • "all-readonly"

отказ — точный, атрибутированный, окончательный

  • policy_denied_source
  • policy_denied_field
  • policy_denied_function

source: "sqai" · без повтора

04Детерминированный движок

Зафиксировано до запуска: float64, один поток, одна среда.

Сначала разрешаются привязки. Модель указала источник и поле; SQAI извлекает фактические значения через примитив движка extractColumns с выравниванием по строкам, нулевые значения обрабатываются попарно. SQAI никогда не объединяет массивы самостоятельно — поэтому входные данные, которые хешируются, в точности совпадают с теми, что были выполнены.

Только теперь запрос достигает движка. Среда выполнения подписана, версионирована и зафиксирована: точность float64, один поток. Первый вызов compute() инициализирует её один раз — примерно за 110 секунд; после этого она остаётся резидентной — finance.npv в прогретом состоянии занимает 0,83–0,93 мс.

конверт детерминизма
runtime_bundle_version0.1.0
runtime_bundle_sha2564d64142e4c1ff63d299cfc8b172fdf97cb59169b545e1e02978e678a632ce6e1
platformdarwin
architecturearm64
precision_modefloat64
thread_count1
seed
input_hash2ea5ede72acd2912fe9e1230cef34afad4c9436bfa8a709bac2da02b478e3212

Записывается с каждым результатом — конверт указывает область действия гарантии, не претендуя на большее.

05Ответ + происхождение

Два хеша. Один до, один после.

invocation_hash проставляется до выполнения — по модулю, функции, аргументам, разрешённым привязкам, начальному значению, контракту и области. computation_hash проставляется после: хеш вызова, свёрнутый с каноническим результатом. Воспроизведение — это повторный запуск с побайтовым сравнением.

Оба SDK используют один канонический сериализатор, поэтому одно и то же вычисление даёт побайтово идентичные хеши в TypeScript и Python. Ответы на запросы данных подчиняются той же дисциплине: plan_hash по каноническому разрешённому плану, путь принятия решения и точная область выполнения.

3188.1687606249325finance.npv · привязано к живому столбцу · 0,83 мс в прогретом состоянии

проставляется до выполнения

invocation_hash

8223a694250fc751fcf8a7777b8e1f524c44ff1f0e7e83451467f554a6123950

модуль · функция · аргументы · разрешённые привязки · seed · контракт · область видимости

проставляется после выполнения

computation_hash

ff5280ea128113f528dd1e9a28b9bc4a81469075ed7c981c7176fb172d98085d

хеш вызова, свёрнутый с каноническим результатом

Побайтово идентичны в TypeScript и Python — результат, вычисленный на одном языке, воспроизводится и верифицируется на другом.

оба вычисляются относительноcontract_hash sha256:79f1c5a6…

на плоскости запросовplan_hash f87610d8afeb…decision_path "exact_spec"deterministic_scope "local_registered_source"

06Цикл обнаружения

Никаких догадок. Обнаружить, проверить вхолостую, затем выполнить.

Имена полей и сигнатуры функций обнаруживаются, а не придумываются. AI SDK предоставляет ровно три инструмента — и только один из них выполняет запрос.

  1. 01listSources()

    Что доступно?

    Подключённые источники с точными именами полей, типами и допустимыми операциями для каждого поля. Никогда не выполняет запрос.

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

    Что можно вычислить?

    Тот же инструмент, выполняющий поиск по детерминированному каталогу: подходящие модули, точные сигнатуры и признак обязательности seed.

  3. 03explainQuery({ … })

    Запустится ли?

    Холостой прогон. Возвращает разрешённый план, уверенность и предварительный invocation_hash — только предварительный, не выполненный.

  4. 04queryData({ … })

    Выполнить.

    Единственный инструмент, который выполняет запрос. Возвращает результат вместе с полной цепочкой происхождения; объёмные результаты остаются доступны по result_id.

Инструменты никогда не бросают исключений — каждый исход типизированok · needs_clarification · rejected · error

Механика, поле за полем.

Документация