01 项目概述与环境搭建
学习理念:理解"掌柜问数"要解决什么问题、数仓的星型模型怎么设计、元数据知识库的三元组结构(MySQL+Qdrant+ES)。这一章全是概念,不涉及编码,是后续所有编码的基础。
海外对标:Databricks Genie(自然语言查询数据湖)、Salesforce X-SQL(CRM 数据 Text2SQL)
本节 AI 替代率:~85% | 人工干预率:~15%
| 角色 | 能力范围 |
|---|---|
| 🤖 AI 擅长 | 生成数仓模型介绍、SQL 查询示例、Docker Compose 配置 |
| 👤 人类需理解 | 元数据知识库的三存储设计思想、星型模型"事实表+维度表"的关联方式 |
一、项目概述
掌柜问数是一个基于自然语言处理与数据分析技术的智能数据服务系统,面向数据仓库应用场景,旨在帮助用户通过对话方式高效获取数据仓库中的数据洞察。用户无需掌握复杂的查询语法,即可用自然语言提出问题,系统自动完成对数据仓库数据的理解、计算分析与结果可视化,大幅提升数据使用效率,降低数据分析门槛,助力业务决策智能化。

数据仓库(DW-Data Warehouse)是面向分析、集成化、非易失性、随时间变化的企业级数据存储系统,核心作用是把企业分散在各个业务系统(如电商的交易系统、物流的仓储系统、CRM 的客户系统、 Elasticsearch/Qdrant 检索库、MySQL 业务库等)的零散数据,经过抽取、清洗、转换、加载 后,按主题域整合存储,最终支撑企业的数据分析、报表统计、经营决策、数据挖掘等场景。
数仓数据来源
1)业务系统对应业务库,是数仓最主要、最基础的数据来源。
- 关系型数据库MySQL、SQL Server、Oracle等
- 订单、用户、商品、支付、物流、会员、库存等
- 方式:CDC(实时)、全量 / 增量获取
2)日志数据(行为数据)
用户行为、系统行为、埋点数据。
- App / 小程序 / 网站埋点日志
- 服务端日志、Nginx 日志
- 方式:Kafka、Logstash采集
简单说:业务库管 "干活"(支撑日常交易 / 操作),数据仓库管 "复盘"(支撑分析 / 决策),掌柜问数 —— 问一句,出报表,人人都是数据掌柜
项目意义:告别写 SQL,告别等数据,自然语言一问,秒出结果、秒懂经营。让数据会说话,让决策更简单。
- 不用代码、不用 SQL、不用培训
- 像聊天一样,用日常语言问业务、查指标、看趋势
- 自动理解表结构、生成 SQL、返回可视化 结果
- 业务人员自助查数,数据团队解放双手
- 让每一位管理者、运营、业务员,都能轻松掌数
二、项目架构
2.1 概述
本项目以数据仓库的元数据为核心,使用 MySQL 存储结构化元数据信息,结合 Qdrant 构建语义向量索引、Elasticsearch 构建全文索引,形成统一的元数据知识库。查询过程中,系统首先根据用户自然语言问题进行多路召回,筛选相关表、字段及指标定义,再将元数据信息与用户问题共同输入大模型生成 SQL,最终完成自动查询与结果返回,确保生成结果的准确性与可控性。

2.2 数仓-数据库
数据仓库采用了数据仓库领域最经典的星型模型:
事实表(Fact Table):fact_order(订单事实表)—— 存储核心业务交易数据("发生了什么");
维度表(Dimension Table):dim_region/dim_customer/dim_product/dim_date(4 张维度表)—— 存储描述性信息("交易的上下文");

