AI Skills(智能体技能)

数据分析智能体入门:自然语言转 SQL 的落地与校验

“SELECT 看着没问题,执行也通过了,但数不对。”这是 NL2SQL 项目里最让人头疼的情况。比如业务方问“上月新增付费用户数”,AI 生成的 SQL 语法完全正确,甚至能跑出结果——但它把“付费”理解成了“只要下过单就算付费”,没有排除当月退款用户,也没有剔除内部测试账号。结果页面上的数字和 BI 报表对不上,业务方对整个智能体开始怀疑。

这个问题的本质,是 NL2SQL 落地要跨过两个层次:语法层和语义层。语法层是 SQL 能不能解析、能不能执行;语义层是 SQL 反映的是不是业务方真正想要的口径。大模型对前者已经做得不错,但后者才是决定项目能不能上线的关键。下面按四步拆开:元数据准备、检索配置、SQL 校验、结果验证,每一步都给出可检查的验收标准和失败时的回退方案。

先把问题拆开:语法层和语义层

建一个数据分析智能体,本质上是在“用户问题”和“数据库里的答案”之间架一条链路:用户用自然语言提问,系统把问题转成 SQL,执行后返回结果。这条链路上有四个环节容易出问题。

第一个环节是上下文不够。模型不知道库里有哪些表、哪些字段、字段代表什么业务含义,只能靠猜。第二个环节是检索不准。表太多、字段太多,一次塞不进 prompt,但召回的元数据又没覆盖真正需要的那张表。第三个环节是校验缺失。生成的 SQL 能跑通,但 WHERE 条件、JOIN 关系、聚合粒度全都不对。第四个环节是结果没人对。执行成功就算完事,数字和 BI 报表对不上没人发现。

数据分析智能体四步落地流程图

把这四个环节分别卡住,就是下面的四步。

第一步:元数据准备——别让模型“猜字段”

模型不是数据库管理员,它不会主动知道 user_table 里的 status 字段到底有哪几种取值,也不会知道“付费用户”在你的业务里特指 payment_status = 'paid' 且 refund_flag = 0 的用户。这些信息必须提前准备好,作为上下文喂给模型。

准备的内容分三类。第一类是表结构元数据,包括表名、字段名、字段类型、主键外键关系,以及每个字段的中文注释。第二类是业务语义,包括指标定义、枚举值含义、字段之间的业务关联。比如 order_amount 的单位是“分”还是“元”,created_at 是 UTC 还是北京时间,这些细节模型猜不准。第三类是口径规则,也就是业务方对“活跃”“新增”“付费”这些词的精确定义。

一个实用的做法是把这些信息沉淀成 YAML 或 JSON 文件,作为智能体的固定上下文:

纯文本
tables:
  - name: orders
    comment: "订单主表,每行一笔订单"
    columns:
      - name: user_id
        type: bigint
        comment: "下单用户ID,关联 users.id"
      - name: order_amount
        type: decimal(10,2)
        comment: "订单金额,单位:元,已扣除优惠"
      - name: status
        type: varchar(20)
        comment: "订单状态:pending/paid/cancelled/refunded"
    business_rules:
      - name: "付费订单"
        definition: "status = 'paid' 且不存在同 order_id 的 refunded 记录"

这一步的验收标准很直接:挑 20 个业务方最常问的问题,逐个人工判断“给模型的元数据是否足以回答这个问题”。如果 20 个里有 3 个以上需要模型额外猜测,就说明元数据不够,回退方案是先把这 3 个问题涉及的字段注释和业务规则补上,再继续往下走。

第二步:检索配置——向量加关键词的混合召回

当库里有上百张表、上千个字段时,不可能把所有元数据全塞进 prompt。这时候需要一个检索环节,从元数据库里挑出和当前问题最相关的表和字段。这里建议用混合检索:向量检索负责语义相似,关键词检索负责精确匹配。

向量检索解决的是“用户说客户,表名叫 customer”这种同义表达问题。先把每张表的描述、每个字段的注释嵌入成向量,再把用户问题也嵌入,计算相似度召回。但向量检索有个毛病:它可能把语义相近但完全无关的表也召回来,还会漏掉精确的枚举值或字段名匹配。

关键词检索补的就是这个短板。用户问“订单状态是 pending 的有多少”,关键词检索可以直接命中 status 字段注释里的 pending。两者结合,才能保证召回既不错也不漏。一个简单的混合策略是把两路召回结果做加权融合,或者先关键词过滤再向量排序。

