AI 数据问答权限:自然语言不能绕过指标边界
AI 数据问答权限自然语言不能绕过指标边界一、数据问答越自然越容易让人忘记权限AI 数据问答让用户直接输入上周新增用户为什么下降系统自动查数并解释。体验很顺但风险也很明显。自然语言入口不能绕过 BI 权限、指标口径和数据分级。用户没权限看的字段不能因为换成问句就被查出来。为什么权限要放在查询生成之前而不是结果脱敏之后因为 LLM 生成 SQL 的过程本身就会看见表结构如果你的 Schema 里有一张salary_detail表模型在生成查询计划的时候就已经知道这张表的存在了。等结果回来再做行级过滤数据已经被读出来、传过来了审计日志里也会有这条查询记录。正确的做法是在 Prompt 里只给模型他想看的那部分 Schema让模型根本不知道有这张表的存在。这就是Schema 裁剪的核心价值——不是挡住数据是连表名都不让模型看到。数据问答系统必须把权限放在查询生成之前。模型只能在用户可见的数据域里生成 SQL 或查询计划。权限不能等查询结果出来后再脱敏因为那时数据已经被访问了。二、问答链路要先做语义解析和权限裁剪一个安全的数据问答链路应先识别用户意图和实体再根据权限裁剪可用指标、维度和表。模型生成查询时只能看到裁剪后的 Schema。flowchart TD A[自然语言问题] -- B[意图和实体识别] C[用户权限] -- D[Schema 裁剪] B -- E[可用指标维度] D -- E E -- F[生成查询计划] F -- G[SQL 审核] G -- H[执行查询] H -- I[生成回答]SQL 审核也不能省。模型可能生成跨权限 Join、全表扫描或危险函数。审核层负责拦住不合规查询。为什么 AI 生成的 SQL 必须经过审核层而不是直接执行一个典型的翻车案例用户问上季度各部门收入对比模型自动 Join 了财务表和 HR 表 —— 用户没有 HR 表的权限但因为 LLM 觉得需要部门名称字段就自动跨了权限边界。SQL 审核层要在执行前做三件事检查 JOIN 的表全在用户权限范围内、拦截SELECT *这种全列拉取、禁止DROP/DELETE等危险语句。这不只是安全需求更是合规红线。三、查询计划比直接生成 SQL 更可控相比让模型直接输出 SQL可以先输出结构化查询计划再由系统编译成 SQL。这样更容易校验指标和维度。from dataclasses import dataclass dataclass class QueryPlan: metric: str dimensions: list[str] filters: dict[str, str] def validate_plan(plan: QueryPlan, allowed_metrics: set[str], allowed_dims: set[str]) - None: if plan.metric not in allowed_metrics: raise PermissionError(fmetric not allowed: {plan.metric}) denied set(plan.dimensions) - allowed_dims if denied: raise PermissionError(fdimensions not allowed: {denied})这个校验很朴素但能表达核心原则模型不能凭自然语言扩大权限。所有字段都要经过系统确认。为什么不用允许列表而用拒绝列表做权限校验用拒绝列表黑名单的话你今天禁了salary明天 HR 加了个salary_v2字段就绕过去了。正确做法是白名单模式用户的allowed_metrics和allowed_dims是在登录时就确定好的集合模型无论生成什么字段名你都只跟这个集合做交集。不在集合里的直接拒绝不存在漏网之鱼。四、拒答也要解释清楚不要只说没有权限当用户无权查看某个指标时系统应说明可见范围。例如“你可以查看部门汇总但不能查看个人明细”。这样比冷冰冰的拒绝更容易被接受。还要处理间接泄露。即使用户看不到个人明细也可能通过多次过滤推断个体数据。系统应设置最小聚合粒度和查询频率限制。小样本结果需要隐藏或合并。最后所有问答要留审计日志。记录用户问题、生成计划、执行 SQL、返回行数和权限判断。出了问题必须能复盘自然语言如何变成查询。缓存也要遵守权限。数据问答为了提速可能缓存问题到结果的映射。缓存 key 必须包含用户权限版本、指标版本和过滤条件不能只按问题文本缓存。否则两个用户问同一句话权限不同却命中同一份结果就会造成越权泄露。为什么缓存 key 要包含用户权限版本而不只是用户 ID因为权限是动态的。今天 A 用户能看部门汇总明天他调岗了权限被收回。如果你的缓存 key 是user_id:question_text缓存 TTL 设了 30 分钟这 30 分钟内 A 能看到的数据仍然在缓存里躺着。把权限版本号比如 RBAC 的 revision 号拼进 key权限一变缓存自动失效。 踩坑提醒别把 Schema 全量喂给 LLM。很多开发者图省事把整个数据仓库的所有表和字段列出来作为 Prompt 上下文。一个中型数仓两三百张表字段上千个模型不仅处理慢还会脑补出跨表 Join。正确的做法是只给用户权限范围内的表且每张表只暴露聚合后的指标不要暴露明细字段。PermissionError抛出来要解释原因不要只甩 403。用户问我的绩效排名是多少被拒绝如果只返回无权限用户会觉得系统有 bug。返回当前角色仅支持查看部门级汇总数据不支持查看个人明细才是对的做法。拒答日志也要单独存方便 HR/法务后续审查。小样本结果必须隐藏。即使用户有权看某个维度当过滤后的结果行数 阈值如 5 条仍然存在间接泄露个体信息的风险。比如部门里 35 岁以上、薪资最高的员工——如果返回了唯一一个人就等于点名了。系统中应设min_result_threshold低于阈值的显示为5或直接不显示。五、总结AI 数据问答的安全边界必须放在查询生成之前。系统应先按用户权限裁剪 Schema再让模型生成结构化查询计划并通过审核层编译执行。自然语言提升了入口体验但不能提升用户权限。数据问答越方便越要把指标、维度和审计边界写清楚。