为什么 Data Agent 需要 RAG

Text-to-SQL 管道解决的是「命中指标 → 拼 SQL → 执行」的确定性路径。但企业问数场景里还有大量半结构化知识

知识类型 示例 适合载体
指标定义 销售收入 = 已确认订单含税金额 MySQL bi_metric
取数逻辑 宽表 dws_sales_metric_wideindex_name='销售收入' MySQL bi_metric_extract_logic
业务规则 客户留存率分母为上月活跃客户 Markdown + 向量
口径说明 华东区与华北区组织层级差异 Markdown + 向量
FAQ 「新增客户数」是否含试用客户 Markdown + 向量

RAG(检索增强生成) 在 Data Agent 中的定位:当结构化元数据无法直接命中时,从知识库召回相关片段,辅助域分类、指标消歧、结果解释——而不是让 LLM 凭空编造口径。

知识分层架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
flowchart TB
subgraph L1["L1 结构化元数据(主路径)"]
BD[bi_domain 业务域]
BM[bi_metric 指标定义]
BL[bi_metric_extract_logic 取数逻辑]
BT[bi_table 表白名单]
end
subgraph L2["L2 向量知识库(fallback)"]
MD[Markdown 文档]
CH[(Chroma 向量索引)]
BGE[bge-m3 Embedding]
end
subgraph L3["L3 运行时上下文"]
QA[qa_history 会话历史]
FB[qa_feedback 用户反馈]
end
Q[用户问题] --> RET[retrieve_all]
RET -->|优先| L1
RET -->|未命中/低分| L2
MD --> BGE --> CH
RET --> L3

设计原则:MySQL 优先、向量兜底。生产 SQL 生成只依赖 L1;L2 用于解释、消歧与运营沉淀。

MySQL 结构化检索

指标关键词打分

retrieve_all 对 metrics 分支走 MySQL LIKE + 打分排序(虚构示例):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SELECT
m.metric_code,
m.metric_name,
m.domain_code,
(
CASE WHEN m.metric_name = '销售收入' THEN 10 ELSE 0 END +
CASE WHEN m.alias LIKE '%销售收入%' THEN 5 ELSE 0 END +
CASE WHEN m.keywords LIKE '%华东区%' THEN 2 ELSE 0 END
) AS score
FROM bi_metric m
WHERE m.status = 1
AND (
m.metric_name LIKE '%销售收入%'
OR m.alias LIKE '%销售收入%'
OR m.keywords LIKE '%销售收入%'
)
ORDER BY score DESC
LIMIT 5;

取数逻辑关联

命中 M_SALES_REVENUE 后,关联取数逻辑与表白名单:

1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT
l.metric_code,
l.table_code,
l.index_name_value,
l.default_filter,
t.table_name_cn,
t.is_whitelisted
FROM bi_metric_extract_logic l
JOIN bi_table t ON t.table_code = l.table_code
WHERE l.metric_code = 'M_SALES_REVENUE'
AND t.is_whitelisted = 1
ORDER BY l.is_default DESC, l.priority DESC
LIMIT 1;

返回:table_code = dws_sales_metric_wideindex_name_value = 销售收入default_filter = is_valid = '1'

Chroma 向量 fallback

何时触发

条件 行为
MySQL metrics 最高分 < 阈值(如 3) 走向量检索
用户问业务规则类(「留存率怎么算」) 并行走向量
域分类结果为「未知」 扩大向量 top_k

索引构建流程

1
2
3
4
5
6
flowchart LR
A[扫描 knowledge/ 目录] --> B[按 H2 切分 chunk]
B --> C[清洗:去 front-matter]
C --> D[bge-m3 向量化]
D --> E[写入 Chroma collection]
E --> F[记录 doc_id + source_path]

chunk 策略:以 Markdown ## 标题为边界,每块 200–800 字;元数据附带 domainmetric_tagsupdated_at

