案例分析二:一个 Data Analysis Agent 为什么不能只是“问题 → SQL → 答案”?

场景背景

再看另一个最终项目。

业务同学问,“昨天广告收入为什么下降?”

最简单做法是 Text-to-SQL:

用户问题
 ↓
生成 SQL
 ↓
执行 SQL
 ↓
返回结果

如果 SQL 只是查出:

昨天收入:80 万
前天收入:100 万

它只能证明“确实下降了”,并没有解释为什么。

问题矛盾

真正的分析过程是动态的。

可能需要:

先看总收入
 ↓
按广告媒体拆
 ↓
发现 media_B 异常
 ↓
只继续查 media_B
 ↓
看请求、曝光、eCPM
 ↓
发现 eCPM 下降
 ↓
继续按广告位拆
 ↓
找到 position_102

这里每一步都依赖前一步结果。

这就是 Agent 的价值。

但数据场景又非常危险。

你不能让模型随便:

SELECT *
DROP TABLE
查询 10 年历史
访问未授权表

所以 Harness 还必须提供 SQL Safety。

前置条件

最终系统可能提供:

get_schema
query_metric
query_by_dimension
execute_sql

同时固定规则:

只允许 SELECT
查询时间不超过 30 天
禁止 SELECT *
限制表白名单
SQL 超时
查询行数限制

解决过程

一次分析可能是:

Step 1:查询总收入
Observation:下降 20%

Step 2:按媒体拆分
Observation:media_B 下降明显

Step 3:查询 media_B 的请求、曝光、eCPM
Observation:请求稳定,eCPM 下降 35%

Step 4:按广告位拆 eCPM
Observation:position_102 降幅最大

Step 5:形成结论

最终结论可能是:

收入下降主要集中在 media_B。

流量请求基本稳定,因此不是整体流量下降。
media_B 的 eCPM 下降约 35%,其中 position_102 最明显。

当前证据更支持“变现价格下降”而不是“请求量下降”。

把这次分析展开成一条证据链,就能看到 Data Analysis Agent 和普通 Text-to-SQL 的本质差别:

图片[1]-案例分析二:一个 Data Analysis Agent 为什么不能只是“问题 → SQL → 答案”?-大赛人网

总收入下降只是起点,媒体、指标和广告位的每一次下钻都由上一轮 Observation 决定;但每条查询都必须经过同一套 SQL Safety。也就是说,分析方向可以动态变化,数据权限和查询成本不能跟着模型一起漂移。

输出结果

除了结论,我们还希望保留:

执行过的 SQL
每条 SQL 耗时
每轮 Agent 决策
Tool Result
Token
Run 状态

这样分析错了以后,才能复盘。

复盘与迁移

这个案例体现了另一种 Harness 能力,让模型负责分析方向,让系统负责数据安全。

后面我们做 Data Analysis Agent 时,不会把 SQL 执行权裸露给模型,而是所有 SQL 都必须经过安全层。

所以 Coding Agent 和 Data Analysis Agent 虽然业务不同,但底层 Harness 思想是统一的。

这套模式也能迁移到运维排障、客服问题诊断、业务指标分析等任务:模型负责判断“接下来查什么”,规则系统负责判断“什么允许查、能查多少、是否需要审批”。这种边界感,是我们整门课希望建立的工程直觉。

常见误区

误解: Agent Harness 就是一个更复杂的 Prompt 模板。
正解: Prompt 只是 Harness 中非常小的一部分。真正的 Harness 还要负责 State、Tool Registry、Tool Execution、Context、Memory、Middleware、权限、安全、Tracing、Session、Run、服务化等能力。一个系统即使 Prompt 写得非常好,只要工具执行没有边界、失败无法恢复、状态无法保存,就很难成为可靠的 Agent 系统。

误解: 既然课程目标是手搓 Agent,就应该完全不用任何框架和第三方库。
正解: “手搓”的重点是把关键机制亲手实现,而不是为了证明自己什么库都不用。我们仍然会使用 Flask、SQLite 以及模型 SDK,因为它们解决的是成熟基础设施问题。我们真正要自己实现的是 Agent 的控制逻辑、Tool 抽象、State、Context、Memory、安全与 Trace,让大家理解框架背后的核心机制,而不是重复造无意义的轮子。

误解: Flask 是 Agent 的核心,所以应该把所有逻辑都写在 Flask 路由里。
正解: Flask 只是服务接口层。Agent Engine、Tool、Memory、Tracing 等核心能力应该与 Web 框架解耦。这样同一个 Agent 以后既可以通过 Flask API 调用,也可以通过 CLI、定时任务、机器人或其他服务调用。如果所有逻辑都塞进 Route,系统很快会变成难测试、难复用、难维护的大函数。

误解: 模型既然已经很强,权限、安全、最大步数这些东西可以靠 Prompt 约束。
正解: Prompt 只能表达期望,不能代替执行层规则。真正危险的动作必须在 Harness 中做硬限制,例如路径校验、命令黑白名单、SQL 只读限制、最大步数、超时与 Human Approval。我们永远不能把系统安全建立在“模型应该会听话”这个假设上。

有些同学会认为只要 Agent 能调用工具并返回结果,就已经完成了工程化。实际上,一个真实 Agent 还需要回答:任务执行到哪一步?失败后能否恢复?服务重启后状态是否存在?用户能否实时看到进度?每一步消耗多少 Token?哪一个 Tool 最容易失败?这些问题都属于 Harness 与 AgentOps 范畴,也是课程后半段重点补齐的能力。

还有一种误区,是把“多步”自动等同于“Agent”。一个固定的五步 Workflow 同样可以非常多步,但只要路径仍然是开发者提前确定的,它就不需要 Agent。我们真正关注的是:任务执行过程中,模型是否要根据 Observation 动态决定下一步。下一节开始,我们会把这个差别从概念真正落实到 Main Loop 代码里。

这一节学到什么程度就够了

这一节信息很多,但我们不需要靠“全部记住”来过关。先合上前面的内容,看看自己能不能说清下面四句话:

  1. LLM 负责决定下一步,但不会直接读取文件或执行 Python。
  2. Tool 才会接触真实环境,执行结果会作为 Observation 返回。
  3. Harness 负责把决策变成受控执行,并保存状态、处理错误、记录过程。
  4. Flask 只是对外入口,不能代替 Agent Engine、Tool、Memory 和安全层。

如果这四句话能用自己的语言解释出来,本节主线就已经掌握了。至于 Streaming 如何推送、Memory 如何持久化、SubAgent 如何协作,现在说不清完全没关系;后面的章节会把它们逐个拆开。

你还可以做一个两分钟的小练习:假设用户说“帮我读取 app.py”,尝试在纸上写出 用户请求 → 模型决策 → Tool Call → 权限检查 → 文件读取 → Observation → 模型回答。只要能标出每一步由谁负责,就已经建立了第一层 Harness 直觉。

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发
头像-大赛人网
欢迎您留下宝贵的见解!
提交
头像-大赛人网

昵称

取消
昵称

    请登录后查看评论内容