资讯动态

基于LLM的智能数据问答系统技术方案

发布时间:2026/10/8 2:54:53 来源:尧图企业网站定制
基于 LLM 的智能数据问答系统技术方案让业务人员用人话查数据而不是写 SQL一、问题引入数据分析师的翻译困境最近跟一位做电商数据分析的朋友聊天他跟我吐槽“业务部门每天问我几百个问题‘上周哪个品类退货率最高’、‘北京区 3 月份销售额环比多少’、‘复购率超过 30% 的用户画像是什么’… 我 80% 的时间都在写 SQL真正做深度分析的时间反而没多少。”这场景是不是很熟悉数据分析师成了SQL 翻译机——业务人员有需求但不懂 SQL分析师懂 SQL但重复劳动太多。本质上这是业务语言和数据语言之间的鸿沟。有没有办法让业务人员直接用人话问数据系统自己把 SQL 写出来这就是我们今天要聊的——基于 LLM 的智能数据问答系统。二、方案分析为什么是 LLM2.1 传统方案的局限在 LLM 火起来之前业界也尝试过一些方案方案原理问题固定报表预定义查询模板灵活性差无法应对临时问题BI 拖拽可视化配置筛选条件学习成本高复杂分析搞不定规则引擎关键词匹配 → 预置 SQL维护成本高泛化能力弱这些方案的共同问题是不够灵活。业务问题千变万化靠穷举或规则很难覆盖。2.2 LLM 带来的可能性LLM大语言模型最擅长的就是理解和生成自然语言。如果我们能让 LLM听懂业务人员的人话问题结合数据表的元信息字段含义、表关系生成准确的 SQL把查询结果再用人话解释回去那不就打通了吗说白了LLM 在这里充当了一个智能翻译官业务问题自然语言 → LLM → SQL → 数据库 → 结果 → LLM → 业务答案自然语言当然这个方案也不是万能的后面会聊到它的边界和坑。三、系统架构设计3.1 整体架构图┌─────────────────────────────────────────────────────────────┐ │ 用户交互层 │ │ Web 界面 / 钉钉/企微机器人 / API │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 智能问答引擎层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ 问题理解 │ │ SQL 生成 │ │ 结果解释与总结 │ │ │ │ (NLU) │→ │ (NL2SQL) │→ │ (Result2NL) │ │ │ └─────────────┘ └─────────────┘ └─────────────────────┘ │ │ │ │ │ ┌─────────┴─────────┐ │ │ ▼ ▼ │ │ ┌──────────┐ ┌──────────┐ │ │ │ 意图识别 │ │ 字段映射 │ │ │ │ 实体抽取 │ │ 表选择 │ │ │ └──────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 数据服务层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ 元数据管理 │ │ 查询执行 │ │ 结果缓存与优化 │ │ │ │ (Schema) │ │ (Executor) │ │ (Cache) │ │ │ └─────────────┘ └─────────────┘ └─────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 数据存储层 │ │ MySQL / ClickHouse / StarRocks... │ └─────────────────────────────────────────────────────────────┘3.2 核心模块说明模块 1元数据管理Schema Manager这是整个系统的地基。LLM 再聪明也不知道你表里每个字段是什么意思。我们需要告诉它有哪些表每张表是干什么的有哪些字段字段类型、含义、取值范围表与表之间怎么关联# 示例元数据配置简化版tables:-name:ordersdescription:订单主表记录用户下单信息columns:-name:order_idtype:BIGINTdescription:订单唯一标识-name:user_idtype:BIGINTdescription:用户 ID-name:order_amounttype:DECIMAL(18,2)description:订单金额元-name:order_statustype:TINYINTdescription:订单状态1-待支付 2-已支付 3-已发货 4-已完成 5-已退款-name:create_timetype:DATETIMEdescription:下单时间-name:usersdescription:用户表columns:-name:user_idtype:BIGINTdescription:用户 ID-name:citytype:VARCHAR(50)description:所在城市-name:register_timetype:DATETIMEdescription:注册时间relations:-from:orders.user_idto:users.user_idtype:LEFT JOINdescription:订单关联用户信息关键点字段描述要写得像人话不要只写字段名。比如order_status的 description 里把枚举值都列出来LLM 生成 SQL 时才知道该用哪些值。模块 2问题理解NLU用户的问题五花八门系统得先听懂用户问上周北京区退货率最高的品类是什么 系统理解 ├── 意图查询QUERY ├── 时间范围上周2026-03-18 至 2026-03-24 ├── 筛选条件城市 北京 ├── 指标退货率 退款订单数 / 总订单数 ├── 维度品类 └── 排序退货率降序取 TOP 1这里可以用 LLM 做意图识别和实体抽取也可以用小模型 规则做预处理降低成本。模块 3SQL 生成NL2SQL这是最核心的环节。把理解后的问题 元数据一起喂给 LLM让它生成 SQL。Prompt 设计关键你是一名资深数据分析师精通 SQL。请根据以下数据库Schema和用户需求生成准确的SQL查询。 【数据库Schema】 {schema_description} 【注意事项】 1. 字段名必须与Schema中一致不要编造字段 2. 时间范围使用 BETWEEN注意日期格式 3. 关联查询使用正确的JOIN条件 4. 聚合函数注意NULL值处理 5. 只返回SQL不要解释 【用户问题】 {user_question} 【SQL】实际生成的 SQL 示例-- 用户问题上周北京区退货率最高的品类是什么SELECTp.category_nameAS品类,COUNT(CASEWHENo.order_status5THEN1END)*1.0/COUNT(*)AS退货率FROMorders oLEFTJOINusers uONo.user_idu.user_idLEFTJOINorder_items oiONo.order_idoi.order_idLEFTJOINproducts pONoi.product_idp.product_idWHEREu.city北京ANDo.create_timeBETWEEN2026-03-18 00:00:00AND2026-03-24 23:59:59GROUPBYp.category_nameORDERBY退货率DESCLIMIT1;模块 4查询执行与安全防护生成 SQL 后不能直接执行安全第一# 伪代码查询执行的安全检查defsafe_execute(sql:str,user:User)-Result:# 1. SQL 语法校验防止注入ifnotsql_parser.is_valid(sql):raiseSQL 语法错误# 2. 敏感操作拦截禁止 DDL、DMLforbidden_keywords[DROP,DELETE,UPDATE,INSERT,ALTER,TRUNCATE]ifany(kwinsql.upper()forkwinforbidden_keywords):raise检测到危险操作已拦截# 3. 权限校验用户只能查有权限的表tablessql_parser.extract_tables(sql)ifnotuser.has_permission(tables):raise无权限访问相关数据表# 4. 添加查询限制防止慢查询拖垮库ifLIMITnotinsql.upper():sql LIMIT 1000# 5. 执行查询只读账号returnreadonly_db.execute(sql)几个关键安全措施使用只读账号连接数据库拦截所有写操作关键字强制加LIMIT防止全表扫描查询超时控制比如 30 秒自动 kill模块 5结果解释Result2NL查出来是一堆数字业务人员可能还是看不懂。让 LLM 再翻译一次查询结果 品类数码配件退货率18.5% LLM 解释 上周北京区退货率最高的品类是数码配件退货率达到 18.5% 意味着每 100 单约有 18-19 单发生退货。建议重点关注该品类的 产品质量和物流体验。这个环节可选但对于非技术用户很友好。四、关键实现细节与踩坑经验4.1 Prompt 工程怎么让 LLM 生成更准的 SQL这是整个系统成败的关键。分享几个实战经验坑 1LLM 瞎编字段名用户问用户的平均客单价LLM 可能生成AVG(order_price)但表里实际叫order_amount。解法在 Prompt 里明确约束——“字段名必须与 Schema 中完全一致禁止编造”。同时做后校验生成的字段名必须在 Schema 里存在。坑 2时间理解错误用户说上周LLM 可能理解错日期范围。解法在 Prompt 里注入当前日期明确时间计算规则。或者在前置模块把上周解析成具体日期范围再传给 LLM。坑 3多表关联搞错用户问北京用户的平均订单金额LLM 可能忘了关联用户表直接用订单表里的地址字段如果有的话。解法在 Schema 里明确标注表关系和关联条件Prompt 里强调必须使用正确的 JOIN。Prompt 优化前后对比【优化前 - 容易出错】 请根据以下表结构生成SQL 表orders(user_id, amount, status, create_time) 问题上周北京用户的平均订单金额 【优化后 - 更稳定】 你是一名资深数据分析师请根据以下信息生成标准SQL 【当前日期】2026-03-25 【表结构】 orders表订单表 - user_id: 用户ID关联users.user_id - amount: 订单金额元 - status: 订单状态1待支付 2已支付... - create_time: 下单时间 users表用户表 - user_id: 用户ID - city: 所在城市 【关联方式】 orders.user_id users.user_idLEFT JOIN 【用户问题】 上周北京用户的平均订单金额 【要求】 1. 时间范围上周 2026-03-18 至 2026-03-24 2. 城市筛选users.city 北京 3. 只统计已支付订单status IN (2,3,4) 4. 使用LEFT JOIN关联users表 5. 字段名必须与Schema一致4.2 模型选择用 GPT-4 还是国产模型场景推荐方案说明复杂查询、多表关联GPT-4 / Claude 3理解能力强准确率高简单单表查询国产大模型通义/文心/智谱成本低响应快高频场景小模型微调固定场景准确率更高成本最低建议先用大模型验证方案可行性跑通后针对高频场景用小模型或 Prompt 优化降低成本。4.3 准确率提升RAG 示例增强如果 LLM 生成的 SQL 老出错可以试试少样本学习Few-Shot【示例 1】 问题昨天销售额是多少 SQLSELECT SUM(amount) FROM orders WHERE DATE(create_time) 2026-03-24 AND status IN (2,3,4) 【示例 2】 问题各城市 3 月订单量排名 SQLSELECT u.city, COUNT(*) FROM orders o JOIN users u ON o.user_id u.user_id WHERE o.create_time BETWEEN 2026-03-01 AND 2026-03-31 GROUP BY u.city ORDER BY COUNT(*) DESC 【当前问题】 ...把历史问题-SQL对作为示例放进 PromptLLM 会照葫芦画瓢准确率显著提升。更进一步可以做成向量检索RAG用户问题 → 向量化 → 检索相似历史问题 → 取 TOP 3 示例 → 拼进 Prompt → LLM 生成 SQL4.4 结果校验怎么知道 SQL 对不对LLM 生成的 SQL 不一定对需要校验机制# 伪代码SQL 结果校验defvalidate_result(sql:str,result:Result,question:str)-bool:# 1. 语法校验能正常执行吗# 2. 结果非空校验有数据返回吗空结果可能是条件写错# 3. 合理性校验数值是否在合理范围# 比如销售额结果是负数肯定有问题# 4. LLM 二次校验可选把 SQL 结果 原问题再给 LLM让它判断是否合理validation_promptf 请判断以下SQL是否正确回答了用户问题 用户问题{question}生成SQL{sql}查询结果{result}请回答合理 / 不合理并说明原因。 returnllm_check(validation_prompt)五、完整流程演示来个完整的例子看看系统怎么跑起来的【Step 1】用户提问 用户帮我看看最近 7 天上海和杭州哪个城市的销售额更高 【Step 2】问题理解 → 意图对比查询 → 时间最近 7 天2026-03-19 至 2026-03-25 → 维度城市上海、杭州 → 指标销售额SUM(amount) → 对比方式两个城市分别计算比较大小 【Step 3】SQL 生成 LLM 生成 SELECT u.city, SUM(o.amount) AS 销售额 FROM orders o LEFT JOIN users u ON o.user_id u.user_id WHERE o.create_time BETWEEN 2026-03-19 AND 2026-03-25 AND u.city IN (上海, 杭州) AND o.status IN (2,3,4) GROUP BY u.city; 【Step 4】安全检查 ✓ 无危险关键字 ✓ 字段存在于 Schema ✓ 用户有权限 ✓ 自动添加 LIMIT 1000 【Step 5】执行查询 结果 | 城市 | 销售额 | |------|----------| | 上海 | 1580000 | | 杭州 | 920000 | 【Step 6】结果解释 最近 7 天上海的销售额为 158 万元杭州为 92 万元。 上海的销售额比杭州高出约 71.7%。 【Step 7】返回用户 展示自然语言结论 数据表格 可选的 SQL 展开六、方案边界与局限聊了这么多优点也得诚实说说这个方案不适合的场景场景问题建议超复杂分析多步推理、因果分析、预测类问题LLM 生成 SQL 搞不定仍需人工分析数据权限极敏感不同用户看到的数据差异很大需要更细粒度的行级权限控制实时性要求极高期望毫秒级响应LLM 调用本身有延迟1-3秒不适合数据质量差表字段混乱、无文档先治理数据再搭问答系统说白了这个系统最适合的场景是业务人员的高频、相对标准化的取数需求问题可以转化为单条 SQL 解决的场景数据表结构清晰、有良好文档七、总结基于 LLM 的智能数据问答系统核心思路很简单用 LLM 做翻译打通业务语言和 SQL 之间的鸿沟。关键成功因素元数据要准字段描述写清楚关系标明白Prompt 要精约束足够多示例足够好安全要严只读账号、危险操作拦截、LIMIT 保护校验要全语法检查、结果合理性判断预期要合理适合标准化取数不适合复杂分析写在最后这个方案我们已经在一个企业级数据平台上落地了覆盖了 80% 的日常取数需求数据分析师终于有时间做真正的分析了。当然实现过程中踩的坑远不止文中所写——比如 LLM 偶尔会把杭州写成杭州市导致查不到数据比如用户问最近有时候指 7 天有时候指 30 天…你在做类似系统时遇到过什么坑或者对这个方案有什么疑问欢迎在评论区交流

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