摘要:在现代化数据平台、智能 BI(ChatBI)、Text-to-SQL 以及企业级决策支持系统的落地实践中,如何将业务人员口语化的自然语言意图,精准转化为底层数仓的物理指标与可执行查询,是整个数据应用链路中最核心的瓶颈。
许多系统往往直接将自然语言直接丢给大模型生成 SQL,导致频繁出现指标口径对不齐、非可加指标被错误求和、同名异义词混淆、过滤条件丢失等严重生产事故。
本文将系统拆解“从意图到检索与计算”的完整技术链路:
指标模型的底层解构:原子指标、派生指标、复合指标与维度的标准化建模;
意图识别与槽位抽取:业务目标分类、时间表达式标准化与实体识别;
语义对齐与多路召回:词表倒排、向量语义检索与知识图谱的混合路由;
指标拆解与计算图(DAG)生成:复合指标递归分解、修饰词继承与计算逻辑编译;
生产级 Python 引擎实现:包含完整的意图解析、元数据对齐、DAG 分解与 SQL 生成代码;
指标检索评估体系与生产避坑指南。
一、 为什么“查指标”是数据智能化中最难的一环?
在传统 BI 时代,用户查数据的路径是固定的:打开预先开发好的仪表盘(Dashboard),在下拉框中选择“部门”、“日期”,查看固定的图表。这种模式虽然稳定,但开发周期长、无法满足敏捷多变的探索性分析需求。
在大语言模型(LLM)普及后,业务人员期望通过自然语言直接提问:
“看下华东大区上个月新客的客单价是多少,按品类排个序。”
“上周华南区退款率突然飙升的原因是什么?哪款商品贡献最大?”
看似简单的一句话,对于底层数据系统而言,却需要跨越一条巨大的语义与工程鸿沟:
┌─────────────────────────────────────────────────────────────────────────┐ │ 从自然语言意图到物理计算的鸿沟 │ └─────────────────────────────────────────────────────────────────────────┘ [业务自然语言] [底层数据基础设施] - 口语化、模糊、省略主语 - 严格的表结构与物理字段 - 包含业务术语缩写 ("GMV", "客单价") - 聚合函数、Group By、Join 关系 - 相对时间描述 ("上个月", "上上周同期") - 精确的时间戳范围 [Start, End) - 复合逻辑 ("客单价" = 销售额 / 用户数) - 分子分母独立计算后再做除法 │ ▼ 【从意图到检索:指标拆解与计算链路】直接 Prompt LLM 编写 SQL 的致命缺陷
很多初创团队试图通过简单的 Prompt(把 DDL 和用户问题直接喂给 GPT-4)来实现 Text-to-SQL,但在真实业务场景下,这种做法的准确率通常不足 40%:
幻觉与口径漂移:大模型不知道公司内部特定的“客单价”到底是用
支付金额 / 支付订单数还是支付金额 / 支付人数,极易根据通用常识自行脑补。非可加指标误聚合:率值类指标(如“转化率”、“留存率”)和去重计数指标(如“UV”)属于非可加指标。大模型常犯的低级错误是先算每天的转化率,再对其做
AVG(),导致严重数学错误。同名异义与修饰词丢失:用户口中的“销售额”,在财务口径下是“已开票确认收入”,在运营口径下是“已付款未退款 GMV”,大模型无法在没有元数据锚定的情况下做出正确判断。
因此,构建一套基于指标标准化建模、意图槽位抽取、语义检索对齐与计算图动态拆解的确定性引擎,是实现可靠智能数据查询的唯一技术路径。
二、 指标体系的底层建模:指标、维度与修饰词的标准化解构
在进行意图解析之前,必须建立一套标准化的指标元数据模型(业界通常采用阿里巴巴 OneData 建模方法论)。任何复杂的业务指标,都可以被拆解为以下核心要素:
┌──────────────────────────┐ │ 业务指标标准模型构成 │ └────────────┬─────────────┘ │ ┌───────────────────────────────────┼───────────────────────────────────┐ ▼ ▼ ▼ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ 原子指标 │ │ 修饰要素 │ │ 分析维度 │ │ (Atomic) │ │ (Modifiers) │ │ (Dimensions) │ ├──────────────┤ ├──────────────┤ ├──────────────┤ │ - 业务过程 │ │ - 时间周期 │ │ - 空间粒度 │ │ - 度量字段 │ │ - 业务过滤词 │ │ - 聚合分组项 │ │ - 聚合函数 │ │ - 流程状态 │ │ - 层级下钻项 │ └──────────────┘ └──────────────┘ └──────────────┘2.1 核心术语定义与三层指标体系
1. 原子指标(Atomic Metric)
定义:不可再拆分的核心业务度量,基于特定的单一业务过程。
数学表达:
聚合函数 + 物理事实度量字段示例:
支付金额:
sum(pay_amount)支付用户数:
count(distinct user_id)曝光次数:
count(impression_id)
2. 派生指标(Derived Metric)
定义:在原子指标的基础上,叠加了时间周期和一个或多个业务修饰词(过滤条件)生成的指标。
数学表达:
时间周期 + 修饰词列表 + 原子指标示例:
近30天_华东大区_App端_新客_支付金额时间周期:
最近30天修饰词:
region = 'East_China',platform = 'App',is_new_user = 1原子指标:
支付金额
3. 复合指标(Composite Metric)
定义:由两个或多个派生指标通过四则运算或数学函数组合而成的指标。
数学表达:
f(派生指标1, 派生指标2, ...)示例:
新客客单价 = 近30天_新客_支付金额 / 近30天_新客_支付用户数ROI = 广告带来的GMV / 广告消耗成本退款率 = 退款成功金额 / 支付金额
2.2 指标类型对比与计算约束表
| 指标类别 | 可加性(Additivity) | 聚合计算特征 | 计算阶段 | 常见错误规避 |
| 完全可加指标(如支付金额, 订单量) | 可跨时间、维度自由累加 | SUM(),COUNT() | 单层聚合即可完成 | 避免重复关联导致的数据膨胀 |
| 半可加指标(如账户余额, 库存量) | 跨空间维度可加,跨时间维度不可加 | 空间求和,时间取最新快照 (LAST_VALUE) | 需按时间分区截取截面数据 | 严禁对跨时间周期的库存求SUM() |
| 不可加指标(如 UV, 转化率, 客单价) | 跨任何维度都不可直接累加 | 先分别计算基础度量,最后在最外层做除法/去重 | 必须使用多层子查询或计算图(DAG) | 绝对不能先算比率再做AVG() |
三、 意图识别与槽位抽取(Intent Parsing & Slot Extraction)
当用户输入一句话后,系统的第一步是将非结构化的自然语言文本拆解为一个结构化的意图槽位对象(Intent Slot Object)。
[用户输入]: "看下华东区上个月新客的客单价是多少,按品类排个序" │ ▼ ┌───────────────────────────────────────────────────────────┐ │ 意图识别与槽位抽取流水线 │ ├──────────────────┬────────────────────────────────────────┤ │ 意图类型 │ 指标查询与排序 (Metric_Query_With_Sort) │ ├──────────────────┼────────────────────────────────────────┤ │ 目标指标候选 │ ["客单价"] (属于复合指标) │ ├──────────────────┼────────────────────────────────────────┤ │ 时间修饰词 (Time)│ "上个月" ➔ [2026-07-01, 2026-07-31] │ ├──────────────────┼────────────────────────────────────────┤ │ 业务修饰词 (Filter)│ region="华东区", user_type="新客" │ ├──────────────────┼────────────────────────────────────────┤ │ 分组维度 (GroupBy)│ ["品类"] │ ├──────────────────┼────────────────────────────────────────┤ │ 排序规则 (OrderBy)│ 客单价 DESC │ └──────────────────┴────────────────────────────────────────┘3.1 意图分类(Intent Classification)
用户查询数据的意图通常可以划分为四大类:
单点事实查询(Fact Query):查询特定时间、特定条件下的具体指标值。
“昨天总销售额是多少?”
多维下钻与对比(Breakdown & Comparison):按维度拆解或进行同环比对比。
“上周各省份的 GMV 排名,以及环比增长率。”
异动归因分析(Root Cause Analysis):探寻指标变化的底层驱动因素。
“为什么上周日退款率环比上升了 5%?”
趋势与预测查询(Trend & Forecasting):请求时间序列连续曲线或未来趋势。
“过去 6 个月活跃用户的变化趋势。”
3.2 槽位抽取与相对时间标准化
槽位抽取(Slot Filling)的核心挑战在于时间表达式的归一化。自然语言中的时间充满歧义与动态上下文(如“上周五”、“近30天”、“今年一季度”、“环比上期”)。
时间归一化引擎逻辑
输入相对时间字符串: "上个月" 获取当前系统时间 (Anchor Time): 2026-08-21 11:00:00 计算逻辑: 1. 当前年份 = 2026, 当前月份 = 8 2. 目标月份 = 8 - 1 = 7 月 3. 计算 7 月的绝对起始与结束时间戳: Start_Time = 2026-07-01 00:00:00 End_Time = 2026-07-31 23:59:59 4. 对应同周期 (YoY): 2025-07-01 ~ 2025-07-31 5. 对应环比期 (MoM): 2026-06-01 ~ 2026-06-30四、 语义对齐与多路召回:如何精准定位目标指标?
在大型企业中,元数据字典里可能维护着几千个指标、上万个维度。单纯依赖关键词匹配或单一向量检索,往往会产生严重的语义误命中。
4.1 传统单一检索的失效场景
词形相似但口径完全相反:
下单金额vs支付金额vs退款金额向量模型生成的 Embedding 在高维空间极其接近(余弦相似度 > 0.92),因为它们经常出现在相同的语境中,但财务含义完全不同。
行业缩写与黑话隐喻:
用户问:“大盘流水”,底层物理指标叫
total_gmv;用户问:“老带新拉新人数”,底层物理指标叫
referral_new_user_cnt。
4.2 三层多路召回架构(Hybrid Retrieval & Disambiguation)
为了实现 99% 以上的指标定位准确率,生产级架构采用“精准词表 + 稠密向量 + 知识图谱”三路召回与重排机制:
[用户提取到的候选指标词] │ ┌───────────────────────────┼───────────────────────────┐ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 第一路: 词典与 │ │ 第二路: 稠密 │ │ 第三路: 知识 │ │ 倒排索引 (BM25)│ │ 向量检索 (Dense)│ │ 图谱关联检索 │ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤ │ - 同义词/别名库 │ │ - 指标定义向量 │ │ - 业务域上下文 │ │ - 拼音/前缀匹配 │ │ - 业务描述匹配 │ │ - 实体-指标拓扑 │ │ - 编辑距离模糊查│ │ - BGE / OpenAI │ │ - 上下文约束树 │ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ │ │ └───────────────────────────┼───────────────────────────┘ │ 候选指标集 (Top-20) ▼ ┌─────────────────────────┐ │ 倒数排名融合 (RRF) 粗排 │ └────────────┬────────────┘ │ ▼ ┌─────────────────────────┐ │ Cross-Encoder 精准重排 │ │ + 业务规则置信度过滤 │ └────────────┬────────────┘ │ ▼ [精准命中目标指标元数据]4.3 倒数排名融合(RRF)算法在指标召回中的应用
当三路检索分别返回不同的候选集与分数时,利用倒数排名融合算法(Reciprocal Rank Fusion, RRF)对结果进行无量纲化融合打分:
RRF_Score(d ∈ D) = ∑ [ 1 / (k + r_m(d)) ] (m ∈ M)d:候选指标元数据。M:检索通道集合([BM25, Dense_Vector, Graph_Search])。r_m(d):指标d在第m路检索中的排名次序。k:常数平滑因子(通常取 60)。
通过 RRF 算法,能够同时兼顾精确关键词命中的高确定性与向量语义检索的泛化性。
五、 指标拆解与计算图(DAG)动态生成
当系统精确定位到用户想要查询的指标后,如果该指标是原子指标,生成 SQL 非常直接;但如果是复合指标(Composite Metric),就必须进行递归拆解并构建有向无环计算图(DAG)。
5.1 复合指标的递归分解过程
以业务中最常见的指标“新客客单价”为例,其分解链路如下:
┌───────────────────────────┐ │ 目标: 新客客单价 (Node 0)│ │ Formula: Node 1 / Node 2 │ └─────────────┬─────────────┘ │ ┌──────────────────────┴──────────────────────┐ ▼ ▼ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │ 分子: 新客支付金额 (Node 1) │ │ 分母: 新客支付人数 (Node 2) │ ├─────────────────────────────┤ ├─────────────────────────────┤ │ - 时间: [上月起始, 上月结束] │ │ - 时间: [上月起始, 上月结束] │ │ - 过滤: region='华东区' │ │ - 过滤: region='华东区' │ │ user_type='新客' │ │ user_type='新客' │ │ - 原子度量: sum(pay_amount) │ │ - 原子度量: count(distinct │ │ - 来源表: dwd_fact_orders │ │ user_id) │ │ - 分组: category_name │ │ - 来源表: dwd_fact_orders │ │ │ │ - 分组: category_name │ └─────────────────────────────┘ └─────────────────────────────┘5.2 修饰词的继承与下推(Filter Pushdown & Inheritance)
在指标拆解中,必须严格处理修饰词与过滤条件的继承关系:
全局修饰词(Global Filters):用户在自然语言中指定的条件(如
region = '华东区'),必须下推并继承到所有的子叶子节点中。指标自有修饰词(Intrinsic Filters):指标定义本身附带的条件(如
新客对应的is_new_user = 1),与全局修饰词进行AND逻辑合并。同构查询合并(Subquery Coalescing):如果分子(支付金额)和分母(支付人数)来自同一张物理事实表、具备相同的时间周期与过滤条件,编译器应自动将其优化合并为单次扫描聚合,避免重复全表扫描。
六、 生产级 Python 实战:端到端“意图解析-指标匹配-SQL构建”引擎
下面提供一份完整、可直接运行的工程级 Python 实现代码。该引擎模拟了从非结构化输入、元数据字典多路召回、DAG 递归指标分解,到最终生成标准 SQL 的全流程。
6.1 核心代码实现
import json import re from datetime import datetime, timedelta from typing import List, Dict, Any, Optional from dataclasses import dataclass, field # ==================== 1. 元数据对象定义 ==================== @dataclass class MetricMeta: code: str # 指标唯一标识 name: str # 指标中文名 metric_type: str # ATOMIC (原子) / DERIVED (派生) / COMPOSITE (复合) base_table: Optional[str] = None # 物理事实表 agg_expr: Optional[str] = None # 聚合表达式,如 sum(amount) formula: Optional[str] = None # 复合计算公式,如 {pay_amt} / {pay_user_cnt} required_filters: List[str] = field(default_factory=list) # 自带过滤条件 synonyms: List[str] = field(default_factory=list) # 别名/同义词 # 模拟企业级指标元数据资产库 METRIC_CATALOG: Dict[str, MetricMeta] = { "pay_amount": MetricMeta( code="pay_amount", name="支付金额", metric_type="ATOMIC", base_table="dwd_trade_order_di", agg_expr="SUM(pay_amount)", synonyms=["销售额", "流水", "GMV", "总收益"] ), "pay_user_count": MetricMeta( code="pay_user_count", name="支付用户数", metric_type="ATOMIC", base_table="dwd_trade_order_di", agg_expr="COUNT(DISTINCT user_id)", synonyms=["买家数", "支付人数", "下单人数"] ), "arpu": MetricMeta( code="arpu", name="客单价", metric_type="COMPOSITE", formula="{pay_amount} / NULLIF({pay_user_count}, 0)", synonyms=["笔单价", "客单", "平均购买额"] ) } DIMENSION_CATALOG = { "品类": "category_name", "省份": "province_name", "大区": "region_name", "渠道": "channel_code" } # ==================== 2. 意图解析与多路检索器 ==================== class IntentAndMetricMatcher: def __init__(self, catalog: Dict[str, MetricMeta], dimensions: Dict[str, str]): self.catalog = catalog self.dimensions = dimensions def parse_time(self, query: str) -> Dict[str, str]: """简易时间规则归一化引擎""" now = datetime(2026, 8, 21) # 假定当前系统基准时间 if "上个月" in query: # 2026年7月 start_date = "2026-07-01" end_date = "2026-07-31" elif "昨天" in query: yesterday = now - timedelta(days=1) start_date = end_date = yesterday.strftime("%Y-%m-%d") else: # 默认近7天 start_date = (now - timedelta(days=7)).strftime("%Y-%m-%d") end_date = now.strftime("%Y-%m-%d") return {"start_date": start_date, "end_date": end_date} def match_metric(self, query: str) -> Optional[MetricMeta]: """多路召回:精确匹配 + 别名倒排匹配""" for code, meta in self.catalog.items(): if meta.name in query: return meta for syn in meta.synonyms: if syn in query: return meta return None def match_dimensions_and_filters(self, query: str) -> Dict[str, Any]: """抽取维度与业务修饰词""" selected_dims = [] for dim_cn, dim_en in self.dimensions.items(): if dim_cn in query: selected_dims.append(dim_en) filters = [] if "华东" in query: filters.append("region_name = '华东大区'") if "新客" in query: filters.append("is_new_user = 1") return { "group_by": selected_dims, "filters": filters } # ==================== 3. 指标 DAG 分解与 SQL 编译引擎 ==================== class MetricSqlCompiler: def __init__(self, catalog: Dict[str, MetricMeta]): self.catalog = catalog def compile(self, metric: MetricMeta, time_range: Dict[str, str], filters: List[str], group_by: List[str]) -> str: """根据指标类型编译生成最终的物理查询 SQL""" if metric.metric_type == "ATOMIC": return self._compile_atomic(metric, time_range, filters, group_by) elif metric.metric_type == "COMPOSITE": return self._compile_composite(metric, time_range, filters, group_by) else: raise NotImplementedError(f"不支持的指标类型: {metric.metric_type}") def _compile_atomic(self, metric: MetricMeta, time_range: Dict[str, str], filters: List[str], group_by: List[str]) -> str: all_filters = list(filters) all_filters.extend(metric.required_filters) all_filters.append(f"dt >= '{time_range['start_date']}' AND dt <= '{time_range['end_date']}'") where_clause = " AND ".join([f"({f})" for f in all_filters]) select_cols = list(group_by) select_cols.append(f"{metric.agg_expr} AS {metric.code}") group_by_clause = f"\nGROUP BY {', '.join(group_by)}" if group_by else "" sql = f"""SELECT {', '.join(select_cols)} FROM {metric.base_table} WHERE {where_clause}{group_by_clause}""" return sql def _compile_composite(self, metric: MetricMeta, time_range: Dict[str, str], filters: List[str], group_by: List[str]) -> str: # 1. 解析复合指标中依赖的底层原子指标 Token tokens = re.findall(r'\{([a-zA-Z0-9_]+)\}', metric.formula) sub_metrics = [self.catalog[t] for t in tokens] # 2. 检查是否满足同构合并优化(来自同一张物理表) tables = set([m.base_table for m in sub_metrics]) if len(tables) == 1: # 同表优化:合并为单层查询计算 table_name = list(tables)[0] all_filters = list(filters) all_filters.append(f"dt >= '{time_range['start_date']}' AND dt <= '{time_range['end_date']}'") where_clause = " AND ".join([f"({f})" for f in all_filters]) # 构造内层聚合度量 inner_select_exprs = list(group_by) computed_formula = metric.formula for sub_m in sub_metrics: inner_select_exprs.append(f"{sub_m.agg_expr} AS {sub_m.code}") computed_formula = computed_formula.replace(f"{{{sub_m.code}}}", sub_m.code) group_by_clause = f"\n GROUP BY {', '.join(group_by)}" if group_by else "" sql = f"""WITH raw_aggregated_data AS ( SELECT {', '.join(inner_select_exprs)} FROM {table_name} WHERE {where_clause}{group_by_clause} ) SELECT {', '.join(group_by) + ',' if group_by else ''} {computed_formula} AS {metric.code} FROM raw_aggregated_data""" return sql else: # 异构跨表:通过 Common Dimension Full/Left Join 进行多路合并计算 raise NotImplementedError("跨表复合指标 Join 组装逻辑") # ==================== 4. 端到端测试流水线 ==================== def run_pipeline(user_query: str): print("=" * 70) print(f"【用户自然语言输入】: \"{user_query}\"\n") # 步骤 A: 意图解析与槽位抽取 parser = IntentAndMetricMatcher(METRIC_CATALOG, DIMENSION_CATALOG) time_info = parser.parse_time(user_query) matched_metric = parser.match_metric(user_query) slots = parser.match_dimensions_and_filters(user_query) if not matched_metric: print("❌ 未能识别到相关指标元数据!") return print("✔ [槽位抽取结果]:") print(f" - 目标指标: {matched_metric.name} ({matched_metric.code}) [类型: {matched_metric.metric_type}]") print(f" - 时间范围: {time_info['start_date']} 至 {time_info['end_date']}") print(f" - 分析维度: {slots['group_by']}") print(f" - 过滤条件: {slots['filters']}") print() # 步骤 B: 指标拆解与物理 SQL 编译 compiler = MetricSqlCompiler(METRIC_CATALOG) executable_sql = compiler.compile( metric=matched_metric, time_range=time_info, filters=slots["filters"], group_by=slots["group_by"] ) print("✔ [生成的物理执行 SQL]:") print("-" * 50) print(executable_sql) print("-" * 50) if __name__ == "__main__": test_query = "看下华东区上个月新客的客单价是多少,按品类排个序" run_pipeline(test_query)6.2 代码运行输出分析
运行上述程序后,控制台会输出高度规范、带 CTE 逻辑且正确规避了除以零风险(NULLIF)的标准 SQL 语句:
====================================================================== 【用户自然语言输入】: "看下华东区上个月新客的客单价是多少,按品类排个序" ✔ [槽位抽取结果]: - 目标指标: 客单价 (arpu) [类型: COMPOSITE] - 时间范围: 2026-07-01 至 2026-07-31 - 分析维度: ['category_name'] - 过滤条件: ["region_name = '华东大区'", 'is_new_user = 1'] ✔ [生成的物理执行 SQL]: -------------------------------------------------- WITH raw_aggregated_data AS ( SELECT category_name, SUM(pay_amount) AS pay_amount, COUNT(DISTINCT user_id) AS pay_user_count FROM dwd_trade_order_di WHERE (region_name = '华东大区') AND (is_new_user = 1) AND (dt >= '2026-07-01' AND dt <= '2026-07-31') GROUP BY category_name ) SELECT category_name, pay_amount / NULLIF(pay_user_count, 0) AS arpu FROM raw_aggregated_data --------------------------------------------------七、 评估体系与生产落地避坑指南
为了保证“从意图到检索”系统的工业级稳定性,必须建立一套可量化的离线/在线评估指标体系与异常防护机制。
7.1 核心评估矩阵
在日常迭代中,应当构建包含 500~1000 个真实业务问答的黄金测试集(Golden Dataset),通过以下指标监控系统表现:
意图分类准确率(Intent Accuracy):分类器准确识别用户是查指标、做对比还是做归因的比例。
槽位提取 F1 值(Slot F1-Score):时间、维度、修饰词的精确率(Precision)与召回率(Recall)调和平均值。
指标 Top-1 / Top-3 召回率(Metric Hit Rate @ K):正确指标出现在候选检索集前 K 位的概率。
端到端 SQL 执行一致率(Execution Accuracy / EX):生成的 SQL 在真实数仓中跑出的数值结果,与数据分析师人工编写的标准 SQL 运行结果完全一致的比例。
Precision = TP / (TP + FP) Recall = TP / (TP + FN) Slot_F1 = 2 × (Precision × Recall) / (Precision + Recall)7.2 生产落地四大避坑原则
1. 警惕“同环比计算的时间漂移”陷阱
隐患:用户问“上个月的环比增长”,如果直接对过滤出来的上月数据做计算,会因为缺失上上个月的数据导致计算结果为
NULL。解法:在指标计算图中,若检测到同环比依赖,底层数据扫描的时间范围必须自动向前扩展(例如查 7 月环比,底层需拉取 6 月与 7 月全量数据,在外层通过滑动窗口函数
LAG()完成比率计算后,再截取 7 月数据呈现)。
2. 防止非可加指标的“二次聚合”事故
隐患:上层前端可视化图表(如 Superset/Tableau)在收到后端返回的多行数据后,默认会再次对所有行执行
SUM()操作。若返回的是“客单价”或“留存率”,前端的二次自动求和将产生荒谬的业务数值。解法:元数据中必须透传
is_additive = False标记,强制前端禁用自动求和,仅允许展示或重新发起动态重算请求。
3. 建立指标别名与负反馈自学习闭环(Human-in-the-loop)
机制:当检索系统置信度较低(Top-1 与 Top-2 分数差异小于 0.05)时,不要盲目执行,而是主动向用户发起反问确认(Clarification):
“您指的是【财务口径_实付金额】还是【运营口径_GMV】?”
用户点击确认后,系统自动将该 Query 作为别名沉淀至元数据同义词库中,实现知识库的自进化。
4. 严控大模型在 SQL 编译阶段的自由度
原则:让 LLM 负责理解模糊语义,让确定性编译器负责生成物理 SQL。
绝对不要让大模型直接从头编写 SQL 字符串。大模型只负责输出结构化的 JSON 槽位(AST),随后的表关联、JOIN 路径选择、字段聚合、NULL 处理全部由底层的规则代码(Deterministic Rule Engine)严格编译生成。
从模糊的自然语言意图到精确的数据检索与指标计算,其核心本质是“用确定性的元数据资产体系,约束并对齐不确定性的自然语言语义”。
通过构建标准的三层指标模型(原子/派生/复合)、引入多路语义召回与 RRF 融合、结合动态计算图(DAG)实现逻辑分解,我们能够彻底攻克传统 Text-to-SQL 准确率低下、口径难以对齐的顽疾,为企业构建出高可用、高可信的下一代智能数据大脑。