エージェント向け — ガバナンス付きデータツール

AIエージェントツール
証明とともに答える。

SQAIはツール呼び出しモデルに、3つのガバナンス付きツールを通じて構造化データへの読み取り専用アクセスを提供する。モデルは型付きインテントを記述する。コントラクトとポリシーがそれを検証する。決定論的エンジンが実行する。すべての回答は、再現可能なハッシュとともに返される。

Iループの一ターン

リクエストが入るどの地域の総収益が最も高かったか?
任意のツール呼び出しモデルモデル

ステップを計画し、インテントを記述する。データには触れない。

ツール呼び出し — 型付きインテント、SQLではない{ version:"1", kind:"query", spec:{ metric:"revenue", aggregation:"sum", group_by:"region", source:"sales" } }
ガバナンス付きツールSQAI
  1. contractハッシュ固定されたケイパビリティコントラクト
  2. policy実行前にチェックされる許可リスト
  3. engine決定論的、読み取り専用の実行
型付きステータス — 例外をスローしないstatus: ok · needs_clarification · rejected · error
回答がハッシュとともに返るeast — 2,130.50 · plan_hash f87610d8afeb…
ok

ループを抜ける。行または値 — そしてそれを再現するハッシュ。

needs_clarification ↺

ループに戻る。質問と候補として見つかった項目 — モデルはスペックを絞り込んで再度呼び出す。カラムを推測することはない。

拒否とエラーは同じ返却レーンを通る — モデルが読める型付き結果であり、実行を中断する例外ではない。

IIツールセット

3つのツール。実行は1つ。

sqai.tools() が返すのは厳密に3つのツールのみ — 意図的に小さなサーフェスだ。ディスカバリとドライランは実行しない。実行は厳密に1か所でのみ行われる。

listSources

実行しない

ディスカバリー。型付きフィールドを持つ接続済みソース、ケイパビリティモジュール、関数シグネチャ — 1つの入力から3つのモード。スペックは正確な名前を使用する。

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

queryData

実行するツール

バージョン管理された1つの入力 — kind による判別共用体: クエリまたは計算。4つの結果、常に型付き、例外なし。

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

explainQuery

ドライラン — 実行しない

実行せずにインテントを解決・検証する。モデルは明確化のデバッグに使用し、開発者はプランのプレビューに使用する。

preview invocation_hash ≠ executed hash

このセットは generateText または streamText にそのまま渡せる — 型付き、キャストなしで代入可能。 Vercel AI SDK セットアップ

IIIエラー契約

ツールは例外を投げない。

例外はエージェントの実行を中断する。そのためここでは何も投げない: 曖昧さ、拒否、失敗はすべて型付きステータスとして返され、モデルはステップバジェット内でそれを読み取り、修正できる。

retryable 一時的なものにマークを付ける — network_error · timeout · rate_limited · service_unavailable

queryData — 4つの結果

ok結果: 行または値、出所ハッシュ、宣言済みの切り捨て。plan_hash · invocation_hash · computation_hash · truncated
needs_clarificationインテントが曖昧だった。質問と候補一覧 — 推測はしない。question · candidates · explanation
rejectedリゾルバーがインテントを拒否した。何も実行されていない。rejection_reason · candidates · explanation
error安定したコードを持つ構造化された失敗 — モデルが読み取り、調整する。code · message · retryable · nearest_matches?

すべての分岐はデータ。ループはターンを維持する。

原則

モデルを
非信頼クライアントとして扱う。

コードによるポリシー · ツール入力にポリシーフィールドなし · 縮小のみ

IV原則の適用

業界はこれを本番環境で学んだ — 自律型コーディングエージェントが本番データベースを削除した事例は広く知られている。SQAI の答えは振る舞いではなく構造による: 公開されるサーフェスは設計上読み取り専用だ。書き込みおよび非決定論的カテゴリは生成されず、フラグ、ポリシー、モデル入力のいずれによっても有効化できない。

