PostgreSQL Field Guide

Text-to-SQL 生产模式

把自然语言查询变成受约束、可解释、可拒绝的数据库操作

Text-to-SQL 的目标不是“尽量生成一条能跑的 SQL”,而是只在证据、权限和成本边界清楚时执行正确查询;其余请求应澄清或拒绝。

推荐执行链

自然语言问题
  → 解析业务实体、指标、时间范围和期望粒度
  → 检索版本化 schema / metric 契约与少量已验证示例
  → 生成结构化查询计划和参数,不直接执行自由文本
  → SQL AST 校验、对象/函数白名单、权限与成本检查
  → 受限角色 + 只读事务 + 超时 + 结果上限
  → 返回结果、口径、SQL 指纹、截断状态与可解释错误

模型输入至少包括:schema 版本、表/列语义、主外键、枚举值、时区、金额单位、软删除规则、租户边界、已批准指标定义和允许查询的对象。不要把整个数据库 DDL、示例客户数据或凭据无差别塞进上下文。

结构化工具优先

对常见分析请求,优先让模型生成领域参数:

{
  "metric": "paid_order_revenue",
  "time_range": { "start": "2026-07-01", "end": "2026-08-01" },
  "group_by": ["day"],
  "filters": [{ "field": "region", "op": "eq", "value": "east" }],
  "limit": 100
}

由服务端把 metric、字段和操作符映射到已审查 SQL。只有长尾探索才进入自由 SQL 通道;该通道仍必须解析 AST,不能用正则判断“以 SELECT 开头”。CTE、可写 CTE、函数、COPY、多语句和注释混淆都会绕过天真的字符串检查。

数据库执行封装

BEGIN READ ONLY;
SET LOCAL statement_timeout = '3s';
SET LOCAL lock_timeout = '500ms';
SET LOCAL idle_in_transaction_session_timeout = '5s';

-- 由策略层批准的单条参数化 SELECT;服务端强制结果行/字节上限
SELECT date_trunc('day', paid_at) AS day, sum(total_cents) AS revenue_cents
FROM analytics.paid_orders
WHERE tenant_id = $1
  AND paid_at >= $2
  AND paid_at < $3
GROUP BY 1
ORDER BY 1
LIMIT 100;

COMMIT;

READ ONLY 是纵深防御,不是完整沙箱:仍应只允许受信函数和对象,以低权限专用角色执行,并由服务端绑定 tenant、环境和参数。模型不能传入连接字符串、role 或 search_path

执行前检查

  1. 只允许一个语句和允许的 AST 节点;拒绝 DDL/DML、COPY、任意函数调用和系统管理对象。
  2. 所有字面值转为绑定参数;标识符只能来自 schema 契约白名单。
  3. 对高成本候选运行 EXPLAIN (FORMAT JSON),检查访问对象、估算行数和总成本;估算只是信号,不能保证运行时间。
  4. 强制时间范围、行数/字节上限和最大 join 数;大导出走独立异步产品能力。
  5. 敏感列在策略层拒绝或映射为已脱敏视图,不依赖模型“记得不要选”。
  6. tenant 条件由数据库 RLS 或服务端模板注入,不能由用户问题决定。

正确性与拒答

查询能执行不等于答案正确。评估集应覆盖空结果、重复 join、时区边界、NULL、退款/取消、迟到数据、权限隔离和口径歧义。对每个问题同时断言:允许/拒绝决策、结果集、访问对象、最大成本与解释文本。

以下情况应澄清而不是猜测:指标有多个业务定义;日期缺少时区或年份;实体名称匹配多个 ID;请求要求不存在的历史快照;schema 版本与部署不一致。

不要自动修复并无限重试

语法错误最多基于结构化错误做有限重生成。57014(超时/取消)应缩小请求或转异步;4000140P01 只在整个事务可安全重放时重试。始终保留原请求、schema 版本、查询指纹与最终决策。

进一步阅读:PostgreSQL 18 事务 READ ONLY 语义错误码附录

Last updated on

On this page