事实表:
fact_order(核心业务数据)字段 类型 作用 示例 order_idVARCHAR(30) 订单主键(唯一标识订单) ORD20250101001customer_idVARCHAR(20) 关联客户维度表 C001(对应李伟)product_idVARCHAR(20) 关联产品维度表 P001(对应 iPhone 15 Pro)date_idINT 关联日期维度表 20250101(2026 年 1 月 1 日)region_idVARCHAR(20) 关联区域维度表 R001(对应广东省)order_quantityINT 订单数量(度量值) 1(购买 1 台手机)order_amountFLOAT 订单金额(核心度量值) 8999.00(iPhone 15 Pro 售价)维度表(描述上下文)
维度表 核心字段 作用 典型分析维度 dim_regionprovince/region_name订单所属区域 按省份 / 大区(华南 / 华东)分析销量 dim_customergender/member_level客户属性 按性别 / 会员等级分析消费能力 dim_productcategory/brand产品属性 按品类(手机数码 / 家用电器)/ 品牌分析销量 dim_dateyear/quarter/month时间属性 按年 / 季度 / 月分析销售趋势
数据仓库的核心价值:
分析灵活:星型模型支持 "多维度组合分析",比如:
- 分析 "2026 年 Q1 华东地区黄金会员购买手机数码类产品的总金额";
- 分析 "2026 年 2 月广东省女性客户购买家用电器的订单数量";
性能优化:维度表数据量小(比如dim_customer只有 20 条),事实表数据量大但结构简单,关联查询效率高;
灵活扩展:新增维度(如dim_payment支付方式)只需加一张维度表,不影响现有表结构。
典型查询场景:
场景 1:2026 年 Q1 总订单金额 预期结果:所有 2026 年 1-3 月订单金额总和(约 50 万 +)。
SELECT SUM(f.order_amount) AS total_amount
FROM fact_order f
JOIN dim_date d ON f.date_id = d.date_id
WHERE d.year = 2026 AND d.quarter = 'Q1';场景 2:2026 年 1 月各省份订单金额排名: 预期结果:广东省(R001)、上海市(R005)、浙江省(R002)金额靠前。
SELECT r.province, SUM(f.order_amount) AS province_amount
FROM fact_order f
JOIN dim_region r ON f.region_id = r.region_id
JOIN dim_date d ON f.date_id = d.date_id
WHERE d.year = 2026 AND d.month = 1
GROUP BY r.province
ORDER BY province_amount DESC;场景 3:黄金会员购买苹果品牌产品的总数量 预期结果:黄金会员购买苹果产品的总数量(比如李伟、张敏等黄金会员购买的 iPhone 15 Pro 数量)
SELECT p.category, SUM(f.order_amount) AS category_amount
FROM fact_order f
JOIN dim_product p ON f.product_id = p.product_id
JOIN dim_date d ON f.date_id = d.date_id
WHERE d.year = 2026 AND d.month = 2
GROUP BY p.category
ORDER BY category_amount DESC;场景 4:2026 年 2 月各产品品类的订单金额 预期结果:手机数码类(iPhone/Samsung/ 华为)金额最高,其次是家用电器。
SELECT SUM(f.order_amount) AS female_platinum_amount
FROM fact_order f
JOIN dim_customer c ON f.customer_id = c.customer_id
JOIN dim_date d ON f.date_id = d.date_id
WHERE d.year = 2026 AND d.quarter = 'Q1'
AND c.gender = '女' AND c.member_level = '铂金';场景 5:2026 年 Q1 女性铂金会员的消费金额 预期结果:陈静、周燕、高梅等铂金女性会员的总消费金额。
SELECT SUM(f.order_amount) AS female_platinum_amount
FROM fact_order f
JOIN dim_customer c ON f.customer_id = c.customer_id
JOIN dim_date d ON f.date_id = d.date_id
WHERE d.year = 2026 AND d.quarter = 'Q1'
AND c.gender = '女' AND c.member_level = '铂金';2.3 元数据知识库
元数据知识库是数据仓库的 "说明书中心"—— 它把数据仓库里的表、字段、指标等信息,统一整理成 "结构化的元数据",让智能体(或用户)能快速理解数据仓库的结构,最终实现 "用自然语言生成 SQL 查询" 的目标。
元数据知识库作为数据仓库的语义基础设施,用于集中管理和高效检索表结构、字段定义、字段取值示例及复杂指标说明等元数据信息,支撑后续的智能检索与 SQL 生成。
元数据信息主要来源于两部分:一部分数据仓库自动采集,另一部分由人工进行补充与配置。完整的元数据统一存储于 MySQL 数据库中,并对其中部分关键信息构建向量索引和全文索引,以提升语义召回与关键词召回的效果。
2.3.1 元数据库
元数据库共包含四张表,具体结构如下图所示:

