id, title, type, domain, stack, tags, level, prerequisites, est_hours, related, week
| id |
title |
type |
domain |
stack |
tags |
level |
prerequisites |
est_hours |
related |
week |
| ai.agent-design.scenario.report-agent |
运营报表 Agent:规划、只读 SQL 工具、结构化输出和任务进度 |
scenario |
ai |
| agent-design |
| langgraph |
| postgresql |
| fastapi |
|
| 报表 Agent |
| Text-to-SQL |
| 规划 |
| 结构化输出 |
| 任务状态 |
| 流式进度 |
|
advanced |
| ai.agent-design.react-planning |
|
3 |
| ai.agent-design.interview |
| ai.langgraph.persistence-hitl |
| ai.agent-ops.observability-cost |
|
|
运营报表 Agent:规划、只读 SQL 工具、结构化输出和任务进度
业务背景与问题
运营每周要找数据组要报表(“9 月各大区 GMV 和环比”),排队要两三天。希望做一个报表 Agent:用自然语言提需求,自动查数、出图、写结论。原型的问题:
- 生成的 SQL 偶尔写错表名,或者把“退款订单”也算进了 GMV;
- 有一次生成了没有时间条件的查询,扫描了整张订单表,拖慢了业务库;
- 复杂报表要跑一两分钟,页面一直转圈,用户以为卡死了;
- 结论里的数字和图表对不上。
约束
- 只能读,不能写;不能影响线上业务库。
- 指标口径(GMV、退款率)以数据组的定义为准。
方案设计
- 工作流 + 局部 Agent:整体流程固定为“理解需求 → 规划 → 查询 → 出图 → 写结论”,只在“规划和查询”环节让模型多步探索。
- 指标口径作为 Skill:把指标定义、表结构、示例 SQL 写成技能文件,按需加载,而不是让模型猜。
- SQL 工具的安全边界:连接只读从库 / 数仓;只允许 SELECT(用 SQL 解析器校验,不靠字符串匹配);强制时间范围、
LIMIT、语句超时(statement_timeout);先 EXPLAIN 检查预估行数,超过阈值拒绝。
- 结构化输出:结论用 Schema 输出(指标名、数值、来源查询 ID),数值必须来自查询结果——生成后程序校验每个数字都能在结果中找到。
- 任务状态和进度:任务表记录状态(排队 / 规划中 / 查询中 / 生成中 / 完成 / 失败),LangGraph 节点用
custom 流推送进度,前端通过 SSE 显示;失败的步骤可以重试,不用从头开始。
关键代码
只读 SQL 工具的校验(使用 sqlglot 解析 SQL,示意,API 以官方文档为准):
取舍
| 选择 |
优点 |
缺点 |
| 工作流 + 局部 Agent(本方案) |
可控、可展示进度、容易评测 |
灵活性有限 |
| 完全自主的 Agent |
能处理开放问题 |
难控制成本和正确性 |
| 预定义指标 API(语义层),不让模型写 SQL |
口径一致、最安全 |
需要先建设指标体系,覆盖不到的问题答不了 |
| 模型直接写 SQL |
覆盖面广 |
口径和安全风险,需要本方案中的护栏 |
易错点
- 只用字符串判断
SELECT,被 WITH ... DELETE 或多语句绕过:用解析器,并且数据库账号本身只读。
- 连接业务主库查询。
- 结论中的数字由模型“复述”,不校验来源。
- 长任务没有进度和超时,用户反复点击生成多个重复任务(要防重复提交)。
面试怎么讲
“报表 Agent 我没有做成完全自主的,而是固定流程,只在规划和查询环节让模型多步探索。指标口径写成 Skill 按需加载;SQL 工具连只读从库,用解析器只允许 SELECT 和白名单表,强制时间范围、LIMIT 和语句超时;结论用结构化输出,每个数字都要能在查询结果里找到;任务有明确的状态,进度通过 SSE 推给前端,失败的步骤可以单独重试。”