Agent 数据分析:先把指标口径写清楚,再开放自然语言提问
数据分析 Agent 最容易做成一个会写 SQL 的聊天框,但真正难的是指标口径、权限边界、查询安全和结论解释。
01.数据分析 Agent 的难点,不只是把自然语言翻成 SQL
“让业务同学直接问数据库”听起来很吸引人,但如果系统只有一层 NL -> SQL -> answer,实际风险会非常高。
真正麻烦的地方通常在这里:
- •同一个指标在不同团队里口径不同
- •模型可能会引用不存在的表或字段
- •查询权限、扫描成本和数据脱敏要求很严格
- •结果解释容易脱离上下文,得出错误结论
所以数据分析 Agent 更像一个“分析流程编排器”,而不是一个只会写 SQL 的聊天框。
02.用一个更真实的问题来理解这个场景
假设运营同学问:
为什么昨天退款率突然升高?
这个问题如果直接丢给模型,会有很多隐含前提:
- •退款率的定义是什么
- •“昨天”按哪个时区算
- •对比的是前一天、上周同期,还是 7 日均值
- •是否需要按渠道、地区或商品分类拆解
- •有没有异常订单需要剔除
也就是说,真正要做的第一步并不是生成 SQL,而是把问题转成一个可执行、可审计的分析请求。
03.指标口径和语义层,应该先于 Agent 存在
很多数据分析 Agent 一开始就追求“任何问题都能问”,结果最先崩的是指标定义。
更稳的做法是先准备一层最小语义层,例如:
- •
gmv - •
order_count - •
refund_rate - •
daily_active_users
每个指标都要明确:
- •来源表
- •过滤条件
- •计算公式
- •默认时间粒度
- •是否允许按哪些维度拆解
这一步做好之后,Agent 才有可能在受控范围内生成稳定分析请求。
04.先把自然语言问题转成结构化分析请求
相比直接生成 SQL,我更建议先让模型输出一个结构化请求对象,再由系统编译成查询。
from typing import Literal
from pydantic import BaseModel, Field
class AnalysisRequest(BaseModel):
metric: Literal["order_count", "refund_rate", "gmv"]
dimensions: list[str] = Field(default_factory=list)
filters: dict[str, str] = Field(default_factory=dict)
compare_with: Literal["none", "previous_day", "previous_week"] = "none"
needs_chart: bool = False
METRIC_SQL = {
"order_count": "count(*)",
"refund_rate": "sum(refund_orders)::float / nullif(count(*), 0)",
"gmv": "sum(pay_amount)",
}
def compile_query(request: AnalysisRequest) -> str:
select_parts = [f"{METRIC_SQL[request.metric]} as value"]
group_by = []
for dimension in request.dimensions:
select_parts.append(dimension)
group_by.append(dimension)
sql = f"select {', '.join(select_parts)} from mart_orders"
if group_by:
sql += f" group by {', '.join(group_by)}"
return sql这个模式的价值在于:
- •模型只能在允许的指标和维度里组合
- •查询逻辑可以落到可维护的编译层
- •后续很容易对“问题解析是否正确”单独做评估
05.什么时候用 SQL,什么时候用 Python 容器
数据分析 Agent 并不只有一种执行路径。
更适合走查询编译链路的场景
- •固定指标看板问答
- •运营或产品的常见分析问题
- •需要权限控制的数据库查询
- •可以映射到既有语义层的问题
更适合走 Python / Code Interpreter 链路的场景
- •上传 Excel、CSV 后做一次性探索
- •清洗格式混乱的数据文件
- •生成临时图表
- •做统计检验、分布分析、异常值排查
这两种路径不要混成一锅。数据库查询强调权限、审计和口径一致;文件分析强调交互性和临时探索。它们的治理方式不一样。
06.执行安全是数据分析 Agent 的底线
一旦系统真的开始跑查询,安全和成本就必须前置考虑。
比较常见的控制包括:
- •只给只读账号
- •只开放 allowlist 表和视图
- •限制最大扫描量和返回行数
- •对高成本查询先做 explain 或成本估算
- •对敏感字段做脱敏或直接禁止返回
如果后面接的是代码执行容器,还要再加一层限制:
- •文件生命周期是否短暂可控
- •运行环境是否隔离
- •生成文件是否需要落回业务系统
不能因为它看起来像“分析助手”,就忽略它本质上仍然在操作真实数据。
07.解释结果时,系统要交代依据而不是只给结论
很多分析 Agent 的另一个问题是:查询没错,但解释太像评论。
更可靠的结果说明至少应该带上这些上下文:
- •分析的指标定义
- •时间窗口和时区
- •使用的过滤条件
- •主要对比基线
- •图表或表格来自哪次查询
如果一句“退款率上升主要因为华东区某类订单异常”后面没有任何依据,这种回答在团队里很难真正被采纳。
08.对业务提问,最好同时保留“解释层”和“查询层”
一个更实用的输出方式通常分两层:
给业务同学看的解释层
- •用自然语言总结变化
- •标出最值得继续追查的维度
- •推荐下一步分析动作
给分析或工程同学看的查询层
- •结构化分析请求
- •实际执行 SQL 或 Python 脚本摘要
- •返回的关键字段和采样说明
这样既方便业务阅读,也方便技术同学复盘和纠错。
09.评估时要拆成三段,而不是只看最终答案
数据分析 Agent 的质量,至少可以拆成这三层:
问题解析是否正确
问题有没有被映射到正确指标、维度和时间范围。
查询执行是否正确
SQL 是否命中允许的表,是否返回了预期粒度的数据,是否触发了不必要的大查询。
结论解释是否忠于结果
自然语言总结有没有夸大因果、漏掉限制条件,或忽略样本量和时间窗口。
把这三层拆开评估,比只问“答案对不对”更容易持续迭代。
10.三个常见误区
1. 没有指标注册,就直接做 NL2SQL
这样一开始看起来很灵活,但很快就会因为口径漂移和字段幻觉出问题。
2. 让模型直接面对整库
表越多、权限越宽,系统越难控,错误查询和越权风险都会上升。
3. 只返回一句结论,不保留分析依据
没有查询上下文、指标定义和过滤条件,结论再像样也很难让人真正信任。
11.总结
数据分析 Agent 真正的价值,不是让每个人都能“随便问数据库”,而是把原本分散在提问、定义指标、写查询、解释结果这些步骤里的工作,整理成一条可追溯的分析流程:
- •问题先结构化
- •查询在受控范围内生成
- •执行有权限与成本边界
- •结论能回溯到依据
只要把这几个环节守住,Agent 才能真正帮团队缩短分析链路,而不是制造一层新的数据不确定性。