0sql 评测:让 AI Agent 生成 SQL 更确定更安全

0sql 用语义层把 JSON 规格编译为受治理 SQL,兼顾确定性与三层安全。
0sql 是一个位于 AI Agent 与数据仓库之间的语义层,主张不让模型直接写裸 SQL,而是让 Agent 调用 `search_fields` 发现字段、构造结构化 JSON 规格,再由引擎编译成受治理的 SQL。其核心优势有三:一是确定性,同一规格永远返回同一 SQL,便于调试、缓存与审计;二是安全性,模型级治理限制可查询字段、参数化输出消除注入、行级过滤器内嵌于模型;三是速度,示例中三字段查询规划仅需约 70 微秒。与 Cube 和 MetricFlow 相比,0sql 面向 Agent 驱动查询,表达能力更强但需维护模型同步。文章也提醒了模型漂移、字段歧义、复杂查询映射困难与托管 API 限流四类失败模式,并给出适用与不适用场景的清晰判断。
0sql 评测:让 AI Agent 生成 SQL 更确定更安全

当 AI Agent 直接从自然语言生成 SQL 时,你会面临两个问题:查询构造的非确定性,以及数据库的直接暴露。0sql 把自己定位为一个语义层,坐落在 Agent 和数据仓库之间,将业务术语规格翻译为受治理的 SQL 语句。
据 0sql 官方文档和 Hacker News 上的讨论,其核心思路是:与其让 Claude 或 Copilot 直接写裸 SQL,不如让 Agent 调用一个 plan_query 接口,传入类似 {projections: [{field: "Web Net Paid"}]} 的规格。引擎返回一条基于治理模型规划的 SQL 语句。同样的规格,永远返回同样的语句。
纯语义到 SQL 的工作方式
0sql 并不直接解析自然语言。它期望的是结构化输入:一个 JSON 规格,通过语义名称引用字段、过滤器和聚合。Agent 的工作是把用户意图映射到这个规格上,引擎的工作是把规格编译成 SQL。
完整流程如下:
- Agent 收到用户查询:“show emea profit last 30 days”
- Agent 调用
search_fields工具查找匹配的度量和维度 - Agent 构造规格:
{projections: [{field: "Profit"}], filters: [{field: "Region", operator: "=", value: "EMEA"}, {field: "Date", operator: ">=", value: "30d"}]} - Agent 用该规格调用
plan_query - 引擎返回基于语义模型规划好的 SQL
语义模型定义了度量(聚合)、维度(分组键)和连接关系。引擎将规格翻译为遵守这些定义的 SQL 语句。如果模型规定“Profit”是连接到 region.name 的 sum(sales.profit),引擎就会生成相应的 SELECT、JOIN 和 WHERE 子句。
语义模型(Semantic Model) 是 0sql 的核心构件,本质上是一份以 YAML 或 JSON 描述的业务语义契约。它把数据仓库中散落的物理表和列,映射为业务人员熟悉的度量、维度、连接与过滤规则。典型定义包括:某个度量的聚合表达式(如 sum(sales.profit))、某维度的来源列(如 region.name)、表之间的连接键,以及可附加在查询上的行级安全条件。模型通常受版本控制,存储在 Git 仓库中,因此每次 SQL 规划都能追溯到具体的模型版本。它带来的直接收益是把“什么是利润”“利润属于哪个区域”这类业务判断从 Agent 的提示词中抽离出来,固化在可评审、可测试的模型里,避免同一术语在不同对话中被解释成不同 SQL。
三层安全边界
安全模型分为三层,这是 0sql 最值得关注的设计。
模型级治理:语义模型定义了哪些字段存在以及如何聚合。如果某个字段不在模型中,Agent 就无法查询它。这防止了 Agent 访问原始列或构造任意连接。
参数化输出:引擎返回的 SQL 中,用户提供的值以占位符形式存在。Agent 从不把字符串插值进 SQL。这在查询构造层消除了注入风险。
行级安全:模型可以编码行级过滤器。如果用户只能看到自己区域的数据,模型会在每个查询中包含该约束。Agent 不需要知道这些规则的存在。
参数化查询(Parameterized Query) 是指 SQL 语句中的用户输入不直接拼接进字符串,而是以占位符(如 ? 或 $1)出现在语句模板中,实际值在执行阶段由数据库驱动单独传入。传统 SQL 注入之所以成立,是因为攻击者能通过闭合引号并追加 OR 1=1 等片段改变语句结构;参数化后,值始终被当作数据而非代码解析,结构由规划器固定,注入面被消除。0sql 在引擎内部即完成这一转换:Agent 传入的 value: "EMEA" 只会落到绑定参数里,不会出现在返回的 SQL 文本中,因此 Agent 即便被恶意提示诱导,也无法通过值字段改写查询语义。
确定性与缓存带来的工程价值
引擎保证同样的规格产生同样的 SQL。这一点在三个场景中至关重要。
调试:如果 Agent 生成了坏查询,你可以通过重跑规格来复现它,不需要重放整个 LLM 对话。
缓存:你可以按规格哈希缓存 SQL 语句。如果 Agent 问了同样的问题两次,可以跳过规划直接返回缓存的语句。
审计:你可以记录规格而不是 SQL。规格更小、更可读,而且不会泄露 schema 细节。
规划速度很快。示例中三字段查询耗时 70 微秒,足以放在 Agent 循环的热路径上。
与 Cube 和 MetricFlow 的对比
0sql 面对的是 Cube 和 MetricFlow 这两个语义层竞品。关键差异在于定位不同。
| 特性 | 0sql | Cube | MetricFlow |
|---|---|---|---|
| 主要用例 | Agent 驱动查询 | 嵌入式 BI 仪表板 | dbt 原生指标 |
| 查询接口 | JSON 规格 → SQL | GraphQL、REST、SQL | 带指标引用的 SQL |
| 确定性保证 | 显式(同规格同 SQL) | 隐式(查询计划缓存) | 隐式(宏展开) |
| 安全模型 | 模型级 + 行级 | 数据访问策略 | dbt 暴露 + 授权 |
| Agent 集成 | CLI + HTTP API 工具调用 | REST API(需包装) | SQL 接口(无工具边界) |
| 表达能力 | 完整 SQL 特性集 | 受 GraphQL schema 限制 | 受 dbt 宏系统限制 |
从表格可以看出,0sql 的表达能力更强,因为它不约束查询形态。Cube 的 GraphQL schema 限制了你问什么,MetricFlow 的宏系统限制了指标如何组合,而 0sql 可以把任意规格编译为 SQL,只要字段存在于模型中。
语义层(Semantic Layer) 是位于数据仓库与上层应用之间的抽象层,用业务术语而非物理表列来定义查询接口。它的价值有三:一是治理,把指标口径、行列权限集中管理;二是复用,同一指标在 BI、Agent、报表中保持定义一致;三是解耦,物理 schema 变更时只需调整语义模型,上层查询不受影响。Cube 和 MetricFlow 属于较早一代语义层,主要服务嵌入式分析、BI 仪表板或 dbt 指标工作流,查询入口是 GraphQL、REST 或带指标引用的 SQL。0sql 沿用同一理念,但把调用方从人类分析工具换成了 AI Agent,因此接口设计为工具调用友好的 JSON 规格,并显式承诺确定性输出。
CLI 与 Agent 集成模式
0sql 随附一个 CLI(zsql),封装了 HTTP API,专为能执行 shell 命令的编码 Agent 设计:
zsql sql --expr "web net paid, web sold date, net paid"
CLI 把 SQL 返回到 stdout,Agent 可以将其管道传给查询执行器或记录审查。
对于使用函数调用(OpenAI、Anthropic)的 Agent,你可以把 HTTP API 暴露为工具。Agent 调用 search_fields 发现可用字段,再调用 plan_query 生成 SQL。整个过程中,Agent 从不直接写 SQL。
架构形态
引擎是无状态的。它从 Git 分支(存储在 0sql 云中)读取语义模型,按需规划查询。你可以通过把 CLI 指向自己的模型仓库来自托管。
架构链路如下:
Agent (Claude)
│ 1. search_fields("profit")
▼
0sql API (stateless)
│ 2. 从 Git 加载语义模型
▼
模型仓库 (YAML/JSON)
│ 3. plan_query(spec)
▼
SQL 生成器
│ 4. 返回 SQL
▼
Agent (执行 SQL)
语义模型定义四类要素:度量(如 sum(profit)、count(orders))、维度(如 region.name、date)、连接关系、以及行级安全过滤器。引擎只编译这些,不执行查询。Agent 负责把 SQL 跑在数据仓库上。
需要警惕的失败模式
0sql 并非万能,文档明确列出了几种失败模式。
模型漂移:如果语义模型与仓库 schema 脱节,引擎会生成无效 SQL。你需要一条 CI 流水线来验证模型与仓库的一致性。
字段名歧义:如果模型定义了两个相似名称的字段(“Profit”和“Net Profit”),Agent 可能选错。search_fields 工具会返回多个匹配,但最终选择权在 Agent。清晰的命名约定是必需的。
复杂查询:引擎为任意规格生成 SQL,但复杂查询(窗口函数、递归 CTE)可能无法干净地映射到语义模型。你可能需要定义自定义度量或回退到裸 SQL。
限流:HTTP API 由 0sql 托管。如果超出速率限制,查询会失败。你需要重试逻辑或自托管部署。
模型漂移(Model Drift) 指语义模型的定义与实际数据仓库 schema 之间逐渐产生偏差。常见诱因包括:上游表结构变更、列重命名、聚合口径调整、分区字段替换,而语义模型未同步更新。漂移不会在模型加载时报错,而是在查询执行时才暴露为无效 SQL 或错误结果。防御手段包括把模型校验纳入 CI,在每次仓库 schema 变更后自动比对待查字段是否存在、连接键类型是否匹配;同时在生产环境记录规划失败率与 SQL 执行错误,将异常规格回灌到测试用例中。对依赖 0sql 的 Agent 管道而言,模型漂移是最容易被低估却被高频触发的故障源。
技术判断:什么时候该用 0sql
适合使用的场景:
- 你在构建 Agent 驱动的分析,需要防止 SQL 注入
- 你想要确定性的查询生成,用于缓存和调试
- 你需要在语义层强制行级安全
- 你在集成能调用 HTTP API 或 shell 命令的编码 Agent
应该避免的场景:
- 你需要完整的 BI 平台,含仪表板和可视化(用 Cube 或 Metabase)
- 你的查询太复杂,无法在语义模型中表达(用带参数化的裸 SQL)
- 你需要亚毫秒级查询规划(HTTP 往返增加延迟)
- 你想自托管但不想管理模型仓库
核心价值是在查询构造层的确定性和安全性。如果 Agent 直接写 SQL,你有注入风险和非可复现的查询。如果 Agent 使用 0sql,你得到的是受治理的 SQL 和清晰的审计轨迹。代价是表达能力:你只能查询语义模型定义的内容。
对于正在构建 Agent 数据管道的团队,0sql 提供了一条介于“让 LLM 裸写 SQL”和“完整 BI 平台”之间的中间路径。它的取舍很清晰,适合那些把安全和可审计放在首位的场景。
参考来源
相关推荐

Claude Code免费不限量方案:Agnes AI+CC Switch配置指南
无需付费订阅,用免费AI平台Agnes AI配合开源工具CC Switch为Claude Code提供后端,实现文本、图片、视频模型不限量免费调用。本文梳理安装配置全流程、实测效果与使用边界,帮助开发者低成本上手Claude Code。

国内新手零成本上手Claude Code完整指南
面向国内新手的 Claude Code 入门指南:两种安装方式(命令行与 IDE 插件)、用国产免费模型 LongCat 替代官方 API 的完整配置步骤,以及用自然语言开发小工具的实操演示与技巧。

当NSA都介入:开源CVE与API密钥劫持背后的AI供应链危机
一天内多个开源项目曝出严重CVE,PHP漏洞惊动FBI,Railway与OpenCode遭入侵致API密钥被窃。本文拆解漏洞窗口、AI加速利用与API密钥黑市背后的AI供应链危机,并给出开发者防御清单。