场景背景
再看另一个最终项目。
业务同学问,“昨天广告收入为什么下降?”
最简单做法是 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 → 答案”?-大赛人网](https://www.dsrw.com/wp-content/uploads/2026/11/image-1400.png)
总收入下降只是起点,媒体、指标和广告位的每一次下钻都由上一轮 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 代码里。
这一节学到什么程度就够了
这一节信息很多,但我们不需要靠“全部记住”来过关。先合上前面的内容,看看自己能不能说清下面四句话:
- LLM 负责决定下一步,但不会直接读取文件或执行 Python。
- Tool 才会接触真实环境,执行结果会作为 Observation 返回。
- Harness 负责把决策变成受控执行,并保存状态、处理错误、记录过程。
- Flask 只是对外入口,不能代替 Agent Engine、Tool、Memory 和安全层。
如果这四句话能用自己的语言解释出来,本节主线就已经掌握了。至于 Streaming 如何推送、Memory 如何持久化、SubAgent 如何协作,现在说不清完全没关系;后面的章节会把它们逐个拆开。
你还可以做一个两分钟的小练习:假设用户说“帮我读取 app.py”,尝试在纸上写出 用户请求 → 模型决策 → Tool Call → 权限检查 → 文件读取 → Observation → 模型回答。只要能标出每一步由谁负责,就已经建立了第一层 Harness 直觉。
















请登录后查看评论内容