检索示例(Python 伪代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def retrieve_vector(question: str, top_k: int = 5) -> list[dict]:
embedding = embed_model.encode(question)
results = chroma_collection.query(
query_embeddings=[embedding],
n_results=top_k,
where={"domain": {"$in": ["销售运营域", "通用"]}},
)
return [
{
"content": doc,
"source": meta["source_path"],
"score": 1 - distance,
}
for doc, meta, distance in zip(
results["documents"][0],
results["metadatas"][0],
results["distances"][0],
)
]

Markdown 知识库规范

建议目录结构(虚构):

1
2
3
4
5
6
7
8
9
10
knowledge/
├── metrics/
│ ├── 销售收入.md
│ ├── 客户留存率.md
│ └── 新增客户数.md
├── rules/
│ ├── 区域口径说明.md
│ └── 时间周期约定.md
└── faq/
└── 常见问法映射.md

指标文档模板

1
2
3
4
5
6
7
8
9
## 销售收入

- **指标编码**:M_SALES_REVENUE
- **业务域**:销售运营域
- **口径**:已确认订单的含税销售金额,不含退款冲减
- **数据源**:dws_sales_metric_wide
- **过滤条件**:index_name = '销售收入' AND is_valid = '1'
- **常见维度**:region_name(华东区、华北区)、period(月/季/年)
- **易混淆项**:与「新增客户数」不同,收入是金额类指标

业务规则文档示例

1
2
3
4
5
6
## 客户留存率口径

- **公式**:本月仍活跃客户数 / 上月活跃客户数 × 100%
- **活跃定义**:当月至少产生一笔有效订单
- **默认过滤**:is_valid = '1'
- **区域维度**:region_name,支持华东区、华北区下钻

retrieve_all 并行策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sequenceDiagram
participant Q as 用户问题
participant R as retrieve_all
participant M as MySQL
participant V as Chroma
participant O as 结果合并

Q->>R: 华东区客户留存率同比
par 并行检索
R->>M: metrics 关键词
R->>M: bi_models 语义模型
R->>M: business_rules 规则表
R->>V: 向量 fallback
end
M-->>O: 结构化命中列表
V-->>O: 文档片段列表
O-->>Q: 统一 RetrieveResult

合并规则:

  1. metrics 有高分命中 → 标记 primary_metric,进入 SQL 管道
  2. 向量片段仅进入 context_for_explain,不参与 SQL 拼接
  3. 多指标同分 → 返回 needs_clarification,让用户选择

知识库运营

运营动作 频率 负责人
新增指标同步 MySQL + Markdown 每次指标发布 数据治理
重建 Chroma 索引 每周或文档变更后 平台运维
检索日志分析(低分问法) 每月 产品经理
口径争议沉淀为规则文档 按需 业务 + BI

索引重建脚本(示意)

1
2
3
4
5
# 清空并重建向量索引
python scripts/rebuild_chroma_index.py \
--source knowledge/ \
--collection metric_kb \
--model BAAI/bge-m3

与 Text-to-SQL 的协作边界

阶段 RAG 角色
域分类 辅助关键词扩展(可选)
指标检索 MySQL 主检索,向量补召回
SQL 生成 不参与,只用 bi_metric_extract_logic
结果解释 注入向量片段,生成口径说明
追问澄清 参考 FAQ 文档生成建议问法

红线:向量检索到的表名、字段名不得直接进入 SQL,必须经过表白名单与取数逻辑校验。

本章小结

  • 企业指标知识分三层:结构化元数据(主)、向量 Markdown(辅)、运行时上下文(会话)
  • retrieve_all 并行检索,MySQL 打分优先,Chroma 作 fallback
  • Markdown 知识库应有统一模板,与 bi_metric 编码对齐
  • RAG 服务解释与消歧,不替代元数据驱动的 SQL 生成

思考题

  1. 若 MySQL 与 Markdown 对同一指标的口径描述不一致,应以哪个为准?如何发现?
  2. 向量 chunk 切太大或太小,分别会导致什么检索问题?
  3. 什么类型的用户问题应该只走向量、不查 MySQL?

系列导航

主题
01 架构全景
02 Text-to-SQL
03 本篇
04 多轮澄清
05 安全校验
06 Vue3 工作台
07 演示验证
08 反馈闭环

← 返回专题首页