制造业 BI 自然语言查询:业务直接问"为什么毛利下滑"
客户是一家华东的机械制造企业,2025 年营收 20 亿左右,5000 多号员工。他们 IT 体系其实挺齐全的——有数仓、有 Tableau、有自研的业务中台,但 CIO 跟我说:「我们业务人员就是用不来这些工具。」
我在他们公司蹲了一周,亲眼看到以下场景:
- 销售副总想看「上季度哪个型号毛利下滑」,发邮件给 BI 团队,等两天拿到一张 Tableau 链接,发现维度不对,再发邮件,又等一天
- 生产经理想看「上月某客户的交付准时率」,打电话给 IT,IT 说「你去 BI 门户搜一下」,生产经理说「我搜不到」
- BI 团队 8 个人,60% 的时间在接临时需求,根本没空做真正的数据建模
典型的「工具都有,但链路不通」。我的任务是做一个 Agent,让业务人员直接用自然语言问问题。
初版翻车:schema 根本装不下
第一版我想得挺简单:业务问题 → 丢给 Claude → 生成 SQL → 执行 → 返回结果。经典的 Text2SQL。
拿到他们数仓文档一看我就懵了:47 个业务域、1283 张表、超过 2 万个字段。
光把核心表的 schema 拼成 prompt 就 340K token,还没算字段注释、业务口径说明。context window 直接炸。
我第一反应是「那就塞个最相关的 schema」,但问题是:业务问问题的时候,他自己都不知道哪张表最相关。他问的是「这个月 A 客户订单情况」,背后可能涉及订单表、报价表、合同表、发货表、回款表五张主表,外加十几张维度表。
这个时候我才意识到,这不是一个 Text2SQL 问题,这是一个多阶段工程问题。
架构:业务域切分 + 检索 + 验证执行 + 归因二次分析
改版之后整个链路变成四层:
层一:业务域切分 + schema 检索
把 1283 张表按业务域切分成 47 组(销售域、生产域、采购域、财务域、仓储域……)。每个域做一份「schema 摘要」,包含这个域的核心业务概念、关键表、常用字段、业务口径。
用户问问题进来,先让 Claude 判断「这个问题涉及哪几个业务域」,然后只把这几个域的 schema 摘要注入 context。如果涉及具体表,再做二次检索拉详细字段。
这个思路其实就是分层 RAG,Context 检索与 Rerank 里有讲过类似的分层检索模式。
层二:SQL 生成
拿到相关 schema 之后,让 Sonnet 生成 SQL。这里我做了几个约束:
- 强制 JSON 输出,包含
sql、dialect、tables_used、assumptions四个字段(参考 Prompt JSON Schema) assumptions字段必须列出所有歧义假设(比如「我假设『毛利』是指销售毛利,不含税费」)- 不允许跨业务域 join,跨域必须拆成多个子查询
层三:验证执行
SQL 生成完不直接执行,要先过三道:
- EXPLAIN 分析:跑一次 EXPLAIN,看执行计划。如果预估扫描行数超过 1 亿,直接拒绝,要求 Claude 重写
- 成本估算:数仓按扫描量计费(他们用的是基于 Trino 的自研平台),超过 2.5 元的查询要业务二次确认
- 采样验证:先用
LIMIT 100跑一次,让 Claude 判断结果是否合理(比如金额字段全是 0 明显不对),合理才放大查询
第一版没这些保护,有次一个业务员问「过去三年所有订单明细」,直接生成了个 SELECT * FROM order_detail 全表扫描 3.7 亿行,平台告警打爆我的 Slack。
最大的坑:业务问的是归因,不是 SQL
这个坑是上线一个月之后才发现的。
业务副总问:「上季度哪个型号毛利下滑得最狠?」
我的 Agent 返回:
1 | 型号 A:毛利率 23.4%,环比下降 8.7% |
副总看了一眼:「我知道 A 下滑了,我问你为什么。」
我当时就懵了。业务人员问「下滑得最狠」的潜台词是归因,不是 ranking。他要的是:「A 型号 Q1 毛利下滑 8.7%,主因是原材料涨价占了 5.2 个点,另外是华南区域打折促销占了 2.8 个点。」
这是一个多步分析任务,不是单次 SQL。
改版我加了一个「归因层」:
- 先识别用户问题类型(ranking / 归因 / 对比 / 趋势)
- 如果是归因类,自动分解成多个子查询(整体下滑幅度、按维度拆分、按时间拆分、同比对比)
- 把多个子查询结果合并,让 Opus 做归因分析
- 用自然语言解读输出
归因这一层必须用 Opus,Sonnet 做出来的归因经常是罗列数字,缺深度推理。这里的取舍思路我写过 CoT vs Direct,归因分析必须走 CoT。
度量:业务自查率从 7% 涨到 64%
上线三个月的数据:
- 业务自查率:7% → 64%(从月活 1200 次业务问询中能独立完成的比例)
- BI 团队临时需求量:月均 340 条 → 月均 87 条,降 74%
- 平均响应时长:人工需求 1.7 天 → Agent 34 秒
- 业务 NPS:从 -12 涨到 +41
BI 团队的角色也变了。原来 8 个人疲于奔命做需求,现在改成:
- 3 个人维护业务域 schema 摘要和口径字典
- 3 个人做复杂分析和建模
- 2 个人做数据治理
BI 经理跟我说:「终于有时间做正经事了。」
成本:月账单 $918.44
拉了 3 月数据:
- 总调用次数 36847(含验证、归因、多次重试)
- 平均单次问题消耗 3.2 次调用(含一次 schema 检索、一次 SQL 生成、一次归因)
- 模型分布:Haiku 41%(分类、schema 检索)、Sonnet 47%(SQL 生成、验证)、Opus 12%(归因分析)
- 月账单 $918.44
平均单次业务问题 $0.027。相比人工处理一条需求的成本(估算 380 元/条,含 BI 工程师工时),降幅超过 99%。
Prompt caching 在这个场景特别有效。47 个业务域的 schema 摘要是固定的,我把高频的 12 个域的 schema 全部做 caching,命中率 78%,省了接近一半的 prompt 成本。具体配置可以看 Prompt Caching 深度指南。
踩过的其他坑
坑一:口径不统一。「销售额」在销售部门指含税销售额,在财务部门指不含税。第一版 Claude 经常用错口径。后来在每个业务域摘要里加了「口径字典」,SQL 生成前强制注入。
坑二:业务术语。「毛茬产品」「粗加工件」「头批料」这些词在 schema 里根本不存在,但业务张口就来。我做了个业务术语 → 字段映射表,问题里出现业务黑话时先做转译。
坑三:时间歧义。「上季度」对财务是自然季度,对销售是考核季度(他们的销售考核季是 3 月 1 日到 5 月 31 日这样错位的)。必须在 prompt 里明确时间语义。
坑四:权限。财务数据不是所有人能看,原来 BI 平台靠列权限控制。Agent 得把用户身份透传下去,SQL 生成时带上权限过滤条件。这块涉及一些安全边界,可以参考 MCP Security Best Practice 的思路。
还没解决的
- 多维下钻:用户问「北京区域销售情况」,然后追问「那朝阳区呢」,跨轮的维度下钻还不够自然
- 可视化:现在只返回表格和文字,没有图表。业务副总说「能不能直接给我一张图」
- 异常检测:用户不知道问什么的时候,Agent 没法主动说「你可能想看下 A 型号的异常下滑」
Q3 准备把可视化这块集成进来。
真正的难点在于 schema 治理、业务口径、归因分析这三座山。我在 检索重排策略 里讲过分层 RAG 怎么搭,在 Agent SDK 生产部署 里有完整的多步 Agent 样板。
- 标题: 制造业 BI 自然语言查询:业务直接问"为什么毛利下滑"
- 作者: Claude 中文知识站
- 创建于 : 2026-04-18 19:38:00
- 更新于 : 2026-04-19 14:12:00
- 链接: https://claude.cocoloop.cn/posts/industry-bi-natural-language-query/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。