具体实现上,可以参考 AgentNLQ 这类系统的思路:先从用户问题里提取可能和表、列、取值相关的实体,把这些实体嵌入后走向量检索,同时用原始关键词做精确匹配,最后合并去重。下面是一段简化的混检索示意代码:

纯文本
def hybrid_retrieve(question: str, metadata_index, top_k: int = 10):
    # 关键词精确命中字段名和注释
    keyword_hits = metadata_index.keyword_search(question, limit=top_k)
    # 向量检索召回语义相近的表和字段
    vector_hits = metadata_index.vector_search(question, limit=top_k)
    # 合并:关键词命中排前面,向量结果去重补后面
    merged = {hit.id: hit for hit in keyword_hits}
    for hit in vector_hits:
        if hit.id not in merged:
            merged[hit.id] = hit
    return list(merged.values())[:top_k]

这一步的验收标准是召回命中率。同样拿那 20 个典型问题测试,看目标表和字段是否稳定出现在 top-10 召回结果里。如果命中率低于 80%,回退方案有两个方向:一是加大 top-k 再看是否只是排序问题;二是检查元数据里的注释是否太笼统,导致向量相似度拉不开差距。先把注释写具体,再调检索参数。

第三步:SQL 校验——两道关卡拦下“看着对”的坏查询

模型生成 SQL 之后,不能直接扔给数据库执行。至少要过两道关卡:语法校验和口径校验。

语法校验简单直接。先把 SQL 交给解析器,比如 PostgreSQL 的 EXPLAIN 或者 MySQL 的 EXPLAIN FORMAT=JSON,在只读库上跑一遍。语法错误、表不存在、字段不存在这类问题在这一步就能拦住。注意这里说的是“在只读库上跑”,不是直接在生产库上执行。

口径校验才是重点。语法对的 SQL 不代表口径对。一个常见做法是让模型在生成 SQL 的同时输出一段口径说明,然后用规则或另一个 LLM 调用对拍。校验的内容包括:

  • WHERE 条件里的过滤是否符合业务规则定义
  • JOIN 是否用对了关联键
  • 聚合粒度是否正确,有没有把订单级和用户级混在一起
  • 时间范围是否符合问题中的“上月”“近 7 天”等表述
  • 有没有把测试账号、内部账号排除掉

下面是一个简化的校验提示词结构:

纯文本
请检查以下 SQL 是否符合业务规则:

问题:上月新增付费用户数
业务规则:
- "付费用户"定义为存在 status='paid' 且无退款记录的订单
- 时间范围使用 order 创建时间
- 排除 user_type='internal' 的测试账号

生成的 SQL:
SELECT COUNT(DISTINCT user_id) FROM orders
WHERE created_at >= '2025-06-01'
  AND created_at < '2025-07-01'
  AND status = 'paid'

请逐条判断,并指出不符合规则的地方。

这一步的验收标准是非法 SQL 拦截率和口径偏离检出率。准备 30 个含错误 SQL 和正确 SQL 的混合样本,看校验环节能不能把有问题的都拦下来,同时不误伤太多正确 SQL。如果拦截率上不去,回退方案是缩小校验范围,先只做最容易出错的几类检查:时间范围、枚举值、测试账号过滤、金额单位。把规则写死成代码或严格的 prompt 约束,比让模型自由判断更可靠。

SQL 语法与口径双层校验流程图

第四步:结果验证——抽样核对,别只信执行成功

SQL 执行成功只代表语法没问题,不代表答案对。结果验证要做的,是把智能体返回的数字和已知正确的参照值做对比。

一个低成本的做法是准备一组“黄金问题集”:这些问题在业务方那里有已经确认的标准答案,比如“上月总订单数”“本月活跃用户数”。每次上线或调整 prompt 后,跑一遍黄金问题集,看智能体的输出和标准答案的偏差。偏差超过阈值,比如 1%,就说明检索、生成或校验的某个环节出了问题。

另一个做法是抽样核对。对于线上真实用户的问题,定期抽几条,人工看生成的 SQL 和返回结果是否合理。不需要抽很多,每天抽 5 到 10 条,积累一周就能发现不少问题。

