资讯详情

基于LLM的自助分析系统:RAG、语义层与NL2SQL实践

📅 2026/10/1 13:37:00 | 华诺云谱 👁 阅读
基于LLM的自助分析系统:RAG、语义层与NL2SQL实践
把业务同学从“排队提数—等数—自己做表”的循环里解放出来是我做这套“基于LLM的智能化自助分析系统”最初的动机。今年我在团队内部从零搭了一套涉及模型选型、RAG知识库、GraphRAG、NL2SQL、语义层设计再到本地化部署和ONNX加速前前后后改了三轮。这篇文章算是阶段性的技术总结把关键设计思路、实测细节和踩坑点写下来供正在做同类系统的同学参考。系统目前稳定支撑了日常经营问答、异常归因和部分风险预警场景业务侧的提数需求明显减少我自己也终于不用半夜起来给人拉数据了。1. 先把这个项目的边界想明白再做系统1.1 自助分析到底要解决什么问题很多团队做自助分析系统第一反应是“我要做个能聊天的BI”然后直接把大模型接到数据库上让业务同学用自然语言问问题。这个方向没有错但落地时会被现实狠狠教育业务问的不是SQL能直接回答的问题而是一个缺失了业务语境的自然语言表达。比如业务说“看看这个月的复购率”系统如果直接把这个话转成SQL十有八九会查错。因为在数据仓库里“复购率”可能不存在这张表里它需要先定义“什么叫复购”——是第二次下单就算还是30天内再次购买才算分母是首购用户数还是全部下单用户数这些口径问题不解决模型再强也白搭。所以我在项目启动时就把核心目标定义清楚了系统要让业务用自然语言完成“取数—看数—解释数”三个动作但背后必须有一个可靠的语义层和知识库兜底而不是让LLM裸奔着去访问数据库。我宁可把系统复杂30%也不希望上线后天天被业务投诉数据不对。这个项目适合谁来参考如果你是数据平台组、BI工程团队、内部工具组的同学正在纠结怎么把LLM接入数据体系这篇文章会比较对路子。如果是做To B产品的也可以借鉴里面的架构思路但商业化的要求会更多需另谈。1.2 LLM在系统里的角色和边界它不是数据库是翻译器我对LLM的定位只有一句话它是把“自然语言”翻译成“可执行分析任务”的翻译器而不是数据存储或计算引擎。SQL还是要走查询引擎图表还是要走可视化组件LLM只负责理解意图、编排流程、生成代码、解释结果。这个定位直接决定了工程边界LLM不直接连生产数据库只允许通过中间层拿数据中间层做权限、限流和审计。LLM生成的SQL必须经过校验器和白名单检查只允许只读查询严禁拼接执行。LLM的“话”不能直接呈现给业务必须等数据结果出来后再基于真实结果组织成结论避免它自说自话。关键决策仍由人确认比如生成一个可疑的分析结论系统要标注“置信度低”或给出正反证据而不是让模型一锤定音。我见过不少翻车案例都是因为过度信任模型输出结果业务拿着错误数据做了经营决策。自助分析系统本身是风险放大器如果数据口径和生成逻辑不设防整个系统的业务信任度会在一次错误问答后归零。所以前期宁可功能少一点也要把质量和安全机制先做扎实。2. 系统架构与关键选型每一个选择都要有理由2.1 模型选型托管API还是本地部署这是项目启动后第一个争议点。团队里有同学觉得直接调商业API最快也有同学担心数据出域风险。我的态度是先分清场景再定选型不要一刀切。我整理过一张对比表发在团队内部当决策依据维度托管API本地部署初始成本低按Token付费高需要GPU服务器和运维人力数据安全数据出域需要合规审批数据不出内网合规风险低模型能力强闭源大模型通常指令跟随更好取决于选的模型开源模型已接近够用可控性受供应商更新和限流影响完全可控可改造可定制延迟不稳定取决于网络和供应商可控内网延迟低长期成本量大后成本成倍增长一次性投入后边际成本低最终我们选了混合路线对外能做脱敏的、不涉及核心经营数据的场景走API涉及核心经营数据、用户隐私的场景走本地模型。本地模型选的是基于Qwen系列开源权重微调的版本配合Int8量化部署在一台双卡机器上满足绝大多数内部场景。这里要提醒一点不要只看开源榜单上的跑分。Open LLM Leaderboard这类公开榜单有一定参考价值但业务场景的SQL生成和中文知识问答能力榜单体现不出来。我建议自己建一套30~50条的业务评测集每条都覆盖真实口径和真实表结构本地和API各跑一遍对比再定。2.2 RAG与知识本体让模型先查后答而不是凭空编纯靠提示词很难让LLM稳定记住企业的指标口径因为模型训练用的通用数据里根本没有你公司的“复购率”定义。这时候必须引入RAG检索增强生成在模型回答前先从知识库里把相关口径、表结构、业务规则检索出来再和用户问题一起交给LLM。但这里有个初学者常踩的坑把一堆表结构文档直接扔进向量库然后期待模型每次都检索对。实际上向量检索对文本相似度很敏感业务问法千变万化经常检索不到正确口径。我从RAG做到GraphRAG再回到知识本体设计才把这个问题压住。简单说我给知识库设计了本体结构不再只存“文档片段”而是存实体和关系业务对象用户、订单、商品、门店、供应商等。指标复购率、客单价、毛利率、库存周转天数等每个指标绑定明确的口径、计算公式、适用时间范围、负责团队。维度渠道、区域、品类、时间粒度等。关系指标与指标之间的派生关系、指标与维度之间的可用关系、表与表之间的关联键。这套本体既可以存储成传统RAG的文本块也可以导出成图结构供GraphRAG使用。GraphRAG这种基于知识图谱的检索方式在处理“A指标上涨对B指标的影响”“跨多个表的关联分析”这类多跳问题时比我直接做向量相似度检索靠谱得多。推荐关注LLM Wiki这类开源项目它提出的本体驱动知识库思路很适合做企业口径管理。2.3 语义层与LLM网关给模型装好“护栏”架构里如果少了语义层LLM会频繁因为“这个字段名看不懂”而生成错误SQL。我在数据库和LLM之间加了一层语义层把物理表字段映射成业务概念物理字段业务别名所属维度user_id用户ID、客户编号用户维度order_pay_time下单时间、支付时间时间维度goods_amount_excluding_tax商品金额、税前金额金额事实这层映射让模型不用去猜“user_id”是什么它只需要理解“用户ID用户维度”SQL模板由语义层配合SQL生成器来拼装。此外我还加了一个LLM网关统一管理所有模型的调用。网关负责模型路由简单问题走小模型难题走大模型省钱又稳定。限流与降级API不稳定时自动切到本地模型避免服务不可用。成本核算按部门、按功能统计Token消耗让预算透明。审计日志记录每一次模型输入输出方便复盘和追责。没有网关的情况下模型调用散落在各个业务接口里出了问题没人说得清楚是哪段流程、哪个模型、哪个提示词导致的。有了网关之后排查问题效率提高非常多。3. 核心细节Token、上下文与三要素提示词3.1 把Token开销算明白为什么你的成本突然失控做LLM应用不懂Token只会被账单教育。Token是模型处理文本的最小单位中文大致是1个汉字≈1~2个Token英文一般一个词≈1~2个Token。我们每轮问答的Token支出由五部分组成系统提示词system prompt每次请求都带固定消耗。用户问题改写后的中间结果。检索出来的知识片段RAG返回的口径内容。多轮对话历史好几轮上下文一起塞进去。模型生成的答案和SQL按输入输出双向计费。我算过一个典型问答固定系统提示词约800个Token检索片段约1200个Token加上用户问题和历史输入一次大概3000~4000个Token模型输出约500~1000个Token。以商业API价格粗略估算一轮问答成本几厘钱到几分钱看着不多但一天几千次调用成本就非常可观了。省钱的关键是三个减冗余、控历史、做缓存。系统提示词里不要放无关内容别把企业文化写在里面。多轮对话历史做截断只保留最近2~3轮超长历史用摘要替代。相同问题和相同检索结果可以做结果缓存尤其适合高频的经营日报查询。3.2 理解注意力机制Key、Query、Value的语义三角Transformer的核心注意力机制中每个Token会生成三个向量Key、Query、Value。业界有个很通俗的解释我很喜欢Key是“我是谁”Query是“我在找什么”Value是“我能提供什么”。注意力计算就是让每个Query去匹配所有Key再用匹配到的权重去加权对应的Value。这个三要素模型不只是纸上概念它直接指导了我设计知识库条目和提示词查询侧“我在找什么”用户带着问题来系统要把问题拆成明确的检索意图比如“复购率”对应指标口径查询“会员客单价异常”对应归因分析查询。检索侧“我是谁”知识库里的每条口径都要写明它属于哪个指标、哪个主题域、适用什么场景并把这些信息写进该条目的Key描述中。内容侧“我能提供什么”每条知识库条目要包含明确的答案、公式、场景示例让模型在检索后不用自己发散补充。我在实际建设指标知识库时要求每条记录必须包含三段式结构我是谁指标名、所属域、别名。我在找什么这条口径适用的典型问题以及它的反例问题防止误召回。我能提供什么计算逻辑、SQL示例、口径说明、业务含义。这样模型拿到的知识既有定位又有边界比单纯贴一段文档好用得多。3.3 提示词模板的工程化写法提示词不要每个人随手写要当成代码一样做工程化管理。我建议在一个目录下统一维护提示词模板每个模板有版本号测试通过后封板防止线上改坏。以SQL生成任务为例我的模板结构大致是系统人设说明助手职责、工作边界、禁止事项。业务上下文当前数据源、语义层说明、日期范围。任务说明让模型按步骤生成SQL不要跳步。示例若干给一个“问题-思考-答案”完整示例叫few-shot。输出格式要求JSON输出方便后处理。你是一名企业数据分析助手。你只能使用给定的数据表和指标口径禁止臆造字段。 请完成以下任务 1. 判断用户问题的分析意图和涉及的指标 2. 从指标字典中查找对应口径 3. 基于提供的表结构生成只读SQL 4. 如果无法确定回答“信息不足”并指出缺失项。 输出为JSON格式{intent: ..., fields: [], sql: }注意few-shot示例不要用理想化的例子要用你实际线上跑得通的例子。模型非常擅长模仿示例的“样子”如果示例写得潦草它也会潦草给你看。4. 实操过程从数据接入到一份可用的分析问答4.1 数据接入与指标口径梳理整个项目的“地基”这个阶段最不性感但决定系统天花板。我把团队里最懂业务的数据分析师拉进来花了整整两周梳理口径。产出物是一份指标字典它的核心字段如下指标主题域口径说明计算逻辑常用维度质检单位用户复购率用户运营近30天内有≥2次有效订单的用户占比复购人数/首购人数渠道、区域、品类数据分析组客单价交易有效订单的总金额/有效订单数SUM(金额)/COUNT(订单)渠道、时间数据分析组库存周转天数供应链库存出清平均周期平均库存/销售成本×周期天数仓库、品类供应链组每个指标的口径确认之后还要生成对应的检索条目。记得给每条口径写多个业务问法比如“复购率”要覆盖“复购怎么样”“第二次买的人多吗”“老客户的回购情况”这样向量检索命中率才会高。避坑提示口径统一是整个项目最容易爆发吐槽的地方。“销售额”到底是含税还是不含税“订单数”是按订单头还是订单明细行算这些争议如果不先解决LLM生成的结果会被业务挑战到怀疑人生。所以提示词里一定要让模型优先查指标字典而不是自己算。4.2 NL2SQL别让模型裸写SQL要给它脚手架直接让LLM对着几十张表生成SQL效果一定不稳定。我的做法是先精简schema再固定SQL模板最后用验证器兜底。精简schema每张表只给核心字段和中文注释关联键单独列出来。几十张全量的表结构会让模型选择困难精简后从源头降低出错率。固定SQL模板常见分析场景拆成模板比如“某指标按时间趋势”“某指标按维度对比”“TopN排名”“占比分析”。模型只需要填表名、字段名、聚合逻辑不要它自由发挥JOIN和子查询。验证器兜底生成后的SQL要做三层检查语法检查、只读检查禁止INSERT/UPDATE/DELETE、表字段白名单检查。检查不通过就打回让模型重写最多重试2次避免死循环。实测下来模板化生成的成功率从裸写的52%提升到91%效果非常明显。还有一个小技巧错误信息要反馈给模型。比如“字段role不存在正确的是role_id”把这种报错喂回去模型往往能自己改对比直接否定它的输出要好用。4.3 用GraphRAG补上多跳关系查询我一开始只用了基础RAG结果遇到一类问题会失灵用户问“华东区的复购率下降是否和促销活动减少有关”这种问题需要的知识分散在复购率口径、区域销量、活动日历、商品条线等多个知识块里普通向量检索只能分别召回模型缺乏把它们串联推理的线索。GraphRAG的做法是把指标、表、维度、活动事件都建成图结构当用户问题涉及多实体关联时先走图查询把相关路径找出来再把这些路径上的事实喂给LLM。我实现的时候没有用太重的图数据库初期直接用NetworkX存关系问题量上来后换了支持图遍历的内存数据库。图里维护的关系包括指标和指标复购率下降 → 影响 → 用户价值客单价上升 → 关联 → 毛利率。表与表订单表 JOIN 用户表 ON user_id订单表 JOIN 渠道表 ON channel_id。指标与业务事件促销活动 → 影响 → 订单量 → 影响 → 复购率。每次问答时语义层先判断是否多跳问题是则触发图查询把查询命中的路径序列化到提示词上下文再让模型生成回答。这样做的结果非常直观涉及关系推导的问题回答完整度从45%提升到80%以上。4.4 模型本地化部署与ONNX加速让推理成本降下来本地模型跑起来后我们第一件事不是调精度而是调性能。业务对响应时间非常敏感超过8秒就会开始不耐烦。我们把模型从PyTorch导出为ONNX格式再做动态轴的配置和量化具体步骤如下加载训练好的开源模型权重导出为ONNX导出时要把输入输出的动态维度维度打开否则固定长度的图推理会浪费算力。开启动态维度让序列长度可变不固定死。做INT8量化模型体积直接缩小到原来的1/4左右内存占用大幅降低。用ONNX Runtime推理配合GPU执行实测推理延迟比原生PyTorch降低了40%~50%。要注意的是量化可能导致精度轻微下降。我在部署前用评测集对比了FP16和INT8两个版本的输出差异在可接受范围内才放心上生产。如果你们对精度要求非常高可以做INT8量化部分敏感层保持FP16的混合方案。部署架构上模型服务用gRPC对外提供配合前面的LLM网关统一调度。实测单卡可以支撑并发8个请求单轮问答总延迟从平均6.2秒降到了3.5秒左右业务反馈“终于可以忍受了”。5. 常见问题与排查实录都是真金白银踩出来的5.1 模型一本正经地编口径怎么办这是RAG系统最常见的问题。表象是模型给出的结论有理有据但仔细看属于“看似合理、实则瞎编”。我们遇到最多的是模型把A指标的口径套用到B指标上。排查思路先看检索召回把每次问答的检索结果打印出来确认模型到底参考了什么。如果检索本来就错了后面对齐口径无从谈起。看知识库条目质量如果本体设计里“我是谁”写得模糊模型就容易张冠李戴。在提示词里强约束明确要求“如果未检索到相关口径必须回答不知道禁止猜测”。另外我强烈建议在系统里加一个**“引用来源”展示**。模型回答后面自动附带“本答案参考指标字典[复购率V1.0]未命中口径时给出提示”这能大幅降低业务对错误结论的容忍成本也便于追责。5.2 同样的问法SQL生成结果不稳定这是NL2SQL的经典问题。同一个人同一句话前后两次生成两条不同的SQL结果还不一样。主要原因模型有随机性未把温度参数设为0附近的低随机值。知识召回存在波动导致上下文不同。few-shot示例顺序被扰动。解决方式生成SQL的任务把温度设为0且固定随机种子。对相同问题做缓存命中缓存直接返回历史结果。构建一个“问法归一”模块模型先对用户问题做标准化比如“这个月复购咋样”统一改写为“按月份维度查询复购率趋势”再交给SQL生成能明显降低波动。5.3 上下文超限对话聊着聊着模型就“失忆”了多轮对话越长Token越多可能直接超出模型的上下文窗口。我们遇到过用户连续问十几轮后模型开始不记得最开始的筛选条件甚至输出混乱。解决思路是上下文浓缩阶段性隔离每轮对话只保留和分析直接相关的实体条件例如“华东区”“6月”其余内容丢弃。对话超过一定轮数用“总结摘要”压缩早期内容。每个问题独立处理SQL生成不要把历史SQL错误带过来。5.4 评测集建设不能偷懒否则回归永远心里没底最后一条也是我觉得最重要的一条一定要建业务评测集。没有评测集你改一个提示词、换一次模型都无法量化效果是否变好只能靠感觉。我的评测集分成三类类型说明数量口径问答直接问指标定义、计算方法80条数据查询含SQL生成和结果校验120条归因分析多跳推理场景40条每条评测样本必须包含自然语言问法、标准答案或标准步骤、验收标准。每次模型或提示词变更后用自动化脚本跑一遍对比新旧输出记录通过率和错误类型分布。这样改任何东西之前心里都有底。最后一些个人体会这套系统从立项到稳定运行最深的感触是LLM项目80%的工作量不在模型而在模型外围绕它的业务工程。口径梳理、知识本体设计、评测集建设这些听起来不酷的活儿恰恰决定了系统能不能从“演示系统”变成“生产系统”。后来系统又接了几个新场景指标异常归因和风险预警都跑得比较顺。方向也验证了智能自助分析不是替代数据分析师而是把数据分析师从重复取数里解放出来让他们去做更高级的事情。如果你的团队也在做类似的系统建议先把口径和评测这两件地基事做扎实剩下的能力可以一层层往上加很快就会见效。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