モデルが送信するもの
型付きインテントのみ — バージョン管理されたスペック。SQL 文字列、コード、接続ハンドルは含まない。
送信できないもの
ポリシー。allowedSources、allowedFields、allowedFunctions は createSQAI() の設定で固定される — ツール入力スキーマにポリシーフィールドは存在しないため、リクエストはサーフェスを縮小できるが、拡大はできない。
それでも要求した場合
構造化された拒否 — policy_denied_source、policy_denied_field、policy_denied_function。リトライ不可、モデル可読、実行は継続する。
ポリシーモデル詳細

V配線

3行で接続。デフォルトで制限付き。

1つのパッケージがクライアントをツールにラップする。ソースは初回呼び出し時に遅延接続され、最初の計算でランタイムが一度プロビジョニングされ、その後ウォーム状態を維持する — 実測 0.83 ms。

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"

サーバーサイド専用 — Next.js では Edge ではなく Node ランタイムを使用すること。

モデルに渡されるもの

maxRowsToModel
25エンジンが実行した全件のうち、モデルが参照する行数
maxCellsToModel
250セルバジェット — 収まらない場合は行全体を削除する。行の一部を表示することはない
maxBytesToModel
32,000モデルが参照する値のバイトバジェット
maxExecutionRows
1,000エンジンが実行するハードキャップ — スペックに limit がない場合は defaultLimit 100

切り捨ては常に宣言される — truncated: true、returned_rows < total_rows。サイレントな切り捨ては発生しない。完全な結果はアプリケーションコードから result_id で取得できる。

VIエージェント分析

エージェントが根拠を示せる分析。

エージェント分析は既知のパターンで失敗する: 不正なツール呼び出し、モデル自身による計算、誰も検証できない一見もっともな数値。それぞれに対する答えは構造的であり、プロンプトの改善ではない。

01無効なツール呼び出し

バージョン管理された1つの入力が、実行前に検証される。不正または曖昧なインテントは型付きステータスを返す — クラッシュせずにループが継続する。

02モデルが計算する

ここでは違う。計算はエンジンが行う。16問の定量的セットで、エンジンが計算を担うことで同じモデルが 0/16 から 16/16 になった。

03検証できない数値

すべての回答にハッシュが付与される。同じインテントを同じデータに対して再実行すればハッシュが一致する — TypeScript と Python でバイト単位で同一。

04レイテンシの積み重なり

ループはレイテンシを乗算する。クエリプレーンはインプロセスでサブミリ秒で動作し、ウォームコンピュートの実測値は 0.83 ms。

VIIよくある質問

エージェント向け — よくある質問

AI エージェントにデータベースへの読み取り専用アクセスを与えるには?

SQL をフィルタリングするのではなく、生成しないこと。ソースを createSQAI() に接続し、モデルに sqai.tools() を渡す: モデルが到達できるサーフェスは設計上書き込みパスを持たない 4,574 の読み取り専用ケイパビリティとソースのみだ。ブロックすべき書き込みカテゴリは存在せず、それを再有効化するモデル入力もない。

エージェントのリクエストが曖昧な場合、どうなりますか?

queryData は needs_clarification を返し、質問と候補フィールドを提示します。列を推測することはありません。モデルはその質問に答えて再度呼び出します——ループがもう一周するだけです。

ツールが例外をスローすることはありますか?

ありません。すべての失敗は、安定したコード・メッセージ・再試行フラグを持つ構造化された結果として返されます。曖昧さ、拒否、ポリシー違反、一時的な障害——いずれもモデルが読めるデータとして返ってきます。

モデルが自身の権限を拡張することはできますか?

できません。allowedSources・allowedFields・allowedFunctions はコードに記述され、createSQAI() 時に設定され、実行前に検査されます。ツールの入力スキーマにポリシーフィールドは存在しません。拒否された機能を指定すると、構造化された policy_denied エラーが返されます。

Vercel AI SDK と連携できますか?

できます。@thyn-ai/sqai-ai-sdk は、generateText および streamText 向けに型付きツールセットとして3つのツールを提供します。ピア依存は ai ^7.0.0 と zod ^4.0.0、Node 20 以降のサーバーサイド専用です。内部クライアントは、任意のエージェントループに組み込める同一の SDK です。