周四下午两点,业务同学在群里甩过来一句话:“你看昨天华南区转化率为什么掉了?”搁在以前,这个问题的标准解法是:先登数仓查订单表,确认转化率确实在掉,再怀疑渠道、怀疑活动、怀疑机型,一层层往下钻,最后做一张三折页简报。整个流程通常是两个小时起步,而且大量时间不是花在“分析”上,而是花在“取数、清洗、拼接、核对口径”上。
所以我搭了一个数据分析智能体,目标就一句话:让业务问题直接变成数据和结论。它不是一个套着问答外壳的报表工具,而是一个能自主规划查询、执行计算、生成解释性文字、并基于上下文进行多轮追问的智能体。本文想把这个项目掰开揉碎讲一讲:为什么需要它、整体架构怎么设计、文本转查询和归因这些核心模块怎么落地、以及真实环境中踩到的坑。如果你也在考虑给团队搭一个自助分析助手,这篇文章应该能帮你少走不少弯路。
1. 为什么折腾这个:数据分析的“最后一公里”一直被卡在取数
在讲架构之前,我先把做这个项目的动机说清楚。我们团队的数据基建其实不差,数仓层有统一的表,指标也有定期的报表,但业务侧拿到这些数据之后,还是经常回过头来找人:“帮我看一下为什么这个数掉了”“能不能按渠道拆一下”“上周的留存是多少”。原因很简单,报表是静态的,一旦问题的角度变了,就必须改查询条件,而改查询条件这件事又回到了写SQL的人手上。
这就形成了一个很常见的“取数工具人”局面:分析师每天都在帮业务查数、导数据、补口径,真正深入业务去解释“为什么”的时间反而很少。我统计过自己一个月的工时,大概六成以上消耗在数据获取和清洗上,真正能做判断、写结论的时间不到四成。这个比例放在任何团队里都是不健康的。
1.1 我确定的三个核心使用场景
动手之前,我先复盘了团队里高频出现的分析诉求,最后圈定了三类必须由智能体承接的场景,避免一上来就把范围铺得太大:
- 日常指标问答:类似“昨日新增用户是多少”“最近两周App上的平均订单金额怎么变化”。这类问题占了需求量的五成以上,本质上是取数动作,完全可以自动化。
- 异常波动归因:比如“转化率为什么掉了”“华南区营收为什么上升”。这类问题需要多层拆解,至少要看趋势、再看维度贡献、最后找可能的原因。
- 临时数据分析:业务偶尔会发来一个Excel或CSV文件,里面是活动数据、渠道明细或用户标签,要求“帮忙看一下有没有规律”。这不是固定表结构能满足的,需要智能体自己读文件、做统计描述、生成图表。
确定范围很重要。很多智能体项目做砸,不是因为模型能力不行,而是因为想把所有问题一把抓,结果每个场景都只做到了半吊子。我后来把这三类场景作为开发的验收基线,每做一个版本就先跑一轮,跑不通就不往下加新功能。
1.2 传统BI工具和智能体的本质区别
我们在做这个项目之前,团队内也有一套自助式BI平台,业务同学可以自己拖拽图表、配置筛选条件。但实际用下来,门槛依然很高。业务同学的诉求往往是“这个数为什么变高了”,而BI工具只能告诉他“这个数变高了”,至于为什么得自己去找对比、下钻、换维度,整套操作路径太长了。
核心区别可以用一张表说清:
| 对比维度 | 传统BI工具 | 数据分析智能体 |
|---|---|---|
| 交互方式 | 拖拽组件、配置筛选 | 自然语言对话、多轮追问 |
| 查询组织 | 用户自己设计图表和过滤 | 模型自动规划查询计划 |
| 数据分析 | 只能展示指标,靠人判断 | 自动生成趋势对比、归因候选 |
| 口径维护 | 按图表配置,分散在报告里 | 集中维护指标字典,复用性强 |
| 出错恢复 | 用户自己排查配置 | 系统记录失败并自动修正 |
我用一个生活化的类比来说,传统BI就像给你一本菜谱和一堆食材,做法写得清清楚楚,但你得自己掌勺;智能体更像一个有经验的帮厨,你跟他说“今天想吃得清淡点”,他会自己判断是清蒸还是炖汤,然后把成品端上来,再告诉你为什么选这道菜。
2. 整体架构:大脑、手和记忆是怎么分工的
这件项目真正开始设计时,我面临的一个关键问题是:该把逻辑放在模型里,还是放在代码里?很多人以为数据分析智能体就是“写一段提示词,把数据传给大模型,等它返回结果”,但实际做下来就会发现,这会导致两个严重问题:第一,模型对表格内容不感知,容易生成不存在的字段;第二,权限和口径控制完全失控,因为它根本不知道哪些数据能看、哪些不能看。
我最后采用了“控制流在代码里,判断流在模型里”的分层设计。所有必须保证正确的事情,比如权限校验、超时熔断、字段白名单、SQL参数化,全部交给代码;而需要灵活判断的事情,比如用户想表达什么指标、怎么拆解归因、用什么图表呈现,全部交给大模型。整个智能体分为四层。
2.1 入口交互层
入口层负责接收用户的消息,也负责维护每次会话的状态。用户可以在对话框里连续追问,比如先问“昨日整体转化率”,再追问“分渠道看看”,系统要能理解“分渠道”是针对前一个问题的补充条件,而不是一个全新的独立问题。这里我通过会话ID关联历史消息,并且会把最近两轮问答的摘要一并传给模型,避免上下文丢失。
入口层还支持两种输入形态:一种是文本问题,另一种是文件上传。上传的Excel和CSV会先被解析成临时表,再进入后续执行流程。这个设计看起来简单,但后期频繁用到,因为业务临时分析的数据很多都不在数仓里。
2.2 规划大脑层
这是整个智能体最核心的一层。大模型接收到用户问题后,并不是直接去查数据库,而是先产出“查询计划”。查询计划类似于传统程序里的中间表示,把自然语言问题翻译成一个结构化的JSON,里面包含指标、时间范围、分组维度、过滤条件等关键信息。模型再根据这个计划决定调用哪些工具、按什么顺序调用。
每个工具都是一个独立的函数,比如query_dashboard、query_channel_detail、calc_weekly_ratio、generate_chart。这样做的优势是,模型不需要理解所有SQL细节,只需要理解“工具A能查什么,工具B能算什么”,大大降低出错概率。
2.3 执行工作层
执行工作层负责真正落地。查询执行器连接数仓时只有只读权限,每条SQL单独设置执行超时时间,默认15秒;查询返回行数也会做一个上限限制,防止用户问一个不合理的全表扫描把数据库拖垮。图表生成器则只基于真实返回的数据集工作,绝不允许模型凭空生成数值。
执行工作层里还有一个专门处理本地文件的工具,底层用表格计算库实现,能对上传的数据做字段统计、缺失值检测、分组聚合和简单的相关性分析。它不是万能的,但足以覆盖大部分临时分析场景。
2.4 记忆与缓存层
为了支撑多轮对话,我加了一个轻量级的会话记忆层。它会保存每个会话的查询计划、执行结果和前几轮的关键结论,最新的会话数据保存在内存里,超过一定时间自动收进日志库。这样用户追问“那环比呢?”的时候,系统不需要重新理解前面的所有上下文,直接取上一轮的指标和时间范围就能完成计算。
指标结果缓存也很重要。同一个问题在一小时内被反复询问时,系统会直接读取缓存结果,不需要重新跑SQL,响应速度能提到秒级。这看起来是个小优化,但实际使用中业务侧非常吃这一套,因为他们的很多问题本质上是“同样的数换着角度问”。
3. 核心模块实现:文本转查询、归因引擎、自动可视化
第2节讲的是骨架,这一节是真正让它“看起来聪明”的三块核心模块,也是我在开发过程中花时间最多的地方。
3.1 文本转查询:先产出查询计划,再生成SQL
文本转查询最直觉的做法是让模型直接写SQL,但实践下来问题非常多。最大的坑是模型对表结构和字段含义不了解,经常把“平台类型”猜成“platform”,把“客户ID”猜成“customer_id”,一旦猜错,整个查询就报错。更严重的是,模型有时会把不存在的事实拼进SQL里,比如生成一个用户表单里根本没有的字段,而数据库不会报错,只会返回空结果,用户看到的就是一个“没数据”的假象。
为了避免这个问题,我设计了一个结构化查询计划的中间步骤。模型先根据指标字典和用户问题,输出一个类似这样的JSON:
{ "intent": "trend_query", "metrics": [ { "field": "order_amount", "agg": "sum" } ], "date_range": { "start": "2024-03-01", "end": "2024-03-31" }, "group_by": ["channel_name"], "filters": [ { "field": "region", "operator": "=", "value": "华南" } ], "order_by": [ { "field": "order_amount", "direction": "desc" } ] }这个查询计划有巨大的工程价值。首先,它把“用户意图”和“具体SQL语法”解耦了,如果字段名变了,只需要改映射表,不需要重写整个模型的逻辑。其次,这个计划可以非常方便地做字段白名单校验,在计划进入下一阶段之前,程序会逐项检查字段名是否是字典中注册过的有效字段,防止模型凭空创造字段。最后,它还能被人类审计,出了问题回放日志时,只看到查询计划就能判断是模型理解错了,还是执行层出了问题。
3.2 归因引擎:不只告诉你掉了,还要给出候选原因
归因是我认为最有价值、也最难做好的模块。很多报表工具只能告诉你“转化率从3.2%降到2.8%”,但业务侧真正想知道的是“为什么”。我设计的归因引擎采用两阶段判断。
第一阶段是异常预检。系统会先计算当前指标的时间序列,自动做环比、同比和阈值判断。只有确认“这个变化确实异常”的时候,才会进入归因阶段;如果只是正常波动,系统会直接说明“变化幅度在正常波动范围内”,避免过度解读。这个设计我在早期版本里没有做好,结果模型对每个波动都强行找原因,反而闹了很多笑话。
第二阶段是维度下钻与贡献拆分。系统会按地区、渠道、品类等维度分别计算指标的贡献变化量,把整体变化拆解成各个维度的加减关系。比如整体营收下降了100万,可能华南区贡献了-70万,渠道B贡献了-50万,其他渠道正向拉回20万。模型拿到这组数字后,再结合业务知识生成候选原因,并给出置信度排序。
我举个例子。某个工作日,系统给出的归因结论是:
“昨日整体转化率下降的主要来源是华南区,贡献了整体降幅的68%;其中渠道B的触达量较前日下降约35%,且客单价同步下滑。根据历史数据,渠道B的波动与当前城市区域的活动投放节奏高度相关,建议优先核查渠道B近期投放预算和落地页转化情况。”
这个结论并不是模型拍脑袋写的,而是基于真实拆分数据生成的,每一句话背后都对应一个查询步骤或一项统计结果。正因如此,它才具备让业务信任的基础。
3.3 自动可视化:按数据语义而不是按用户指令选图
可视化模块看起来最容易,但实际做起来很讲究。早期版本我直接让模型从代码库里选择图表类型,结果模型经常选错,比如把时间趋势画成饼图,把占比关系画成折线图。后来我换了一个方案:让模型先输出“数据关系类型”,再由代码层映射到具体图表类型。模型只要判断这是“趋势”“占比”“对比”还是“分布”,剩下的交给代码决定。
映射表大概是这样的:
| 数据关系 | 匹配的图表类型 | 典型问题 |
|---|---|---|
| 趋势变化 | 折线图 | 这周营收怎么变化 |
| 占比构成 | 堆叠柱状图 | 各渠道贡献了多少 |
| 分组对比 | 柱状图 | 各省转化率排名 |
| 相关性 | 散点图 | 客单价和复购率有关吗 |
| 分布形态 | 直方图/箱线图 | 订单金额都集中在什么区间 |
这套映射比直接让模型写图表代码稳定很多。因为图表选型本身是有明确规则的,用代码控制不容易出错;模型只需要做最擅长的语义判断。此外,所有图表生成前都会检查数据是否为空、是否为纯数值,避免出现“画了一个空壳图”的低级问题。
4. 关键技术决策:指标字典、权限隔离和可观测性
如果说核心模块决定智能体的“上限”,那么有几个支撑性设计决定它的“生死”。我专门把这三项单独拿出来讲,因为它们都是平时看不到、但在生产环境中特别要命的东西。
4.1 指标字典是定海神针,不能指望模型自学
数据分析智能体最大的风险之一,是模型对业务口径的臆测。最典型的情况是“活跃用户”这个指标,不同团队有不同的定义:有的按“当日有登录行为”,有的按“当日有付费行为”,还有的按“七日内有任意行为”。如果指标字典里没有一个明确的官方口径,模型就会随机挑一个,输出的数字自然对不上。
我在系统里建了一个指标字典,每个指标包含以下字段:标准名称、业务别名、计算口径、来源表、可用维度、统计周期和注意事项。当用户提问时,系统会对问题进行向量化检索,从指标字典中召回最相关的若干条目,把它们作为上下文注入到模型推理中。这里有个细节,不是把整个字典全部塞进提示词,那样既浪费token又干扰判断,只召回与当前问题相关的部分就够了。
同时,日常维护指标字典成了我这个项目里最重要的工作。每发现一个新的口径疑点,我就去和对应业务线的同学确认,然后写进字典里。这个资产的价值不亚于智能体本身的模型代码,因为模型的每一次正确判断,本质上都建立在口径清晰的地基上。
4.2 权限隔离:必须在查询执行之前完成检查
权限问题在小规模Demo里容易被忽略,但一旦这个智能体面向整个业务团队,就变成了严肃的安全问题。不同角色能看的数据不一样,财务数据、用户隐私、渠道成本明细,都不是全员可见的。
我的做法是在查询计划进入执行器之前,依次做三层校验。第一层是表权限,检查用户是否有权限访问该表。第二层是行级过滤,根据用户所属的组织或区域自动在过滤条件里追加一条租户条件,比如华南区的人只能看到华南区的数据。第三层是列级脱敏,敏感字段在执行结果返回给模型之前直接丢弃,保证模型永远看不到它不该看到的内容。
曾经有同事建议直接让模型在提示词里做判断,我都否决了。原因是权限是安全底线,不能依赖模型的自觉和临场发挥,必须由代码强制保证。我在整个链路中都遵循一条原则:凡是涉及“能不能”“该不该”的问题,都放在代码层;凡是涉及“怎么看”“怎么解”的问题,才交给模型。
4.3 可观测性:每次推理过程都要留痕
让模型自主完成多步分析,意味着系统内部会发生很多我们预想不到的路径。如果不记录每一步发生了什么,出了问题就会非常难排查。我要求系统对每一次对话的全过程做日志落盘,包括用户原始问题、查询计划、生成的SQL、实际执行耗时、返回行数、模型回复、错误信息、token用量等关键字段。
这套日志不只是事后排查用的。我把积累的失败样例整理成了一个回归评测集,每次升级模型或者调整提示词后,先拿回归集跑一遍,观察失败率有没有改善。这个动作保证了系统可以持续演进,而不是改一处坏一处。后来我还做了一个简单的观测面板,把每日的查询成功率、平均耗时、最常见的错误类型展示出来,成了我判断系统健康度的主要参考。
5. 真实跑一轮:三个高光场景与一次翻车复盘
光讲设计理念没有说服力,我把开发过程中印象最深的几个真实场景放出来,涵盖成功案例和一次典型的翻车。
5.1 场景一:营收下滑,系统给出分层归因
业务负责人问:“为什么3月第一周整体营收环比下滑了12%?”系统执行的步骤大致是:
第一,指标字典锁定“整体营收”的标准口径,确认时间范围为最近两周;第二,查询总营收的日趋势,计算环比降幅,确实达到12%;第三,按地区拆解,找到华南区贡献了整个降幅的六成以上;第四,在华南区内再按渠道拆,发现渠道B的投放量较上周近乎减半;第五,结合历史数据中渠道B与营收波动的相关性,给出候选归因。
整个过程耗时约40秒,而如果人工来做,我至少要花掉一天,还要频繁向业务确认口径。输出结果也不是干巴巴的数字,而是带了解释逻辑的文本,业务负责人可以直接拿去做下一步决策。这个场景成功的关键在于:指标字典里提前登记了各渠道的统计口径,所以模型的查询计划能准确命中,不需要反复试错。
5.2 场景二:转化率波动,模型先确认再下钻
第二个场景是运营同学问:“最近两天渠道A的转化率怎么有点奇怪?”系统先做了异常预检,发现渠道A的转化率确实下降了约15%,但整体转化率只下降了3%。此时模型并没有直接下结论说“渠道A拖垮大盘”,而是继续下钻,发现渠道A的触达量上升了40%,而用户结构里新用户占比明显偏高,新用户的转化率天然低于老用户。
这是一个很有意思的发现。同样是“转化率下降”,原因可能不是渠道变差了,而是触达量扩大导致的用户结构变化。系统把这条逻辑写成注释,建议运营关注新用户群与目标客群的重合度。这种“把问题背后的机制解释清楚”的能力,正是我认为智能体与普通报表工具有本质区别的地方。
5.3 场景三:上传一份活动明细,自动完成初步探索
有一次,业务同学直接上传了一个活动报名明细的CSV文件,问“这个活动上线后的用户表现怎么样”。系统先把文件解析成临时表,自动输出字段清单、非空率、基本统计分布,再根据问题生成一张报名趋势图和一张来源渠道占比图,最后总结了几个关键信息:晚间报名的占比最高、移动端来源超过七成、二次报名用户比例明显高于新用户。
这个能力并不复杂,底层就是调用表格计算工具做描述性统计。但它解决了一个非常现实的痛点:以前业务发一个Excel过来,你得先自己问他要说明文档、猜字段含义、写清洗脚本,现在系统能在几分钟内给出第一版探索结果。对临时性分析需求来说,它足够实用。
5.4 翻车复盘:模型幻觉字段,连续两次修正失败
必须说,这个智能体也有翻车的时候。有一次用户问“平台整体转化率是否受新版本影响”,系统生成的查询计划里出现了一个不存在的字段“platform”,数据库直接报错。系统自动启动修正机制,第一次修正把它改成了“app_version”,但该字段在数据表中也不存在;第二次修正尝试查“channel_name”,最终得到的是完全错误的结果。
事后回放日志,我发现问题出在两处:一是模型在生成查询计划时,没有严格按照指标字典中的可用维度来填写字段;二是修正循环缺少一个关键约束——修正方向没有回到“查字典”这一步,而是继续用自己的猜想来覆盖。这个案例让我意识到:任何依赖模型自主性的环节,都必须有“不确定就停止并询问”的兜底规则。
针对这个问题,我在提示词和代码两层都做了修补。代码层新增了字段白名单强校验,不符合字典规则的字段直接拒绝;提示词层增加了一句硬性约束:“当你对目标字段不确定时,不要猜测,请向用户询问确认。”这之后模型胡乱编字段的次数大幅下降,但完全杜绝是不可能的,所以日志和人工复核仍然是最后一道防线。
6. 提示词和参数的取舍:能交给代码控制的,绝不指望模型自觉
很多技术同学看到数据分析智能体,第一反应是先琢磨提示词。我的经验恰好相反:提示词只是整个系统的一小块,而且真正好用的提示词一定不长。
6.1 系统提示词我只写三块内容
系统提示词越短越好。核心只保留角色定义、行为规则和输出格式。角色定义告诉模型它是什么,行为规则告诉它遇到不同情况该怎么做,输出格式保证它返回的结果能被程序稳定解析。我举一个简化版本:
你是企业内部分析助手,只基于给定的数据结果进行回答。 行为规则: 1. 先输出你认为需要执行的查询计划,不要跳过中间步骤。 2. 不确定字段时,禁止猜测,优先查指标字典。 3. 如果字典也无法确认,直接向用户提问。 4. 对异常数据要区分“真实异常”和“正常波动”,不可强行归因。 5. 回复包含结论、数据依据和可能的后续建议,语气简洁。 输出格式: - 第一步:输出一个JSON查询计划 - 第二步:输出解释性分析文本 - 第三步:输出可能需要的图表描述字段我见过很多团队把提示词写到两三千字,把各种业务规则往里塞。实际效果并不好,因为模型处理超长提示词时注意力容易被稀释,真正关键的指令反而被淹没了。更可靠的做法是把业务知识放到指标字典和工具定义里,让模型在需要时通过“查询字典”这个工具获得信息,而不是把字典内容全部预埋在提示词中。
6.2 关键参数设置与使用效果
这里给一组我实测下来比较稳定的参数,供初读者参考:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| temperature | 0.1 - 0.2 | 数据分析场景要低随机性,不追求发散输出 |
| top_p | 0.8 | 限制候选集范围,避免模型输出过长或漂移 |
| max_tokens | 1024 | 留下足够空间给分析文本,但不过度消耗 |
| 查询超时 | 15秒 | 执行SQL最长时间,防止拖垮数仓 |
| 修正循环 | 最多3次 | 连续失败必须停止,引导用户补充信息 |
| 会话上下文长度 | 最近2轮完整信息 | 防止上下文过长导致遗忘早期问题 |
其中temperature和修正循环这两个参数是我踩坑最多的地方。早期我把temperature设置得偏高,模型同样的问题在不同时刻给出的口径会有偏差,用户很快就说“这系统一会一个数”。后来我把temperature压到0.2以下,输出稳定多了。另外一个重要经验是:修正循环必须有上限,否则模型会在错误的路径上越走越远,浪费大量时间,最后还给出一个看起来言之凿凿的错误结论。
6.3 让模型更稳定的一些实操技巧
除了参数,我还积累了几个提升稳定性的小技巧。
第一,结构化输出尽量用JSON Schema约束而不是自由文本描述。强制让模型返回规定格式的查询计划,解析程序就不需要去猜测字段含义。第二,每次生成查询计划后,都要和指标字典中的白名单做交叉校验,这一步是硬代码逻辑,不依赖模型。第三,典型查询计划的few-shot示例不需要太多,三五个就够了,主要是为了给模型建立“复杂问题也要拆成步骤”的示范。第四,非常重要的一点,凡是要把结果推向生产的操作,比如发送推送消息、触发告警,都要经过人工确认,不能让智能体全自动完成。
7. 做完这个项目之后的一些真实体会
讲到这里,这个项目的技术结构基本就完整了。最后说几句我个人的真实感受,不算是总结,只是希望给想动手的人一些心理准备。
首先,数据分析智能体的价值不在于它“像人一样说话”,而在于它能体系化地把“取数、清洗、计算、归因、可视化”这一整条链路缩短。它不会替代分析师,但一定会把分析师从繁琐取数里解放出来,让分析师把精力放到真正需要业务判断的地方。如果你们团队的痛点也是大量时间消耗在取数而不是分析上,那这个方向值得投入。
其次,做这类系统一定要尽早建设回归评测集。我前期就是吃了没有评测集的亏,每次调整提示词都感觉变好了,但总有历史问题被改回来。后来把失败案例、正常案例、边界案例整理成一份固定测试集,每次改动都先跑一遍,才真正做到可迭代。
最后再分享一个小技巧:先在指标字典上花时间,比在提示词上花时间更值。模型的提示词写得再好,如果连“业绩”和“销售额”都分不清,系统永远不会有可信度。把这个地基打扎实了,整个智能体才会稳,你才有底气把它展示给别人。