Как это работает
Модель предлагает.
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 мс.
0.1.04d64142e4c1ff63d299cfc8b172fdf97cb59169b545e1e02978e678a632ce6e1darwinarm64float641—2ea5ede72acd2912fe9e1230cef34afad4c9436bfa8a709bac2da02b478e3212Записывается с каждым результатом — конверт указывает область действия гарантии, не претендуя на большее.
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 предоставляет ровно три инструмента — и только один из них выполняет запрос.
- 01
listSources()Что доступно?
Подключённые источники с точными именами полей, типами и допустимыми операциями для каждого поля. Никогда не выполняет запрос.
- 02
listSources({ capabilitySearch: "npv" })Что можно вычислить?
Тот же инструмент, выполняющий поиск по детерминированному каталогу: подходящие модули, точные сигнатуры и признак обязательности seed.
- 03
explainQuery({ … })Запустится ли?
Холостой прогон. Возвращает разрешённый план, уверенность и предварительный invocation_hash — только предварительный, не выполненный.
- 04
queryData({ … })Выполнить.
Единственный инструмент, который выполняет запрос. Возвращает результат вместе с полной цепочкой происхождения; объёмные результаты остаются доступны по result_id.
Инструменты никогда не бросают исключений — каждый исход типизированok · needs_clarification · rejected · error
Механика, поле за полем.
Документация →- Детерминированный AIконверт и три хеша, поле за полем
- Управление данными AIсписки разрешений и правило сужения — в деталях
- Подключение данныхкаждый источник приводится к единой типизированной форме