P1 AIP
意图识别与 RAG
NLQ 智能查数的第一公里:关键词规则意图识别把"一句话"分成知识问答 / 数据分析 / 数据查询三类,RAG 用四路召回(元数据向量 / 知识库 / 对话历史 / few-shot)并行检索相关表与列,融合重排后拼成 Text2SQL 的上下文。看完这 4 个故事,你就知道为什么有些问法一次命中、有些要靠元数据调优。
业务分析师
数据工程师
意图识别
RAG
元数据
融合重排
共 4 个故事
能 / 不能速览
✅ 这个主题能做
- 意图识别按关键词规则分 knowledge_qa / analysis / data_query 三类(置信度 0.9 / 0.85 / 0.8)
- RAG 四路并行召回:元数据向量(TopK15,权重 0.40)、知识库混合(TopK15,0.25)、对话历史(5 轮,0.20)、few-shot 成功样本(Top3,0.15)
- 融合重排:同表合并 → 归一化 → 权重加权 → 排序 → MD5 去重 → Token 预算截断 → TopK
- 表级命中带整表列结构,列级命中只带命中列,构造 Text2SQL 上下文
- 无命中自动回退全量 schema;元数据向量不可用时降级关键词匹配
- 每次查询写 NLQ_QUERY 审计日志,RAG 调用写 rag_call_logs
⛔ 这个主题做不了
- 意图识别是关键词规则不是 LLM,换说法可能分错类
- 向量检索质量依赖 embedding key 与索引重建,未重建时降级关键词匹配
- 知识问答是占位("暂由知识库处理"),没有真正的知识库答案
- 无 OAG 对象路(需配置 Foundry 并显式开启)、无 Cross-encoder 重排序
- 列级命中只带命中列,多表 join 需要相关表都命中
适用角色
本主题面向两个角色:
- 业务分析师(王姐):每天用 NLQ 查数,是意图识别与 RAG 的直接消费者,需要知道"什么样的问法命中率高"。
- 数据工程师(张工):通过补充表描述、生成同义词、重建元数据索引来提升 RAG 命中率,是调优的执行者。
IT 管理员(赵工)可在审计日志与 RAG 调用日志里统计命中情况,反推需要补哪些元数据。
能力速览(能做什么)
意图识别(关键词规则)
按关键词把问题分成知识问答 / 数据分析 / 数据查询三类,返回固定置信度;保证演示链路的确定性。
四路 RAG 召回
元数据向量(表/列+描述+同义词)、知识库混合检索(语义 0.6+关键词 0.4)、对话历史 5 轮、few-shot 成功样本 Top3,并行执行互不阻塞。
融合重排
同表合并 → 分通道归一化 → 权重加权(0.40/0.25/0.20/0.15)→ 排序 → MD5 去重 → 3000 Token 预算截断 → TopK 20。
全量回退与降级
一个词都命中不了时回退全量 schema;向量/embedding 不可用时元数据路自动降级关键词匹配,链路不断。
可观测与调优
POST /api/v1/rag/retrieve 可调试各通道召回结果;admin 可调整通道开关权重(rag_channel_configs)并重建索引。
调整指南(怎么调整)
- 提升元数据路命中率:用数据源"导入元数据"接口的 ai_generate_descriptions=true 参数生成表/列业务描述与同义词,再 POST /api/v1/rag/index/rebuild 重建向量索引。
- 补表口径:table_schemas.description 写清楚业务含义(如"销售额,订单实付总额"),关键词与向量都受益。
- 换问法:把口语换成表名 / 列名词("谁买得多"→"客户 订单 数量"),命中率立竿见影。
- 调通道权重:知识库内容多、元数据缺时,可把 knowledge 权重调高(PUT /api/v1/rag/channels)。
- 验证命中:聊天响应里的 rag_context / rag_channels_used 字段直接反映检索结果,看到全量 schema 就说明没命中。
做得好的场景
规则 + 四路召回这套组合在以下场景表现稳定:
- 演示确定性:规则分类不随模型抖动,同一句话每次结果一致,演示可复现。
- 冷门问法不崩:RAG 无命中回退全量,至少能出结果,不会直接报错。
- 上下文即所得:SQL 生成只认 RAG 给的上下文,不会自己编造不存在的表 / 列。
- 历史复用:对话历史与 few-shot 通道让"上次查过的口径"继续生效,追问更稳。
限制与不足
以下是明确的边界,使用前先知道:
- 规则不聪明:同义改写可能分错类或置信度低(兜底只有 0.5)。
- 向量质量依赖配置:无 embedding key / 索引未重建时,元数据路退化为关键词匹配,语义检索效果打折。
- 知识问答是占位:返回固定提示文案,不是真正的知识库答案。
- 列级命中只带命中列:多表 join 需要相关表 / 列都命中,否则 SQL 生成可能缺列。
- 演示元数据重启重建:ai_generate_descriptions 生成的结果与重建的索引在演示库重启后会重来。
场景故事
故事 1
"每个客户的订单数量"——意图 data_query、RAG 命中、SQL 一次成型
场景:标准查数
角色:业务分析师
耗时:约 3 分钟
- 背景
- 王姐是业务分析师,负责销售周报。她想快速知道每个客户下了几单,直接在"智能查询"里输入"每个客户的订单数量",敲下回车。这是 NLQ 链路最理想的一类问题:意图明确、词能对上表。
- 传统做法对比
- 以前要发工单给数据团队,等 1~2 天拿到一张临时报表,口径还要反复对;现在一句话 3~10 秒出结果,SQL 与中文说明都在页面上,肉眼可核对。
- 角色
- 业务分析师(王姐)。
- 操作步骤
-
- 登录 AIP,打开"智能查询"
- 输入"每个客户的订单数量"
- 发送并等待返回
- 查看 SQL 说明、图表建议与数据表,以及 rag_channels_used 字段
- 系统响应
- 响应 JSON 含 intent=data_query、confidence=0.8、sql_query、visualization 与 rag_channels_used:
{
"intent": "data_query", "confidence": 0.8,
"sql_query": "SELECT c.customer_name, COUNT(o.order_id) AS cnt FROM orders o JOIN customers c ON o.customer_id = c.customer_id GROUP BY c.customer_name",
"visualization": { "chart_type": "bar", "reason": "one dimension and numeric columns" },
"query_result": { "columns": ["customer_name", "cnt"], "rows": [["张三", 2], ["李四", 2], ["王五", 1]] },
"rag_channels_used": ["metadata", "knowledge"]
}
- 结果洞察
- 意图命中 data_query(问句含"订单");RAG 元数据路命中 orders 表级 + customers 列级(customer_name),知识库路补充业务描述,上下文聚焦;Text2SQL 生成正确 SQL,返回 3 行(张三 2 单、李四 2 单、王五 1 单),因"1 个维度 + 1 个数值列"推荐柱状图。一句话查数全链路走通。
- 调整建议
- 想按城市看,问"各城市的订单数"(命中 customers.city);想让"销售额"类问法更稳,用 ai_generate_descriptions 重导元数据生成描述与同义词;复杂口径先问简单版再逐步加条件。
- 动手试一试
- 登录:admin / admin1。页面路径:智能查询。输入内容:"每个客户的订单数量"。预期结果:intent=data_query、返回 3 行(张三 / 李四各 2 单、王五 1 单)、chart_type=bar;再试"各城市的订单数"看是否命中 customers.city。
- 限制提示
- 生成结果以 sql_explanation 为准,关键数字建议人工复核;若模型选错口径(如按 quantity 而非 COUNT),换一种说法重问即可;RAG 上下文里没有的列模型不会用。
故事 2
"什么是订单"——知识问答占位,不查数、不耗 token
场景:知识问答
角色:业务分析师
耗时:约 2 分钟
- 背景
- 王姐想确认系统里"订单"的业务口径,输入"什么是订单"。她原本担心系统会硬套一张表来答,结果返回的是一段"知识问答暂由知识库处理"的提示——这是 AIP 最小链路对定义类问题的诚实处理。
- 传统做法对比
- 以前要翻数据字典、找 DBA 或数据工程师问口径,等回复动不动半天;现在系统直接告知"这类问题暂由知识库处理",不浪费 token 去调模型瞎编。
- 角色
- 业务分析师(王姐)。
- 操作步骤
-
- 打开"智能查询"
- 输入"什么是订单"(或"解释一下销售额")
- 发送,观察返回(不进入 RAG / Text2SQL / 执行链路)
- 系统响应
- 返回 intent=knowledge_qa、confidence=0.9,message 为占位文案,无 sql_query / query_result:
{
"intent": "knowledge_qa", "confidence": 0.9,
"message": "知识问答类问题暂由知识库处理,当前最小链路仅支持数据查询与分析。",
"data_source_name": "aip_demo_warehouse"
}
- 结果洞察
- 问句命中"什么是 / 定义 / 解释 / 含义"等关键词,knowledge_qa 优先级最高(0.9);链路直接短路返回提示,不调 LLM、不写 SQL;这避免了"定义问题被当成查数硬答"的尴尬。审计日志会记录该次 NLQ_QUERY(无 sql)。
- 调整建议
- 想知道口径,把"什么是"换成数据问法("列出订单"、"统计订单");口径细节可到"数据源 → 元数据"看表 / 列描述;后续接入知识库后这里会返回真实答案。
- 动手试一试
- 登录:admin / admin1。输入内容:依次输入"什么是订单"、"解释一下销售额"、"GMV 怎么计算"。预期结果:全部返回 knowledge_qa 占位提示(confidence=0.9);再输入"列出订单"应命中 data_query 并真正查数。
- 限制提示
- 知识问答是固定占位,不是知识库真答案;最小链路不包含知识库,任何定义 / 解释类问题都会走此占位,不要指望它回答业务口径。
故事 3
冷门问法"帮我看看最近谁买得多"——元数据路降级,模型凭全貌猜
场景:冷门问法
角色:销售总监
耗时:约 5 分钟
- 背景
- 李经理是销售总监,不爱用术语,在智能查询里输入"帮我看看最近谁买得多"。意图识别兜底成 data_query(置信度仅 0.5);演示库元数据没有生成描述/同义词,元数据向量路按字符匹配找不到"看看 / 最近 / 谁买得多"这些词,自动降级关键词后仍未命中,回退到全量 schema 交给模型判断。
- 传统做法对比
- 以前这种模糊需求要先约数据分析师"翻译"成"按客户统计订单金额",再排期取数,1~2 天;现在系统几秒返回,但结果可能对也可能要修正——因为模型在"凭全貌猜"。
- 角色
- 销售总监(李经理,非技术用户)。
- 操作步骤
-
- 打开"智能查询",输入"帮我看看最近谁买得多"
- 发送,观察 intent / confidence / rag_context / rag_channels_used
- 查看 SQL 说明,判断模型理解成了"订单数"还是"销售金额"
- 系统响应
- 意图兜底 data_query、confidence=0.5;rag_context 是"全量 schema"而非命中表;模型可能生成"按客户汇总销售额"的 SQL:
{
"intent": "data_query", "confidence": 0.5,
"rag_channels_used": [],
"rag_context": "Table: orders\n - order_id (INTEGER)\n - sales_amount (REAL)\n - customer_id (INTEGER)\n...",
"sql_query": "SELECT c.customer_name, SUM(o.sales_amount) AS total FROM orders o JOIN customers c ON o.customer_id = c.customer_id GROUP BY c.customer_name ORDER BY total DESC"
}
- 结果洞察
- 冷门问法下 RAG 各通道命中率都低(rag_channels_used 为空或只命中无关通道)、回退全量,模型按"买得多 = 金额高"理解,结果(张三 2985、李四 2487.5、王五 998)其实是合理的;但这是"模型猜对了",换成别的表达可能猜错——必须核对 sql_explanation。
- 调整建议
- 把问题说成"表格语言":"按客户统计销售金额";让张工用 ai_generate_descriptions 重导元数据生成同义词(如 sales_amount → 销售额、买了多少)并重建索引,下次就能命中销售列、给模型更聚焦的上下文。
- 动手试一试
- 登录:admin / admin1。输入内容:"帮我看看最近谁买得多"。预期结果:confidence=0.5、rag_context 为全量 schema;再输入"按客户统计销售金额"对比 rag_channels_used 是否命中 metadata。
- 限制提示
- 兜底置信度仅 0.5;回退全量时模型更容易选错表 / 列,结果必须人肉核对;口语词命中不了是关键词/字符匹配的预期行为,补描述与同义词并重建索引才能改善。
故事 4
张工补描述生成同义词并重建索引,RAG 元数据路命中率提升
场景:元数据调优
角色:数据工程师
耗时:约 15 分钟
- 背景
- 张工是数据工程师。他翻 RAG 调用日志统计了近一周检索,发现约 40% 走了"全量回退"——也就是各通道都没命中。检查元数据后发现:默认导入只复制表结构,表 / 列的 description 与 synonyms 全是空的,向量路按"字符重叠"几乎打不中。他用"AI 生成描述"重导一次元数据,再重建向量索引,让 LLM 自动补上业务描述与同义词。
- 传统做法对比
- 以前提升检索效果要么改代码、要么上更重的检索服务,动辄 1~2 天排期;现在"导入元数据"接口带 ai_generate_descriptions=true 参数,调一次 LLM 就把描述与同义词批量补齐,再点一次"重建索引"即可,当天见效。
- 角色
- 数据工程师(张工)。
- 操作步骤
-
- 登录 admin,确认数据源 aip_demo_warehouse 已注册
- 调用 POST /api/v1/datasources/:id/import-metadata?ai_generate_descriptions=true
- 调用 POST /api/v1/rag/index/rebuild 重建元数据向量索引
- 用几条真实问法回归测试,看 rag_channels_used / rag_context 命中情况
- 对比优化前后的命中率
- 系统响应
- 导入返回统计,重建返回索引结果;同一句"最近谁买得多"优化前回退全量,优化后命中销售相关列:
-- import-metadata 返回(示意)
{ "status": "success", "message": "Metadata import complete. Created 0 tables and 0 columns. Updated 3 tables and 12 columns." }
-- index/rebuild 返回(示意)
{ "code": 0, "data": { "data_source": "aip_demo_warehouse", "items": 15, "indexed": 15, "failed": 0, "degraded": false, "collection": "metadata_embeddings" } }
-- 优化后 RAG 上下文(不再回退全量)
Table: orders
- sales_amount (REAL) (销售额)
Table: customers
- customer_name (TEXT) (客户名)
- 结果洞察
- LLM 生成的同义词(如 sales_amount → 销售额 / 金额)写进了 column_schemas.synonyms,"谁买得多"因此命中销售列,RAG 只给相关表列,Text2SQL 上下文聚焦;张工从调用日志统计,全量回退明显减少、元数据路命中率明显提升。
- 调整建议
- ai_generate_descriptions 会调用 LLM,注意 key 配置与成本;生成后抽查描述质量,错的在元数据层面纠正;演示库每次重启重建,生成结果与索引也会重来,正式环境建议把"导入+重建索引"固化进初始化流程。
- 动手试一试
- 登录:admin / admin1。接口:POST /api/v1/datasources/:id/import-metadata?ai_generate_descriptions=true,POST /api/v1/rag/index/rebuild。操作:先按默认方式导入,输入"谁买得多"看全量回退;再带参数重导 + 重建索引,重问同一句。预期结果:优化后 rag_context 命中销售相关列,不再回退全量。
- 限制提示
- 该参数依赖 LLM 可用,无 key 时会降级或失败;生成的是"描述性元数据",不代表数据本身变干净;列级命中只带命中列,若 SQL 还需要其它列,可能要用含列名的问法再问一次。
常见问题
意图识别准吗?
v0.1 是关键词规则:命中关键词即返回固定置信度(知识问答 0.9、分析 0.85、数据查询 0.8,兜底 0.5)。演示稳定、可复现,但真实语义级的意图识别在后续版本,现在换说法可能分错类。
rag_context / rag_channels_used 是什么?
是聊天响应里的字段:rag_context 展示 RAG 送给 Text2SQL 的上下文(命中表 / 列及描述);rag_channels_used 列出实际启用的检索通道(metadata/knowledge/history/fewshot)。看到 context 是"全量 schema"就说明各通道都没命中、回退了。
四路召回是哪四路?权重多少?
metadata(元数据向量,0.40)、knowledge(知识库混合检索,0.25)、history(对话历史 5 轮,0.20)、fewshot(历史成功样本 Top3,0.15)。管理员可用 PUT /api/v1/rag/channels 调开关与权重。
为什么"什么是订单"不返回订单数据?
问句命中知识问答关键词(什么是 / 定义 / 解释等),优先级最高,走 knowledge_qa 占位。最小链路不包含知识库,因此返回提示文案而非数据。
怎么提升 RAG 命中率?
两条路:一是数据侧用 ai_generate_descriptions=true 重导元数据并 POST /rag/index/rebuild 重建索引;二是问法侧多用表名 / 列名词。命中情况用响应里的 rag_channels_used 字段验证。
同义词生成后会被覆盖吗?
会。演示数据源每次启动重建,元数据也重建,ai_generate_descriptions 生成的内容会丢,索引也需重建。正式环境需要把"导入 + 重建索引"固化进初始化流程。
主题小结
一句话:NLQ 的第一公里是"规则 + 四路 RAG"——意图识别定方向、RAG 给上下文。简单问法又快又稳;口语化、歧义、缺元数据是它的天敌。解法就两条:把话说得像表名 / 列名,或让数据工程师用 ai_generate_descriptions + 重建索引把元数据补全。