元数据库核心表转换过程:
转换到
table_info(表信息)table_info 字段 填入的内容(以 fact_order为例)id fact_order(表名作为ID) name fact_order role fact (角色:事实表) description 订单事实表,记录订单数量和金额等核心指标。 table_info 字段 填入的内容(以 dim_region为例)id dim_region(表名作为ID) name dim_region role dim (角色:维度表) description 地区维度表,用于描述订单发生的地理区域信息。 
转换到
column_info(字段信息)column_info 字段 填入的内容(以 fact_order.order_amount为例)id fact_order.order_amount(表名.列名) name order_amount type FLOAT role measure (角色:度量) examples ["8999.00", "6999.00"](JSON 格式) description 订单实付金额,单位:元,不含运费 / 优惠 alias ["订单金额", "实付金额"](JSON 格式) table_id table_fact_order(关联 meta.table_info 的 id) column_info 字段 填入的内容(以 dim_customer为例)id dim_customer.member_level(自定义唯一 ID) name member_level type varchar(20) role dimension 解释:维度 examples ["黄金", "白银", "青铜", "铂金", "钻石", "星耀"] description alias ["会员等级", "用户等级"](JSON 格式) table_id dim_customer(关联 meta.dim_customer的 id) 
metric_info(指标信息)metric_info 字段 填入的内容(以 "订单金额" 为例) id GMV name GMV description 全称Gross Merchandise Value,表示所有订单的成交金额总和。 relevant_columns ["fact_order.order_amount"](JSON 格式) alias [成交总额, 订单总额](JSON 格式) 计算逻辑:SUM(fact_order.order_amount)
metric_info 字段 填入的内容(以 "平均订单金额" 为例) id AOV name AOV description 全称Average Order Value,表示所有订单的成交金额平均值。 relevant_columns ["fact_order.order_quantity"](JSON 格式) alias [平均单价、平均订单金额](JSON 格式) 计算逻辑:SUM(fact_order.order_amount) / COUNT(DISTINCT fact_order.order_id)
转换到
column_metric(字段 - 指标关联)column_metric 字段 填入的内容(关联 "省份月度销售额" 指标) column_id fact_order_order_amount(关联金额字段) metric_id GMV column_id fact_order_order_quantity(关联数量字段) metric_id AOV
元数据知识库录入数据仓库信息:
table_info录入fact_order/dim_region等表的信息(表名、类型fact/dim、描述);column_info录入各表字段信息(比如order_amount的类型FLOAT、角色measure、描述 "订单金额");metric_info录入业务指标(比如 "省份月度销售额" 关联fact_order.order_amount+dim_region.province+dim_date.month);
智能体基于元数据生成 SQL:
用户问 "2026 年 Q1 华东地区黄金会员购买手机数码类产品的总金额",智能体通过元数据知识库匹配:
指标:总金额 → 关联
fact_order.order_amount;维度:2026 年 Q1 → 关联
dim_date.year=2026+quarter='Q1';维度:华东地区 → 关联
dim_region.region_name='华东';维度:黄金会员 → 关联
dim_customer.member_level='黄金';维度:手机数码类 → 关联
dim_product.category='手机数码';最终自动生成对应的 JOIN 查询 SQL。
一句话总结:数据仓库是 "数据载体",元数据知识库是 "数据说明书",两者结合实现 "自然语言转 SQL" 的智能分析。
2.3.2 向量索引
本项目选用 Qdrant 作为向量数据库,向量索引主要用于对字段信息和指标信息进行语义召回。向量索引的构建内容具体如下:
字段信息
column_info 需要建立向量索引的字段如下图所示:

具体示例如下图所示:

指标信息
metric_info 需要建立向量索引的字段如下图所示:

具体示例如下图所示:

2.3.4 全文索引
本项目使用 Elasticsearch 作为全文检索引擎,全文索引主要用于对字段取值进行检索与匹配,索引内容以各类维度值为主,具体如下:

具体示例如下图所示:

2.4 问数智能体
本项目的智能体主体基于Langgraph构建,具体结构如下图所示:

三、项目开发环境
3.1 创建项目
1.在anaconda命令行里新建虚拟环境:
conda remove -n py312 --all # 可选:直接删除环境及所有安装的包
conda create -n py312 python=3.12 #创建虚拟环境执行Python版本2.激活环境:
conda activate py3123.下载项目所需的全部依赖:
pip install asyncmy cryptography "elasticsearch[async]>=8,<9" fastapi[standard] huggingface-hub jieba langchain langchain-deepseek langchain-huggingface langgraph loguru omegaconf pyyaml qdrant-client sqlalchemy各依赖说明如下:
- fastapi[standard]:高性能异步 Web 框架,作为整个服务的 API 入口。
- sqlalchemy:Python 最主流 ORM,用统一模型管理数据库读写与事务。
- asyncmy:MySQL 的高性能 asyncio 驱动,配合 SQLAlchemy 实现全异步数据库访问。
- qdrant-client:向量数据库客户端,用于 Embedding 向量存储与相似度检索。
- elasticsearch[async]:异步 Elasticsearch 客户端,用于全文检索。
- langchain:LLM 应用编排框架,用于构建 RAG、Tool 调用、Prompt 链路。
- langchain-huggingface:LangChain 与 HuggingFace 模型的桥接层(Embedding / LLM 加载)。
- langgraph:用图结构构建可控 Agent 流程。
- jieba:中文分词库。
- omegaconf:强大的分层配置系统,适合多环境、多模型、多参数管理。
- pyyaml:YAML导入导出。
- loguru:更优雅的日志库,替代 logging,适合工程化项目。
- cryptography:加密与证书基础库,很多网络/数据库/安全库的底层依赖。
本项目使用 python 3.12版本及以上,如下图所示

