QueryPilot について
QueryPilotは、SQLAlchemyデータベースを使うAIエージェント向けのポリシー管理付きSQLゲートウェイです。読み取り専用の検証やスキーマ情報に加え、監査・トレース・評価でクエリの信頼性を測定できます。
主な機能
- 01SELECTのみのSQL検証
- 02スキーマの探索と検索
- 03アクセス方針、マスキング、行数制限
- 04修正ヒント付きSQL実行
- 05監査・トレース・評価ツール
活用シーン
- 01読み取り専用の制御下でデータベースを照会
- 02実際のスキーマに基づくSQL生成
- 03エージェントのSQLエラーの調査
- 04評価スイートによるSQLの回帰テスト
MCP 対応
MCPクライアントに、スキーマ確認、SQL検証・実行、任意で自然言語によるデータベース問い合わせのツールを提供します。同じツールをstdioまたはStreamable HTTPで公開できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
uvx querypilotQUERYPILOT_DATABASE_URLシークレットSQLAlchemy-style database connection URL, e.g. sqlite:///demo.db or postgresql://user:pass@host:5432/db. Equivalent to --database-url.QUERYPILOT_DIALECTSQL dialect for the connector. Equivalent to --dialect.QUERYPILOT_MAX_ROWSMaximum rows returned per query. Equivalent to --max-rows.QUERYPILOT_TIMEOUT_SECONDSQuery execution timeout in seconds. Equivalent to --timeout-seconds.QUERYPILOT_ACCESS_POLICY_JSONJSON-encoded AccessPolicy (blocked_columns, allowed_columns, row_filters, masking_rules) enforced before execution. Equivalent to --access-policy-json.QUERYPILOT_MCP_TRANSPORTMCP transport used by `querypilot mcp`. Equivalent to --transport. Most MCP clients should leave this at stdio; streamable-http is for clients that speak Streamable HTTP directly.ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
QueryPilot
AI エージェントのための、安全で測定可能な SQL。
QueryPilot は、LLM エージェントとデータベースの間に位置します。あらゆる SQLAlchemy データベースに対して、読み取り専用でポリシーによりチェックされる SQL ツールをエージェントに提供します。実際のスキーマに基づいてモデルに情報を与え、エラーをモデルに返して SQL を修正できるようにし、SQL が正しく、その正しさが維持されることを証明する評価ハーネスも備えています。
クイックスタート
pip install querypilot
querypilot demo
querypilot demo は、小規模な SaaS データベース(querypilot-demo.db)を作成し、検証済みのクエリを実行して、ブロックされた DELETE を表示します。続けて、次を試してください。
querypilot schema --db sqlite:///querypilot-demo.db # list tables
querypilot schema --db sqlite:///querypilot-demo.db invoices # columns, keys, sample values
querypilot sql --db sqlite:///querypilot-demo.db "SELECT customer_nme FROM customers"
# Error: SQL validation failed: Unknown column: customer_nme
# hint: Column 'customer_nme' does not exist; did you mean customers.customer_name, ...?
querypilot ask --db sqlite:///querypilot-demo.db "Which customers have the highest ARR?"
OPENAI_API_KEY または ANTHROPIC_API_KEY が設定されている場合、ask は OpenAI または Anthropic を使用します(Ollama、vLLM、LM Studio には --generator openai-compatible を使用します)。キーがない場合は、オフラインのデモ用ジェネレーターに切り替わります。
独自のデータベースを使う場合は、querypilot init --db postgresql://[email protected]/prod を実行すると、接続情報、業務上のヒント、カラムの説明、アクセス ポリシーを保持する querypilot.yaml が作成されます。以降は、すべてのコマンド、MCP サーバー、QueryPilot.from_config() がこのファイルを読み込むため、--db を省略できます。
Python では、次のようにします。
from querypilot import QueryPilot
qp = QueryPilot.connect("postgresql://[email protected]/prod") # dialect inferred from the URL
result = qp.execute_sql("SELECT plan, COUNT(*) FROM subscriptions GROUP BY plan")
print(result.sql) # rewritten with a LIMIT, validated against the live schema
print(result.rows)
あらゆるデータベースに接続
QueryPilot.connect(url) は URL から SQL 方言を推測し、テーブル、ビュー、主キーと外部キー、コメントをイントロスペクトします。SQLAlchemy の Engine も受け付けます。
| データベース | URL | インストール |
|---|---|---|
| SQLite | sqlite:///app.db | 同梱 |
| PostgreSQL | postgresql://user:pass@host/db | 同梱 |
| DuckDB | duckdb:///analytics.duckdb | pip install "querypilot[duckdb]" |
| MySQL / MariaDB | mysql+pymysql://user:pass@host/db | pip install "querypilot[mysql]" |
| SQL Server | mssql+pyodbc://… | pip install "querypilot[mssql]" |
| Snowflake | snowflake://user@account/db/schema | pip install "querypilot[snowflake]" |
| BigQuery | bigquery://project/dataset | pip install "querypilot[bigquery]" |
| Redshift | redshift+psycopg2://… | pip install "querypilot[redshift]" |
| Trino / Oracle / Databricks | trino://…, oracle+oracledb://…, databricks://… | querypilot[trino], [oracle], [databricks] |
すべてのクエリは、対象の方言に合わせて sqlglot で検証されます。検証では、ステートメントが1つだけであること、SELECT のみであること、テーブルとカラムが既知であることを確認します。また、各エンジンで危険な関数(pg_read_file、DuckDB の read_csv、MySQL の LOAD_FILE、SQL Server の xp_cmdshell など)もブロックします。実行時には、エンジン固有の保護機能も適用されます。Postgres、MySQL、Oracle では読み取り専用トランザクション、DuckDB では読み取り専用接続を使用し、エンジンが対応している場合はステートメントのタイムアウトも設定します。すべてのクエリは、必ずロールバックされるトランザクション内で実行されます。読み取り専用セッションモードがないデータウェアハウスでは、読み取り専用ロールで接続してください。
エージェントにツールを提供する
各インテグレーションでは、同じ小規模なツールセットを利用できます。結果はコンパクトな JSON で返され、エラーは例外ではなく {"ok": false, "error": ..., "hints": [...]} として返されるため、エージェントは自分で修正できます。
| ツール | 機能 |
|---|---|
list_tables | ポリシーで許可されたテーブルとビュー、およびコメントを一覧表示します |
describe_table | 指定したテーブルのカラム、型、キー、コメント、サンプル値を表示します |
search_schema | 質問に関連するテーブルとカラムを検索します |
validate_sql | SQL を検証し、書き換え後の形式、エラー、「もしかして」のヒントを返します |
run_sql | SQL を検証して実行し、max_rows に達した場合は truncated フラグ付きで行を返します |
ask_database | 自然言語 → 検証済み SQL → 行(LLM ジェネレーターが設定されている場合のみ) |
MCP(Claude Code、Claude Desktop、Cursor、VS Code、Windsurf):
querypilot mcp-config claude-code --db postgresql://analyst@db/prod
# claude mcp add querypilot --env QUERYPILOT_DATABASE_URL=... -- /path/to/uvx --from 'querypilot[mcp]' querypilot mcp
querypilot mcp-config cursor --db sqlite:///app.db # prints the mcpServers JSON block
生成される設定では uvx に絶対パスを使用するため、よくある spawn uvx ENOENT エラーを回避できます。現在の環境を起動するには、--runner python を渡してください。すべてのツールには MCP の readOnlyHint アノテーションが付いています。querypilot mcp --transport streamable-http --port 8000 を実行すると、同じツールを HTTP 経由で提供できます。
OpenAI / Anthropic のツール呼び出し:
tools = qp.as_openai_tools() # Chat Completions; qp.toolkit().openai_responses_tools() for Responses
tools = qp.as_anthropic_tools()
result = qp.handle_tool_call(tool_call.name, tool_call.arguments) # dict or JSON string in, dict out
エージェントフレームワーク:
from querypilot.integrations import (
as_langchain_tools, # LangChain / LangGraph StructuredTools
as_llamaindex_tools, # LlamaIndex FunctionTools
as_openai_agents_tools, # OpenAI Agents SDK FunctionTools
as_claude_agent_mcp_server, # Claude Agent SDK in-process MCP server
claude_agent_allowed_tools,
as_functions, # plain typed functions: Pydantic AI, smolagents, CrewAI, ADK
)
tools = as_langchain_tools(qp, naming="langchain") # sql_db_list_tables, sql_db_schema, sql_db_query, ...
naming="langchain" は、コミュニティ製の SQLDatabaseToolkit(メンテナンス終了)のツール名を再利用するため、既存のプロンプトをそのまま使えます。対応する追加パッケージをインストールしてください:querypilot[langchain]、[llamaindex]、[openai-agents]、[claude-agent]、または [mcp]。詳しくは examples/07_frameworks.py を参照してください。
あらゆる Postgres クライアントを保護する:querypilot proxy(プロトタイプ)
プロキシに SDK は必要ありません。Postgres ワイヤープロトコルサーバーとして、クライアントを問わず、すべてのステートメントに同じバリデーターとアクセス ポリシーを適用します。対象には、psql、psycopg、SQLAlchemy、LangChain、既存の MCP データベースサーバー、Cursor、Claude Code、BI ツールが含まれます。データベースではなくプロキシを接続先に指定してください。
pip install "querypilot[proxy]"
querypilot proxy --upstream postgresql://readonly@db/prod --listen 127.0.0.1:6543 --policy querypilot.yaml
psql "postgresql://[email protected]:6543/prod" -c "SELECT email FROM customers"
npx -y @modelcontextprotocol/server-postgres postgresql://[email protected]:6543/prod # unchanged MCP server
各ステートメントには、次の処理が適用されます。
- 読み取り専用の強制。 書き込み、DDL、COPY、および小規模な許可リストにない値の
SETは拒否されます。許可されたステートメントは、デフォルトで読み取り専用のセッション上にあるREAD ONLYトランザクションで実行されるため、COMMIT; DROP TABLE …は拒否されます。 - 行フィルターと行数上限。 書き換え後の SQL がデータベースに送られるため、ポリシーの
row_filtersは結合、サブクエリ、CTE でも適用され、LIMITはmax_rowsを上限とします。 - マスキング。
masking_rulesは出力位置に基づいて適用されるため、upper(email) AS contactもマスキングされます。 - エージェントが修正できるエラー。 拒否は通常の Postgres エラーとして、SQLSTATE、バリデーターのメッセージ、
HINTとともに返されます。たとえば、Column 'nope' does not exist. Columns of orders: id, customer_id, …のようになります。 - 監査。 各ステートメントにつき 1 件の JSONL レコードが
--audit-logに記録されます。レコードには、クライアントの SQL、実行された SQL、行数、クライアントのユーザーとアプリケーションが含まれます。
ドライバーのハンドシェイク、書式設定用の SET/SHOW、および psql \d や ORM のリフレクションで使われるカタログクエリは、許可リストを通じて実行できます。pg_stats や query_to_xml(...) など、データを読み取る可能性のあるカタログクエリは拒否されます。ポリシーファイルは通常の querypilot.yaml で、--upstream を省略すると、その database_url が使用されます。ループバック外で使用する場合は、QUERYPILOT_PROXY_PASSWORD を設定してください。プロトコルの対応範囲、既知の制限(現時点では TLS 終端とサーバーサイドカーソルには未対応)、およびフェイルクローズする理由については、docs/proxy.md を参照してください。
エージェントがすでに実行している SQL を監視する:querypilot trace と hooks
一部のクエリツールは、たとえば Palantir Foundry の MCP SQL ツールのように、QueryPilot の背後に配置できません。そのような場合、QueryPilot はエージェントの実行内容を読み取ります。trace import は、Claude Code のトランスクリプト内にある各クエリツール呼び出しとその結果を対応付けます。hooks install は新しい呼び出しをリアルタイムで記録します。trace doctor は、種類ごとの失敗率、再試行の連鎖、レイテンシ、停滞を報告し、それぞれの問題について、ツール、プロンプト、データのどれを修正するのが最適かを示します。
querypilot trace doctor # reads ~/.claude/projects
querypilot trace doctor --output report.md # redacted, shareable
querypilot hooks install --guard --max-rows 200
--guard を指定すると、PreToolUse フックが、エージェント自身のスキーマ呼び出しからキャッシュしたスキーマを使って各クエリを検証します。クエリがウェアハウスに届く前に、不明な列を「もしかして」と候補を示す返信とともに拒否し、エポックミリ秒で格納された DATE 列に対する日付演算をブロックし、行数の上限を適用します。Foundry のツールはデフォルトでマッピングされています。ほかのツールは --tool NAME=SQL_FIELD[:DIALECT] でマッピングできます。復元された再試行の連鎖は、回帰テストスイートとして eval replay にエクスポートできます。docs/trace.md と最初の Foundry レポートをご覧ください。
モデルからより良い SQL を得る
QueryPilot が SQL 自体を作成する場合(ask、ask_database、evals)、テキストから SQL を生成する研究で最も大きな効果が測定されている手法を使います。出典と数値は docs/research/developer-needs.md に記載されています。
- 根拠のあるスキーマ。 プロンプトには、各テーブルがコンパクトな DDL 形式で表示されます。主キー、外部キーの結合経路、コメント、カテゴリのようなテキスト列の実際の値も含まれます。値が 10 個以下の場合はすべて、それを超える場合は出現頻度の高い 3 つが含まれます。サンプル値に、ブロック、マスク、または行フィルターが適用された列の値が使われることはありません。
- ビジネスルールを反映。
connect()にhints=とdescriptions=を渡すか、querypilot.yamlに設定すると、「売上とは支払い済みの請求書のみを指す」のような定義を指定できます。 - 必要な場合に限ってスキーマを絞り込み。
schema_token_budget(デフォルトは 6000 トークン)以下の場合は、スキーマ全体を送信します。これを超える場合は、関連するテーブルと、それらを結合する外部キーの中間テーブルを送信します。 - 収束する修正ループ。 検証エラーには「もしかして」という候補を示すヒントが付加されます。データベースエラーは、モデルに返す前に整理されます。結果が空の場合は、1 回だけ穏やかな見直しを促します。デフォルトでは最大 3 回試行します。
from querypilot import AnthropicSQLGenerator, QueryPilot
qp = QueryPilot.connect(
"duckdb:///analytics.duckdb",
generator=AnthropicSQLGenerator(),
hints=["Revenue means SUM(amount_cents) / 100 over invoices with status = 'paid'"],
descriptions={"accounts.segment": "smb, midmarket or enterprise"},
)
answer = qp.ask("Revenue by segment last quarter")
QueryPilot が存在する理由
エージェント向けの読み取り専用 SQL アクセスは、ありふれたものになりつつあります。難しいのは、そのアクセスを測定可能な信頼性の高いものにすることです。つまり、エージェントが作成する SQL が正確で、安全かつ高速であり、性能が後退しないことを証明することです。
QueryPilot は、プロンプト、モデル、設定に対するあらゆる変更を、実行結果を真実とする eval スイートで測定できます。スイートは手作業で作成することも、監査ログを回帰テストセットとして再生して生成することもできます。昨日、本番環境で動作したクエリは、明日も動作し続けなければなりません。
Eval のクイックスタート
このリポジトリをクローンした状態で実行します(同梱のスイートは tests/fixtures/demo.db に対して実行されます)。
pip install -e ".[eval]"
querypilot eval run \
--suite suites/smoke.yaml \
--generator demo \
--report eval-out.json
querypilot eval check \
--report eval-out.json \
--baseline .eval/baseline.json \
--threshold 0.9 \
--require-safety 1.0
出力例(一部抜粋。完全なレポートはこの README の冒頭をご覧ください)。
QueryPilot Eval Report
Suite: smoke
Generator: demo
Overall
✅ Pass rate 3 / 3 (100%)
✅ Safety pass rate 0 / 0 (100%)
✅ Correctness 3 / 3 (100%)
✅ P95 latency 18 ms
✅ No threshold violations.
同梱の suites/smoke.yaml は、小さな SQLite フィクスチャ(tests/fixtures/demo.db)に対して実行されるため、LLM のキーがなくてもハーネス全体を動作させられます。独自のプロジェクトでは、querypilot eval init を実行すると suites/ と .eval/ が生成されます。実際のジェネレーターをベンチマークするには、--generator openai または --generator anthropic を使います。
監査ログの再生
querypilot eval replay は、JSONLAuditSink が書き込んだ JSONL 監査ログを、以前に実行された SQL を正解 SQL とする BenchmarkSuite に変換します。このスイートを再実行することで、独自の本番トラフィックに対する精度の後退を防げます。これは QueryPilot 独自の機能であり、eval の位置付けを支えるものです。
querypilot eval replay \
--audit-jsonl audit.jsonl \
--fixture-db sqlite:///tests/fixtures/demo.db \
--output suites/replay.yaml
querypilot eval run --suite suites/replay.yaml --generator demo --report replay-out.json
保守的なデフォルト設定では、成功した ask レコードのみを対象とし、結果が空ではなく、アクセス ポリシーが有効でないものに限定します。--include-failures、--include-masked、--include-empty を指定すると、それぞれのフィルターを緩和できます。
CI ゲート
querypilot eval check は SuiteReport JSON をしきい値およびコミット済みのベースラインと比較し、リグレッションがあると 0 以外の終了コードで終了します。サンプルの GitHub Actions ワークフローが .github/workflows/eval.yml に含まれています。
- run: querypilot eval run --suite suites/smoke.yaml --generator demo --report eval-out.json
- run: querypilot eval check --report eval-out.json --baseline .eval/baseline.json --threshold 0.9 --require-safety 1.0
リグレッションが検出されると、どのケースでどのようなリグレッションが発生したかが出力に表示されます。
Regression detected.
Pass rate:
baseline: 96%
current: 89%
Failed cases (regression vs. baseline):
- monthly_revenue_by_segment (was passing -> now result_mismatch)
- top_customers_by_arr (was passing -> now repair_failed)
Latency:
baseline p95: 2100 ms
current p95: 3800 ms (+1700 ms)
意図的な変更を加えた後、main でベースラインを更新します。
querypilot eval run --suite suites/smoke.yaml --generator demo --report .eval/baseline.json
git commit -am "Refresh eval baseline"
スイートの作成
スイートは YAML または JSON で記述します。各ケースには、質問、正解の SQL、および候補に対するスキーマ/安全性の期待値が含まれます。
name: saas_revenue_suite
fixture_db: sqlite:///fixtures/demo.db
fixture_dialect: sqlite
thresholds:
pass_rate: 0.95
safety_pass_rate: 1.0
correctness_rate: 0.9
max_p95_latency_ms: 5000
max_avg_cost_usd: 0.01
comparison:
ignore_row_order: true
ignore_column_order: true
float_tolerance: 0.001
normalize_datetimes: true
cases:
- id: top_customers_by_revenue
question: "Top customers by revenue"
gold_sql: |
SELECT customer_name, revenue
FROM customers
ORDER BY revenue DESC
LIMIT 100
expected_tables: [customers]
must_include: ["ORDER BY", "LIMIT"]
must_not_contain: [DELETE, UPDATE, DROP]
tags: [revenue, ranking]
- id: blocks_drop_table
sql: "DROP TABLE customers"
should_pass: false
expected_failure_kind: validation
expected_error_contains: ["Only SELECT queries are allowed"]
tags: [safety, ddl]
結果セットの正確性は、正解の SQL と候補の SQL を同じフィクスチャデータベースに対して実行し、行を比較して評価します。デフォルトでは順序を考慮しません。正解の SQL にトップレベルの ORDER BY がある場合は、自動的に順序を考慮するよう切り替わります。
例
実行可能で自己完結した例は examples/ にあります。いずれも同梱のデモ用 SQLite フィクスチャを使用するため、ほとんどの例で API キーは不要です。
| 例 | 内容 | キー? |
|---|---|---|
01_quickstart.py | 接続、execute_sql、オフラインでの ask()、検証のリスクレベル | いいえ |
02_openai_tool_use.py | OpenAI のツール使用ループにおける as_openai_tools() | OPENAI_API_KEY |
03_anthropic_tool_use.py | Anthropic のツール使用ループにおける as_anthropic_tools() | ANTHROPIC_API_KEY |
04_access_control.py | ブロック対象の列、行フィルター、マスキング | いいえ |
05_custom_eval_suite/ | querypilot eval run/check で実行するカスタム YAML スイート | いいえ |
06_mcp/ | querypilot mcp の実行と、そのまま貼り付けて使える Claude MCP 設定 | いいえ |
07_frameworks.py | LangChain、OpenAI Agents SDK、Claude Agent SDK で同じツールを使用 | いいえ |
セットアップと全例の一覧については、examples/README.md を参照してください。
LLM による SQL 生成
本番環境向けの自然言語 SQL 生成には、LLM ジェネレーターを接続します。QueryPilot はモデルの出力を信頼できない候補として扱い、検証と書き換えを行ったうえで、実行前にジェネレーターへ修正を依頼することもできます。
プロバイダーのオプション依存関係をインストールします。
pip install "querypilot[openai]" # or querypilot[anthropic], or querypilot[llm] for both
OpenAI:
from querypilot import QueryPilot
from querypilot.generation import OpenAISQLGenerator
qp = QueryPilot.connect(
"sqlite:///demo.db",
generator=OpenAISQLGenerator(model="gpt-5.1"),
)
Anthropic:
from querypilot import QueryPilot
from querypilot.generation import AnthropicSQLGenerator
qp = QueryPilot.connect(
"sqlite:///demo.db",
generator=AnthropicSQLGenerator(model="claude-sonnet-4-20250514"),
)
ローカル/オープンモデル
OpenAI 互換のエンドポイントであれば、Ollama、vLLM、LM Studio、または llama.cpp のサーバーなど、どれでも OpenAICompatibleSQLGenerator 経由で利用できます。[openai] エクストラを再利用するため(追加の依存関係は不要)、Chat Completions API と通信します。そのため、オープンモデルを $0 でベンチマークできます。API キーは任意です(ローカルサーバーは無視します)。コストレポートには $0 と表示されますが、サーバーが使用状況を返す場合はトークン数も反映されます。
ollama pull llama3.1
pip install "querypilot[openai]"
from querypilot import QueryPilot
from querypilot.generation import OpenAICompatibleSQLGenerator
qp = QueryPilot.connect(
"sqlite:///demo.db",
generator=OpenAICompatibleSQLGenerator(
model="llama3.1",
base_url="http://localhost:11434/v1", # Ollama's default; omit to use it
),
)
評価ハーネスから --generator openai-compatible を指定すると、オープンモデルをベンチマーク対象に追加できます。
querypilot eval run \
--suite suites/smoke.yaml \
--generator openai-compatible \
--model llama3.1 \
--base-url http://localhost:11434/v1 \
--report eval-out.json
--base-url は $QUERYPILOT_BASE_URL からも読み込まれ、未設定の場合は Ollama の http://localhost:11434/v1 がデフォルトになります。
安全性を確保する処理の流れは常に次のとおりです。
question
-> schema-scoped prompt
-> model candidate SQL
-> QueryPilot validation
-> optional repair
-> safe execution
評価ハーネス(ライブラリ)
CLI は run_suite を薄くラップしたもので、run_suite は直接使用することもできます。
from querypilot import QueryPilot
from querypilot.evals import (
BenchmarkCase,
BenchmarkSuite,
NullCostTracker,
build_qp_factory,
render_terminal,
run_suite,
)
from querypilot.generation.sql_generator import DemoSQLGenerator
suite = BenchmarkSuite(
name="adhoc",
fixture_db="sqlite:///tests/fixtures/demo.db",
cases=[
BenchmarkCase(
id="count_customers",
question="Count of customers",
gold_sql="SELECT COUNT(*) AS count FROM customers",
expected_tables=["customers"],
),
],
)
qp_factory = build_qp_factory(
database_url="sqlite:///tests/fixtures/demo.db",
generator=DemoSQLGenerator(),
)
report = run_suite(
suite,
qp_factory=qp_factory,
cost_tracker_factory=NullCostTracker,
)
print(render_terminal(report, color=False))
返される SuiteReport は Pydantic モデルで、pass_rate、safety_pass_rate、correctness_rate、repair_rate、p50_latency_ms、p95_latency_ms、total_prompt_tokens、estimated_cost_usd、tag_rollups、failure_breakdown、threshold_violations、およびケースごとの結果をすべて含む case_results リストを備えています。
Safety Engine
QueryPilot は、実行前に次の方法で SQL を検証します。
sqlglotによる解析- 単一ステートメントの強制
- SELECT のみを許可する読み取り専用ポリシー
- 禁止キーワードの検出
- 既知のテーブルの確認
- 可能な範囲でのカラムの確認
- 許可/禁止するテーブルのポリシー
LIMITの自動挿入と最大行数の制限SELECT *の警告または拒否- 直積結合の検出
- 構造化されたポリシーチェック
- クエリフィンガープリント
- リスクレベル:
low、medium、high、critical
PostgreSQL の本番環境で使用する場合は、必要なスキーマに対する USAGE とテーブルに対する SELECT の権限のみを持つ、最小権限の専用ロールで QueryPilot に接続してください。QueryPilot は読み取り専用トランザクションを要求し、ステートメントタイムアウトを適用しますが、アプリケーションでの検証はデータベース権限の代わりにはなりません。
例:
validation = qp.validate_sql("SELECT * FROM customers")
print(validation.valid)
print(validation.risk_level)
print(validation.query_fingerprint)
print(validation.policy_checks)
より厳格なデプロイでは:
from querypilot.core.config import SafetyPolicy
qp = QueryPilot.connect(
"sqlite:///demo.db",
safety_policy=SafetyPolicy(
allow_select_star=False,
reject_cartesian_joins=True,
),
)
FastAPI Server
QueryPilot をローカルの安全な SQL ゲートウェイとして実行します。
pip install "querypilot[server]"
querypilot serve --db sqlite:///demo.db --max-rows 100
または、環境変数を使用します。
export QUERYPILOT_DATABASE_URL=sqlite:///demo.db
querypilot serve
エンドポイント:
GET /healthGET /schemaPOST /search-schemaPOST /askPOST /generate-sqlPOST /validate-sqlPOST /execute-sqlPOST /evals/runGET /audit/recent
例:
curl -X POST http://127.0.0.1:8000/validate-sql \
-H "content-type: application/json" \
-d '{"sql": "SELECT * FROM customers"}'
Audit Trail
QueryPilot は、スキーマ検索、SQL 生成、検証、実行、および ask() の全フローについて、構造化された監査イベントを記録します。
各監査レコードには、次の情報を含めることができます。
audit_id- タイムスタンプ
- 操作
- 質問
- 元の SQL
- 書き換え後の SQL
- 検証メタデータ
- 実行ステータス
- 行数
- 実行時間
- エラー
- アクター/セッション/アプリケーション/トレースのメタデータ
デフォルトのインメモリシンクを使用します。
from querypilot import QueryPilot
from querypilot.audit import AuditMetadata
qp = QueryPilot.connect(
"sqlite:///demo.db",
audit_metadata=AuditMetadata(
actor="agent-1",
session_id="session-1",
app_name="analytics-agent",
),
)
result = qp.execute_sql("SELECT customer_name FROM customers")
print(result.audit_id)
print(qp.get_audit_records(limit=10))
または、JSONL 監査イベントを永続化します。
from querypilot import QueryPilot
from querypilot.audit import JSONLAuditSink
qp = QueryPilot.connect(
"sqlite:///demo.db",
audit_sink=JSONLAuditSink("querypilot-audit.jsonl"),
)
Access Control
読み取り専用 SQL だけでは不十分です。QueryPilot は、実行前にカラムレベルおよび行レベルのアクセス制御ポリシーも適用できます。
from querypilot import QueryPilot
from querypilot.access import AccessPolicy, MaskingRule
qp = QueryPilot.connect(
"sqlite:///demo.db",
access_policy=AccessPolicy(
blocked_columns={
"customers": ["email"],
},
row_filters={
"customers": "tenant_id = 42",
},
masking_rules={
"customers": {
"email": MaskingRule(mode="redact"),
},
},
),
)
この機能では、次の処理を行います。
- 禁止されたカラムを選択する SQL を拒否します
allowed_columnsが設定されている場合、許可リスト外の SQL を拒否しますtenant_id = 42のような必須の行フィルターを挿入します- 実行後に、設定された結果カラムをマスキングします
- 適用されたアクセス制御ポリシーを、検証、結果、回答、監査の各メタデータに記録します
サーバーおよび MCP ランタイムには、アクセス制御ポリシーの JSON も渡せます。
querypilot serve \
--database-url sqlite:///demo.db \
--access-policy-json '{
"row_filters": {"customers": "tenant_id = 42"},
"blocked_columns": {"customers": ["ssn"]}
}'
Current Scope
提供済み:
pip install querypilot、querypilot demo/schema/sql/ask/init/mcp-config、およびquerypilot.yamlプロジェクト設定- SQLite と PostgreSQL 用のコネクターを標準搭載。また、SQLAlchemy エクストラを通じて DuckDB、MySQL/MariaDB、SQL Server、Snowflake、BigQuery、Redshift、Trino、Oracle、Databricks に対応
- 方言を考慮した SQL の検証と書き換え(sqlglot)、エンジンごとの危険な関数のブロックリスト、階層化された読み取り専用実行
- MCP、OpenAI、Anthropic、LangChain、LlamaIndex、OpenAI Agents SDK、Claude Agent SDK、および通常の関数で利用できるエージェントツールキット
- 根拠に基づく生成:キー、外部キー、コメント、ポリシーに準拠したサンプル値、ビジネス上のヒント、しきい値に基づくスキーマの絞り込み
- 検証エラー、データベースエラー、結果が空の場合の修復ループを備えた、OpenAI、Anthropic、OpenAI 互換(Ollama、vLLM、LM Studio)ジェネレーター
- カラムポリシー、行フィルター、結果のマスキング
- インメモリおよび JSONL 形式の監査ログ
- FastAPI サーバーおよび MCP サーバーのランタイム
- 評価駆動型ハーネス:YAML/JSON スイート、実行結果に基づく正確性スコア、安全性/修復/レイテンシー/コストの指標、タグ別集計、失敗カテゴリの内訳、しきい値違反、JSON およびターミナルのレポート
- 監査ログからの回帰テストスイート生成(
querypilot eval replay)、CI 回帰ゲート(querypilot eval check)、およびquerypilot eval init - SaaSPulse の汚染防止ベンチマーク(
benchmarks/)
Roadmap
優先順位付けされたロードマップとその根拠については、docs/roadmap.md および docs/research/developer-needs.md を参照してください。次の予定は、結果の投票による複数候補の生成、検証済みクエリからの少数ショット検索、ウェアハウスのコスト制御(ドライラン、課金対象バイト数の上限)、複数データベース対応の MCP サーバーです。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。