一、背景
在典型的埋点数据分析场景中,从数据采集到可视化展示通常遵循一条固定链路:
- 在指标平台定义埋点事件及元数据。
- 应用代码触发埋点,将数据发送至消息队列(如Kafka)。
- 通过ETL任务消费消息,将数据落地到指定的数据库表中。
- 在可视化平台(如Grafana)新建仪表盘,通过编写SQL查询来展示数据。
核心痛点:每当需要新增一个数据分析视图时,数据开发或分析师必须人工梳理多张表的复杂结构、理解字段含义、理清表间关联关系,最后才能编写出正确的SQL查询语句。这个过程耗时费力,且高度依赖个人经验,导致数据分析场景固化,难以灵活响应多变的业务查询需求。
二、思路
分析上述痛点后,我们发现这是一个非常适合引入AI能力进行增强的场景,原因如下:
- 查询需求多变:无法通过预置代码穷举所有可能的分析维度和组合。
- 人力成本高:需要既懂业务又精通复杂SQL的专家投入大量时间。
- 结论依赖个人:数据分析报告的深度和质量因人而异。
因此,一个可行的思路是:构建一个AI Agent,使其能够理解用户的自然语言描述,自主生成精准的SQL查询,执行查询并最终生成结构化的数据分析报告。
要实现这一目标,需要解决三个关键问题:
- 知识注入:如何让AI理解数据库中各表的结构、字段含义及关联关系?
- 执行通路:如何让AI生成的SQL能够被安全地执行并返回结果?(通常无直接数据库权限)
- 低成本验证:如何利用现有资源快速搭建原型,验证方案可行性?
三、方案设计与实现
带着问题,我们开始寻找并实施解决方案。
首先,需要打通AI与数据平台之间的执行通路。通过分析现有Grafana仪表盘的请求,我们发现数据查询均通过同一个API端点 (/api/ds/query) 完成,其核心参数是一个包含原始SQL语句 (rawSql) 的请求体。
这提供了一个绝佳的接入点:将该API封装成一个AI可调用的“工具”。我们使用 Spring AI 的 @Tool 注解快速实现了这一功能。
@Tool(name = "query_grafana",
description = "使用Grafana执行SQL查询以获取数据")
public JSONObject queryGrafana(@ToolParam(description = "查询开始时间,格式:yyyy-MM-dd HH:mm:ss") String from,
@ToolParam(description = "查询结束时间,格式:yyyy-MM-dd HH:mm:ss") String to,
@ToolParam(description = "查询数据类型: table(表格) | time_series(时间序列)") String format,
@ToolParam(description = "时间间隔(毫秒)。仅当format为time_series时需传入。") Long intervalMs,
@ToolParam(description = "Grafana SQL查询语句") String rawSql) {
// 时间格式转换
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime fromDateTime = LocalDateTime.parse(from, formatter);
LocalDateTime toDateTime = LocalDateTime.parse(to, formatter);
String fromTimestamp = String.valueOf(fromDateTime.toInstant(ZoneOffset.UTC).toEpochMilli());
String toTimestamp = String.valueOf(toDateTime.toInstant(ZoneOffset.UTC).toEpochMilli());
// 调用封装的Feign客户端
JSONObject resp = grafanaService.query(fromTimestamp, toTimestamp, intervalMs, rawSql, format);
return resp;
}
工具中的 grafanaService.query() 方法内部通过Feign客户端调用Grafana的查询接口,从而解决了SQL执行通路的问题。
2. 表结构知识库构建 (RAG for Schema)
AI需要知识才能生成准确的SQL。我们选择使用RAG技术为AI注入表结构知识。公司内部部署了RAGFlow服务,这为快速构建知识库提供了便利。
实施步骤:
- 整理知识源:从OBS数据库导出目标表的结构(DDL语句)。由于部分表缺乏字段注释,我们手动补充了表名、字段的业务含义以及关键的表间关联说明,并将其整理成飞书文档。
- 创建知识库:在RAGFlow中创建知识集,选择“表格”解析模式,确保每张表的DDL作为一个完整的语义块(Chunk),避免信息被割裂。
- 优化召回:RAGFlow会自动为每个Chunk生成关键词和问答对。为提高召回准确率,我们结合业务理解手动补充了更贴近查询场景的关键词。
- 封装检索工具:将RAGFlow的检索接口同样封装成一个AI Tool,供Agent在需要了解表结构时调用。
@Tool(name = "get_table_schema", description = "根据问题中的关键词检索相关的数据库表结构(DDL语句)。")
public List<String> getTableSchema(@Param("query") String question) {
return ragFlowService.retrieval(question);
}
3. 构建OBS数据分析Agent
一个功能完善的Agent需要结合架构、大模型和上下文工程。为了快速验证,我们基于内部AI平台Trae(一个支持ReAct模式、工具调用及长短期记忆的Agent框架)进行构建。
我们将前两步开发的query_grafana和get_table_schema工具通过MCP协议发布为独立的服务,并在Trae平台中将其配置给Agent使用。
最后,也是最关键的一步,是设计一个高度定制化的系统提示词,以引导AI严格按照我们的业务流程工作:
# Role:数据分析专家
## Background:用户需要专业的数据分析支持来解决复杂的业务问题...
## Goals:
- 准确理解业务需求,明确查询目标。
- 系统分析相关表结构,确保全面理解数据关系和业务逻辑。
- 设计并执行高效、准确的数据查询。
- 生成包含可视化图表和深度洞察的专业分析报告。
## Constrains:
- 严禁虚构或模拟数据。
- 涉及时间必须使用工具获取当前时间。
- 必须先分析表结构再执行查询。
- 查询无数据时直接告知,不猜测。
## Workflow:
1. 深度理解用户的查询需求。
2. 循环调用 `get_table_schema` 工具,直到获取所有可能相关的表结构信息。
3. 基于表结构,设计查询逻辑并编写Grafana SQL。
4. 调用 `query_grafana` 工具执行查询。如遇错误(如401权限、400语法错误),按规则处理或重试。
5. 分析查询结果,生成包含SQL语句、数据总结、可视化建议和业务洞察的Markdown格式报告。
## Initialization:作为数据分析专家,你必须遵守所有约束,使用中文与用户交流。
四、效果展示
完成上述步骤后,一个智能的OBS数据分析Agent便构建成功。以下是一些交互示例:
- 用户提问:“分析一下过去一周海外用户访问APP各功能的分布情况。”
- Agent行动:
- 理解需求,确定需要“用户”、“访问”、“功能”、“海外”、“时间”等关键词。
- 调用
get_table_schema工具,检索出包含用户信息、行为事件、地区信息的相关数据表。
- 分析表结构,编写出关联多张表、按地区和功能分组的复杂SQL查询语句。
- 调用
query_grafana工具执行SQL,获取结果数据。
- 自动分析结果,生成一份结构化的报告,内容包括:执行的关键SQL、以表格形式展示的访问分布、核心发现(如TOP3热门功能)、以及业务建议。
最终生成的报告逻辑清晰、数据准确,能够有效辅助决策。
五、总结与展望
本次实践验证了利用AI Agent赋能传统数据分析流程的可行性。通过将RAG技术、工具调用与智能体架构相结合,我们成功构建了一个能够理解业务需求、自主查询数据并生成报告的智能助手,打破了数据查询的固化壁垒。
未来优化方向:
- 动态知识库:接入数据库Binlog,自动发现表间关联,并存入图数据库,实现表结构RAG的动态更新。
- 复杂智能体系统:采用LangGraph等框架构建多智能体系统,细化分工,例如拆分为“需求分析Agent”、“SQL生成Agent”、“报告润色Agent”,以处理更复杂的任务。
- 降低使用门槛:将Agent能力封装成飞书机器人或简单的Web应用,让产品、运营等非技术同学也能便捷地进行数据探索与分析。