3.2 搭建开发环境
本项目采用 Docker 管理开发环境,相关容器配置文件已提供于课程资料中的 docker 目录。将该目录拷贝至项目根目录后,进入 docker 目录并执行 docker compose up -d,即可一键启动项目所需的全部基础服务。
【P0 必须理解】 docker-compose.yaml 定义了 5 个基础服务,这是项目运行的前提。完整配置见
2.资料/2.docker compose/docker-compose.yaml。
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: Atguigu.123
ports:
- "3306:3306"
volumes:
- ./mysql:/docker-entrypoint-initdb.d # 自动初始化 dw.sql + meta.sql
elasticsearch:
build: ./elasticsearch
ports:
- "9200:9200"
environment:
discovery.type: single-node
xpack.security.enabled: "false"
kibana:
image: kibana:8.19.10
ports:
- "5601:5601"
depends_on:
- elasticsearch
qdrant:
image: qdrant/qdrant:v1.16
ports:
- "6333:6333" # HTTP
- "6334:6334" # gRPC
embedding:
image: ghcr.io/huggingface/text-embeddings-inference:cpu-1.8
ports:
- "8081:80"
environment:
MODEL_ID: /models/bge-large-zh-v1.5
volumes:
- ./embedding/bge-large-zh-v1.5:/models/bge-large-zh-v1.5
下发资料虚拟机信息: 192.168.200.10 root/root
| 容器 | URL | 账号密码 |
|---|---|---|
| qdrant | http://192.168.200.10:6333 | 无 |
| MySQL | 192.168.200.10:3306 | root/Atguigu.123 |
| Elasticsearch | http://192.168.200.10:9200 | 无 |
| Kibana | http://192.168.200.10:5601 | 无 |
| embedding | http://192.168.200.6:8081 | 无 |
🔥 【P0 必须理解】 这 5 个服务的端口和地址在后端配置(
conf/app_config.yaml)中对应。
3.3 安装所需服务
3.3.1 服务说明
本项目所需的全部服务如下:
- MySQL:用于存储数据仓库的元数据信息,包括表格信息、字段信息和指标信息,同时也充当业务数据仓库使用(模拟 Hive 场景)。
- Qdrant:作为向量数据库,用于存储字段信息、指标信息的向量表示,在用户提问时通过语义相似度检索出最相关的元数据,为生成SQL提供高相关性的上下文信息。
- Elasticsearch:对各维度字段的实际取值建立倒排索引。当用户问题中包含自然语言形式的维度描述时(例如"华北地区"、"数码品类"),可通过全文检索匹配到数据库中真实存在的字段取值,为生成 SQL 时的 WHERE 条件或者GROUP BY分组提供准确依据。
- Kibana:是 Elasticsearch 的可视化管理与调试界面,用于索引管理、查询语句调试以及检索效果验证,方便开发过程中观察和优化检索行为。
- Text Embedding Inference:用于部署 Embedding 模型推理服务,将元数据文本及用户问题转换为向量表示,为 Qdrant 提供向量数据来源,是语义检索能力的基础。
3.3.2 安装
本项目所需的全部基础服务通过 Docker Compose 统一部署。
找到课后资料相关镜像文件,将文件上传到centos服务器

将资料中中dockercompose相关资料上传服务,执行导入docker镜像脚本,将所需docker镜像导入,减少下载镜像时间
bashchmod +x import_docker_images.sh ./import_docker_images.sh相关脚本与依赖文件已包含在项目资料中。进入 docker-compose.yaml 所在目录,执行以下命令即可完成所有服务的安装与启动:
bash#启动所有docker服务 docker compose up -d
四、企业痛点-方案映射
| 痛点 | 传统方案 | AI Agent 方案 | 效率提升 |
|---|---|---|---|
| 业务人员不会写 SQL | 排队等数据团队 | 自然语言直接问 | 查询从小时→秒 |
| 数仓结构复杂难理解 | 翻阅文档 | 元数据知识库自动理解 | 数仓理解从天→分钟 |
| 多维度分析查询复杂 | 手动写 JOIN | 自动识别维度/事实表 | 分析效率 5x |
五、本阶段文件索引
| 优先级 | 文件 | 路径(相对于 data-agent/) |
|---|---|---|
| 🟢 P2 | docker-compose.yaml | 2.资料/2.docker compose/docker-compose.yaml |
| 🟢 P2 | app_config.yaml | conf/app_config.yaml |
| 🟢 P2 | meta.sql / dw.sql | 2.资料/2.docker compose/mysql/ |