Agent 应用开发会员账号
知识目录选择核心方向与细分内容
知识单元 23高级实现约 18 分钟

理解 → 实现 → 排错 → 取舍

自然语言查询的口径、粒度与执行边界

考察语义层、受控 SQL、只读执行和结果复核。

Text-to-SQL司库权限

知识内容核对 2026-10-03 · 原题来源核对 2026-10-02

这个知识点,你想学到哪一步?

按当前基础选择起点,也可以依次深入。遇到不熟悉的概念,先回到核心原理;完成后用知识练习检查理解。

先理解

刚接触这个知识点

补齐先备概念,读原理与反例,再用自己的话解释为什么。

从核心原理开始 →

再实现

准备把原理写进代码

理解实现步骤与边界,完成小任务,对照验收要求检查结果。

查看代码示例 →

会排错

需要处理故障与条件变化

沿连续追问定位失效前提,再比较迁移案例,说明方案应如何调整。

沿问题继续深入 →

能取舍

需要设计或评审方案

结合工程推演与资深自评标准,解释方案的适用条件、代价和替代选择。

分析工程场景 →
知识单元目录

LEARN · PRACTICE · REFLECT

知识学习与个人记录

我的笔记与复习 ↗

先沿着原理、问答和迁移案例阅读。需要检查理解时,再切换巩固练习或展开个人记录。

作答与个人记录

每次修改后的提交会保留为独立历史。掌握程度由你对照标准自评。

核心知识 · 自然语言查询的口径、粒度与执行边界

先理解核心原理

先备概念:SQL JOIN 与聚合、数据库权限、指标与实体建模

SQL 可运行只证明语法与执行成立;答案正确还要求实体、粒度、时间和权限匹配用户意图。安全约束与业务语义必须分别验证。

先定义要算什么,再定义怎么查

“今天招行余额”至少缺账户集合、余额类型、时点和币种。把口径写成结构化意图,明确账户实体、过滤范围、快照时间及指标,再映射到受治理的表或视图。模型能建议 SQL,但不能自主选择更宽权限;租户和行级范围从可信身份注入。

SQL 合法不等于没有风险

只允许 SELECT 能降低范围,却不能证明无副作用或资源可控。数据库可能允许有副作用的函数,查询也可能调用昂贵计算。用最小权限角色、函数与表允许清单、只读事务和超时限制共同约束;参数化解决值注入,不能替代结构与权限校验。PostgreSQL 的 RLS 也有 owner、superuser、BYPASSRLS 等边界,实际查询角色需要验证。

聚合正确依赖数据粒度

账户余额是一户一时点,交易是一户多笔。直接 JOIN 后 SUM(balance) 会按交易数重复累计余额,即使行权限、类型与语法全部正确。先确定每个输入的主键和粒度,再在相同粒度聚合或用存在性过滤;数值复核应该根据实体键而非“结果看起来合理”。

返回一个可解释的计算

答案同时呈现账户范围、余额种类、币种和数据截至时间。对多次查询要考虑一致快照,否则明细与总数可能来自不同时刻。金额用固定精度与确定性代码汇总,模型负责解释口径。遇到歧义先澄清;反例是默默把“重庆分行”替成“重庆地区开户”,语法没有错,却改变了用户问题。

用一个问题检查理解

自然语言查数据库,怎样防止 SQL 合法却查错口径或越权?

把问句先映射为实体、指标、时间、币种和权限范围,再生成受限查询。AST 校验与参数化只解决部分问题,还需要最小权限账号、允许的表与函数、行级过滤、超时和资源限制。结果返回查询口径和快照信息,金额用确定性代码复核。对于“招行今天余额”这类歧义,要先确认账户集合与余额时点,不能只证明 SQL 能运行。

实现与取舍

先解决业务语义

为“支出”“可用余额”“利差”等指标定义口径、状态条件和单位。银行简称映射到受控实体字典,地区与分行不应仅靠字符串包含匹配。时间范围显式转成业务时区的起止时刻,确认使用发生日、入账日还是价值日。缺少决定结果的条件时先澄清,或清楚展示采用的默认口径。

执行边界在数据库外和内同时建立

解析 SQL AST,限制语句类型、表、列与函数,值使用绑定参数,标识符来自允许列表。禁止多语句和不受控外部访问;只读查询也可能通过函数产生危险行为或消耗大量资源,因此数据库账号、网络和函数权限仍需收紧。设置语句超时、结果行数与查询成本约束,执行计划检查也不能替代运行限制。

租户隔离不能依靠提示词