这一步的验收标准是黄金问题集通过率。如果 20 个黄金问题里 18 个以上和标准答案一致,才算基本可用。达不到的话,回退方案不是继续调 prompt,而是从上三步往回排查:先看结果不对的问题,是 SQL 校验没拦住,还是检索没召回正确的表,还是元数据本身就没定义清楚。定位到哪一步,就回退到哪一步修。

常见问题排查

落地过程中有几个问题会反复出现,提前知道排查方向能省不少时间。

字段幻觉:模型生成的 SQL 里出现了不存在的字段或表。原因是检索环节没召回目标表结构,或者元数据里字段注释太模糊,模型自己“补”了一个。排查方向是检查召回日志,看目标表有没有出现在上下文里;如果没出现,问题在检索;如果出现了但模型还是编造,问题在元数据质量和校验环节。

口径不一致:同一个问题,不同时间问答案不一样。原因是 prompt 里的业务规则不够明确,模型每次理解有偏差。排查方向是检查口径校验环节有没有生效,以及业务规则描述里有没有歧义词,比如“活跃”指的是登录还是下单。

权限过大:智能体连的是生产库,且使用了一个有写权限的账号。这是最危险的问题。解决方式是只读沙箱约束:为智能体单独创建只读账号,限制在必要的表范围,禁止 INSERT、UPDATE、DELETE、DROP 等写操作;同时在执行层做白名单校验,拦截不在允许列表里的 SQL 类型。即使模型生成了一条 DELETE FROM orders,沙箱账号也没有权限执行。

问题现象常见原因排查方向
SQL 里出现不存在的字段检索未召回目标表,模型幻觉补全检查召回日志,确认元数据是否进入上下文
数字和 BI 报表对不上业务口径定义不明确,模型理解偏差检查口径规则描述是否有歧义,校验环节是否生效
同一问题答案不稳定prompt 温度过高或规则不完整降低温度参数,补充明确的过滤规则
执行报错表名或字段名写错、SQL 方言不匹配检查元数据中的表名是否与实际库一致,确认方言设置

落地建议:从最小可行配置开始

不建议一上来就追求完美的语义层和复杂的校验链路。先做最小可行版本:挑一个业务域,准备 15 到 20 张核心表的元数据,配置好混合检索,加一道语法校验和两三行最核心的口径规则,用只读账号连接,然后跑黄金问题集。跑通了再扩表、加规则、上更细的验证。

NL2SQL 能不能在生产环境用起来,关键不在于模型写得有多快,而在于你相不相信它给出的数字。四步走下来,每一步都有一个明确的验收点:元数据够不够、检索准不准、校验拦不拦得住、结果对不对得上。把前三个环节做扎实,第四个环节的数字才会慢慢变得可信。

热门话题

52okp 是一名关注人工智能、开源软件与效率工具的技术内容创作者,长期实践 Stable Diffusion、ComfyUI、AI 智能体、MCP、Codex 和各类开源项目。通过实际安装、配置与测试,整理可复现的操作教程、问题排查方法和工具使用经验。

登录用户才能发表评论! 登录账户

取消回复

评论列表 (1条):

加载更多评论 Loading...

延伸阅读:

搭建本地知识库问答:文档切分与检索效果怎么调

本地知识库问答答非所问,未必是模型不够强:如果召回片段本身没有答案,问题多半出在文档切分或检索;若片段相关,才该检查提示...

52okp
2026-10-02

给 AI 智能体设置工具权限:只读操作与人工确认

智能体明明只是整理文件,却把原文件直接覆盖;一句不完整的指令,就可能让修改系统状态的命令被悄悄执行。光靠提示词叮嘱“谨慎...

52okp
2026-10-01

Langflow 适合怎样的 AI 工作流原型?从首次配置到运行验证

想验证一个 AI 工作流思路,往往没动手就被搭环境、写胶水代码、调试输入输出耗掉半天。Langflow 这个开源、基于 ...

52okp
2026-10-11

用 7-Zip 分卷压缩并校验大文件:设置分卷大小、密码和解压检查

大文件受网盘、邮箱附件或 FAT32 单文件限制时,7-Zip 可按指定大小分卷,并为 7z 格式设置 AES-256 ...

52okp
2026-10-04

NVIDIA SkillSpector:安装 AI 智能体技能前,先用它扫出提示注入与供应链风险

给 Claude Code 或 Codex 装社区技能时,人们常只看描述和星标,却忽视技能会在智能体上下文中继承 API...

52okp
2026-10-08
    返回顶部