站内精选

一句话结论

给 AI 一个只允许 SELECT 的数据库账号,再配一份表字段白名单提示词,它就能自己写查询、产出可审的接口和权限说明。

这篇解决什么问题

智能体接进业务之后,最常见的翻车不是它答得慢,而是它被问「上个月华东退款率多少」时开始编数字。要让它真去查库,你又不敢直接给一个能写能删的账号。

这篇讲的就是这条边界怎么划:接口只读、字段白名单、口径写在提示词里。适用的情况是内部业务数据查询、表结构明确、量级在单库几张表以内。

不适用的情况也很明确:要跨库联邦查询、要写入或回写状态、或者敏感字段没有视图层做脱敏的库,先别急着开接口。

开始前要准备什么

  • 一个能建账号的 MySQL 或 PostgreSQL 测试库,云上最小规格就够
  • Dify 社区版或扣子个人版,两者都有免费额度,调通阶段不用付费
  • 目标库的表清单和字段注释,没注释得自己补,这步最花时间
  • 10~20 条真实问句样例,用来验证生成的 SQL 对不对
  • 首次跑通通常 1~2 小时,写权限说明再加 20 分钟左右

具体怎么做

第 1 步 · 把表结构摘成白名单

很多人上来就把整个库的 CREATE TABLE 全贴给模型,字段一多它就开始编字段名。正确做法是先按问题域切片,只留三五张表。

你是数据接口设计助手。下面是一个业务库的表结构片段,请帮我做三件事:
1. 只保留与「订单、退款、商品」三类问题相关的表和字段,其余标注为「不开放」;
2. 给每个保留字段写一句话中文说明和示例值格式(例如订单号形如 OD202405xxxx);
3. 输出一张 Markdown 表格,列为:表名 | 字段名 | 类型 | 中文含义 | 是否可查询。
注意:金额字段如果是分为单位的整数,请在含义里写明单位;不要输出任何真实数据,示例值一律用化名。
表结构片段如下:
[粘贴字段清单或建表语句]

预期产出:一张三十行左右的字段白名单表,后面直接当系统提示词的素材用。

第 2 步 · 建一个只能读的账号

权限这件事不能靠提示词兜底。模型被一句「帮我清一下重复数据」带偏的概率不低,账号层的授权才是最后一道闸。

我要为一个只读查询账号授权,账号名 reader_agent,只能访问 sales 库里的 orders、order_items、refunds 三张表。数据库是 PostgreSQL 15,同时请给出 MySQL 8 的等价写法。
请输出:
1. 建账号语句,密码用占位符 <PASSWORD>;
2. 只授予 SELECT 的授权语句,精确到表级,不要给多余的库级权限;
3. 语句超时 10 秒、单次返回行数上限 5000 的配置写法(PostgreSQL 用角色级参数,MySQL 说明 max_execution_time 与 LIMIT 的配合);
4. 一段验证语句,用来确认这个账号执行 UPDATE 会被拒绝。
每条语句后面加一行注释,说明它拦住的是什么风险。

预期产出:一段可直接执行的授权脚本,加一条能自证的验证语句。跑完你会看到 UPDATE 被数据库直接打回。

第 3 步 · 写系统提示词

智能体能不能稳定不写坏 SQL,八成看这段提示词。我习惯把约束写成硬性条款,而不是「请尽量」这种软话。

你是一个只读数据查询助手,服务于内部业务分析。你的唯一职责是把中文问题翻译成一条 SELECT 查询,并解释结果。
硬性约束:
1. 只能输出 SELECT,禁止 INSERT/UPDATE/DELETE/DROP/ALTER/TRUNCATE/GRANT 以及任何写操作;
2. 只能查询白名单内的表和字段,白名单如下:[粘贴第 1 步的表格];
3. 手机号、身份证、详细地址这类字段一律不查,需要地域时改为按省份或城市聚合;
4. 时间范围必须显式写进 WHERE,用户没说就默认最近 30 天,并在回答里说明;
5. 聚合查询带 LIMIT 5000,明细查询带 LIMIT 200;
6. 字段含义不清时先提问,不要猜。
输出格式:
– 先给一句自然语言结论,含数字和时间范围;
– 再给一个 sql 代码块;
– 最后列 2~3 条口径说明,例如「退款率=退款单数/订单数,按支付时间归属月份」。
用户问题:{{query}}

预期产出:一段三百字上下的系统提示词,粘进 Dify 的智能体编排或扣子的角色设定里即可生效。

第 4 步 · 把执行做成一个工具

让模型只负责写 SQL,执行交给后端接口,这是我在实操中反复确认过的一条分工。模型碰不到连接串,出错面小很多。