可信身份决定租户和授权范围,模型不能自由指定 tenant_id。可使用受控视图、网关注入条件与数据库行级安全作多层约束,并验证高权限角色是否绕过这些策略。缓存包含身份范围、数据版本和口径,不能让另一个用户命中更高权限结果。

回答如何可复核

返回指标定义、时间范围、币种、数据时间和查询摘要;受权审计者可查看实际查询及参数。对聚合用已知样本和独立 SQL 交叉检查,特别测试一对多 JOIN 引起的重复累加、退款冲正和空值。结果为空应与查询失败区分。面试者能主动发现 JOIN 放大,比只写 SELECT 更有价值。

代码示例

一对多 JOIN 如何把金额重复累加

用整数分演示重复累加;完整查询还需租户权限、币种、时间与交易口径。

import sqlite3

db = sqlite3.connect(":memory:")
db.executescript("""
CREATE TABLE payments(id INTEGER PRIMARY KEY, amount_cents INTEGER);
CREATE TABLE tags(payment_id INTEGER, tag TEXT);
INSERT INTO payments VALUES (1, 10000), (2, 20000);
INSERT INTO tags VALUES (1, 'bank'), (1, 'expense'), (2, 'expense');
""")
wrong = db.execute("SELECT SUM(p.amount_cents) FROM payments p JOIN tags t ON p.id=t.payment_id").fetchone()[0]
correct = db.execute("SELECT SUM(p.amount_cents) FROM payments p WHERE EXISTS (SELECT 1 FROM tags t WHERE t.payment_id=p.id)").fetchone()[0]
print("joined cents:", wrong)
print("payment cents:", correct)
db.close()

预期输出

joined cents: 40000
payment cents: 30000

工程推演

场景
面试假设:用户问“招行重庆今天支出多少”,数据库有多个账户及冲正流水。
设计决策
解析地区、银行、时区与支出口径,以服务端权限生成受控聚合查询。
验证目标
金额可通过样本独立复核,越权账户不参与返回或缓存。
适用边界
金融字段与计算口径需由实际业务负责人确认。

连续追问与解答

沿着问题的前提和约束继续向下读。先理解参考解答,再尝试收起答案,用自己的话解释因果和取舍。

举一反三:条件变了,怎样推导?

先找出改变的条件,再判断原方案中哪些前提仍成立。下面的案例是教学推演,便于将原理迁移到新问题。

账面余额改为可用余额

改变的条件:指标名称变化,实体集合相同

延伸问题:能只改列名复用所有逻辑吗?

推导与参考解答

先检查可用余额是否已扣冻结、授信是否包含,以及更新时间是否与账面余额一致。如果来自另一个粒度或快照的表,还要重审 JOIN 和时点。口径变化可能影响计算规则而不只是列映射;输出明确余额类型和数据时效。

保持不变的原理:指标语义和粒度必须匹配,字段存在不代表计算口径等价。

一次回答包含总额与明细

改变的条件:从单查询变成多查询

延伸问题:两个 SELECT 各自正确,为什么总额与明细仍不一致?

推导与参考解答

可能两次读取之间发生数据变化,也可能口径不同。固定账户、时间、币种和授权范围,使用合适的同一快照或单次查询产出;标记数据截至时间。若跨数据源无法同快照,说明一致性窗口并核对版本,而不是让模型调数字凑一致。

保持不变的原理:可解释答案来自同一计算契约,多条正确查询仍需一致输入。

易错点

  • 提示词要求只读就算安全
  • 模型直接指定租户条件
  • SQL 能运行就当业务答案正确

参考资料

依据公开技术资料设计;参考资料支持技术机制,场景与评分标准为本站设计,不代表某公司面试原题。 新增问答与迁移案例用于原理讲解,来源核查与案例运行验证分别记录。

检查自己理解到哪一步

读完后可以对照这些标准解释原理、边界和取舍。掌握程度由你自评;需要进一步验证时,再完成下方小任务。

基础达标
能做参数绑定、只读账号和范围限制。
中高级信号
能解释指标语义、时区、行级隔离和查询资源控制。
资深信号
能用反例检查 JOIN 放大、冲正、缓存及高权限绕过。

查看独立示例的校验记录

动手验证 按需完成 · 建议 15 分钟

设计“今日银行支出”查询契约,给出 JOIN 导致重复累加的反例。

展开验收要求与检查点
  • 业务口径显式
  • 权限由可信身份决定
  • 金额可确定性复核

重点检查

  • 将自然语言映射到指标口径
  • 理解只读与 AST 校验的局限
  • 能发现权限和 JOIN 重复累加