我有一个 FastAPI 服务,要提供一个只读查询接口 POST /query,请求体 {“sql”: “…”},用 reader_agent 账号连库,返回 {“columns”: […], “rows”: […], “row_count”: n}。
请帮我写两部分:
1. 接口实现代码。要求:只接受以 SELECT 开头的 sql 字段,正则粗筛之后仍然交给数据库权限兜底;执行前设置 10 秒超时;返回行数超过 5000 时截断并标记 truncated=true;异常统一返回 {“error”: “…”},不要把数据库原始报错抛给调用方。
2. 一段给智能体看的工具描述,中英各一版,说明什么情况下该调用它、sql 参数怎么填、什么情况下不要调用(比如问题里要求修改或删除数据)。

预期产出:一个能跑的单文件接口,加一段工具描述。把它填进 Dify 的自定义工具或扣子的插件配置,就能开始联调。

第 5 步 · 补一份权限说明

接口给出去,总得有人能看懂它开了多大的口子。这份文档我是最后写的,但它是交付物里最容易被忽略、又最容易被追问的部分。

根据下面三份材料,写一份《只读查询接口权限说明》,读者是业务负责人和运维同事。
材料一:字段白名单表格;材料二:建账号与授权 SQL;材料三:系统提示词。
文档结构:
– 开头一句话说明这个接口能做什么、不能做什么;
– 表 1:开放的表和字段,标注敏感字段是否已排除;
– 表 2:账号权限清单,写清能 SELECT 哪些表、有无写权限、超时与行数上限;
– 一节「发现异常怎么办」,给 3 条可操作的处理动作;
– 一节「变更记录」,留空表格即可。
语言平实,不要用「赋能」「闭环」这类词。

预期产出:一页 A4 左右的权限说明,能直接放进内部文档库,评审时基本不用返工。

实测记录

项目 实测情况
首次跑通耗时 约 1.5 小时,其中半小时花在补字段注释
接口响应 单表聚合通常 1 秒内返回,三表关联约 2~3 秒
与手工对比 同一个退款率问题,手工取数约 10 分钟,接口答对时 20 秒内出结果
返工情况 前两版生成的 SQL 漏了时间过滤,加上「未指定默认 30 天」后稳定
成本 云上最小规格测试库按量计费,调通阶段开销很低

有一点要提醒:接口答对的前提是问题本身够清楚。问「最近生意怎么样」这种,它给出的 SQL 大概率不是你想要的。

最容易错的 3 个地方

  1. 只靠提示词约束权限。我第一版没建只读账号,结果测试时模型真的生成了一条 DELETE,好在只是演练库。纠正办法很简单:账号层先收口,提示词只当第二道。
  2. 把整库表结构一次性塞进上下文。字段超过几十个之后,模型开始凭空造字段名,SQL 报错率明显上升。按问题域切成三五张表,白名单之外明确写「不开放」,稳定性立刻不一样。
  3. 不给时间和口径。问「退款率多少」,模型按自然月算,业务按支付时间归属月份,两边数字对不上,还得回头解释。把默认时间窗写进提示词,并强制输出口径说明,这类扯皮能少一大半。

可复用的东西

把上面五段提示词串起来,其实就是一条流水线:表结构精简、授权脚本生成、系统提示词、接口与工具描述、权限说明,每段都能单独拿出来复用。

换一个库、换一个业务域,改的只是白名单内容和问句样例,其余结构不用动。我个人习惯把这五段存成一个文本文件,下次直接从第 2 步开始。

只读接口这件事,难点从来不在写 SQL,而在你敢不敢把边界说清楚。边界写明白了,智能体反而比人更守规矩。

你手上那个库,最想让智能体先查的是哪张表?

常见问题解答

为什么不直接把数据库连接串给 Dify 或扣子里的智能体?

连接串给出去,等于把写权限也一起交出去了,模型被话术带偏时没有任何兜底。正确做法是自建一个只读接口,智能体只调用这个接口,账号权限和超时都由后端控制。

表里如果有手机号、身份证这类字段怎么办?

在提示词的白名单里直接排除,不让模型有机会选择。如果业务确实需要地域分布,就额外建一个按省市聚合的视图,让模型只能查视图,查不到明细。

接口跑起来后发现 AI 生成的 SQL 经常报错,从哪查起?

先看字段注释是不是缺失,模型在含义模糊时最容易猜错字段名;再看有没有在提示词里明确时间范围默认值。这两处补上,报错率通常能降下来一大截。

小程序阅读免费
微信扫码进入小程序,按岗位找 AI 实操步骤
微信扫码进小程序
按岗位找 AI 实操步骤 · 提示词可收藏

发表回复

后才能评论