🤖 第七章 应用实战:财报分析智能体
📄 一句话概括

前六章的 RPA,等的是秒;这一章等的是分钟(规划模式实测十几分钟量级)。而这一节的 RPA 干的活比前面都少——它不再编排流程,只做三件事:送任务、等结果、搬成果。难点全部集中在那个"等"字上。

📝 本节和前面几节的关系

7.2 全节讲的是"怎么让智能体把活干对";本节讲"怎么让机器把这件事重复跑起来"。 与 6.4 对照:第六章的 RPA 是主角(三节都在讲怎么送、怎么取、怎么填);本章的 RPA 退成了配角——因为"怎么拆任务"这件事,已经交给扣子空间自己做了。RPA 剩下的活,是把它接到一条能重复执行的轨道上。 与 5.4.1 对照:那里也讲"发起会话并取回",但那里等的是一次生成的几十秒,本节等的是一次规划任务的十几分钟——量级变了,等待的写法就必须变。

一、这一章的 RPA 为什么变"轻"了

先看这个变化,它决定了本节的重心:

第六章 本章
谁编排流程 RPA 编排(送单→取结果→填 ERP) 扣子空间自己规划
RPA 的角色 主角(三节全讲它) 配角(传送带)
RPA 要懂业务吗 要(字段映射、主数据) 不需要(它只搬文件、搬链接)
等的量级 秒 分钟

"RPA 变轻"不等于"这一节不重要"——恰恰相反:编排的复杂度降低了,稳定性的复杂度升高了。因为:

编排复杂 → 出错时你知道错在哪一格(第六意)
自主规划 → 出错时你要重看它怎么想的(本章)

RPA 在自主规划的产品上跑,最大的风险不是"它做错了",而是"它做了一半、你不知道它算不算做完了"。

二、RPA 在这条链上只做三件事

① 送任务     打开页面 → 上传财报 → 填任务描述 → 提交
② 等结果     轮询状态 → 到点了取回 → 记录耗时与状态
③ 搬成果     把产出(网页链接/文件)落到本地表里,并在表里留痕

三件事里,只有第 ② 件是新的——前六章的"等"大多是几秒到几十秒;本章的"等"是十几分钟,而且要在一批任务里循环地等。

三、等待:分钟级的等待怎么写

这是本节的核心。三条规则:

3.1 不能写死 sleep,只能轮询

# ✗ 错误写法:赌它一定在 15 分钟内跑完
sleep(900)
result = get_result()

# ✓ 正确写法:每 30 秒看一眼,超过超时线就上报
deadline = start + timeout_of(job)
while now() < deadline:
    st = get_status(job_id)
    if st in ("完成", "失败"):
        break
    sleep(30)

为什么不能写死:通用智能体"思考多久"本身不确定——同一个任务,两次耗时可能差一倍。写死 sleep,等于赌一个你不掌握的数。

3.2 超时线 = 预估 × 2(且不低于一个下限)

def timeout_of(est_minutes):
    return max(est_minutes * 2, 10)     # 预估的两倍,但不低于 10 分钟

为什么定在两倍:在"等"这件事上,误杀比多等更贵。 - 多等的成本:占着一台机器的十几分钟; - 误杀的成本:一个可能已经跑完的任务被判定失败,人再去重跑一轮。

3.3 探索模式与规划模式,等待要分档

同一个 RPA 上会同时跑两类任务:探索模式 2~3 分钟就回来,规划模式要十几分钟。等待逻辑必须按任务分档,不能一个数管全部。

⚠️ 这一节最容易忽略的一条:**结果必须落盘**

轮询拿回来的结果,要立刻写进本地(表格/文件),而不是留在内存里等整批跑完。 理由和 4.4.1 那条一样:分钟级的长任务里,任何一次中断都会让你丢掉"已经等到的那些分钟"。 落盘之后,中断可以续跑;不落盘,中断就是白等。

四、批次与并发

分钟级的任务,排期是绕不过去的问题。三个数要一起算:

项 怎么定 为什么
一批多少条 受附件上限(10 个) 与人工复核量双重约束 一次跑太多,异常表会超出人能处理的上限(与 6.5 那条"异常表越大越等于没有"同源)
要不要并行 可以多开会话并行,但要控制路数 并行能压缩总时长,但会同时产出多份结果,复核压力集中爆发
总预算 串行时长 ÷ 并行路数 用来判断"今天这批能不能跑完"

Demo 里那批 8 个任务的算术:串行约 96 分钟(规划 6 个 × 15 分 + 探索 2 个 × 3 分);并行 3 路约 32 分钟。

五、对账:那行加法又出现了

完成 + 超时 + 失败 = 本轮提交数

对不上,就说明有任务不知去向——它不报错,只是不见了。

这条纪律在 4.4.2 出现过("部分成功+留痕"),在 6.4.2 用过一次(通过+待人+重试=提交数),本节是第三次。它出现的场景越来越"安静":

第四章:一次调用返回 9 个结果 → 数量对不上,看得见
第六章:一批提交 8 条 → 有结果丢失,不报错
本章  :一个任务跑十几分钟 → 中途消失,连痕迹都没有

六、四条纪律

① 不写死 sleep——一律轮询(间隔 30 秒量级),且可中断、可续跑;
② 超时线 = 预估 × 2(不低于下限)——宁可等,不要误杀;
③ 探索与规划分档等待——同一台 RPA 上混着跑,不能一个数管全部;
④ 结果必须落盘——长任务的每一分钟,都要能被保住。

七、⚠️ 2026 现状:这一侧的两件事

现状一:平台的产出是云端的,RPA 才有稳定抓取目标

扣子空间的产出(网页链接、生成的文件)都在云端,且跨端同步。这对 RPA 是好事:它只要盯住一个链接或一个文件列表,不用去猜界面在哪儿。

但反过来说:界面随时会变(产品在快速迭代,版本号 3.x 量级频繁更新)。所以本节的纪律和 1.4.2 一样:能抓数据就不截图,能截图就不点坐标——RPA 脚本的寿命,取决于它绑定的东西有多稳定。

现状二:长任务的失败,往往是"静默"的

这是本节最该记住的一句现状:跑十几分钟的任务,失败的方式常常不是报错,而是"没有结果"。

三种情况下,界面都不会给你一个醒目的失败提示——所以那行加法不是可选项,是必需品。

八、动手 Demo:RPA 的等待预算与对账

下面这个脚本给一批任务算三笔账:要等多久、超时线在哪、对不对得上。

# -*- coding: utf-8 -*-
"""7.3 Demo:RPA 的等待预算与对账

通用智能体一个任务的耗时是【分钟级】,
和第六章扣子工作流的【秒级】完全不是一个量级。
本 Demo 给一批任务算三笔账:等多久、查几次、对不对得上。
"""

POLL_SEC = 30          # 轮询间隔
OVER = 2.0             # 超时上限 = 预估 × 2
MIN_TIMEOUT = 10       # 但不少于 10 分钟

# (任务号, 公司, 模式, 预估分钟, 实际分钟)
JOBS = [
    ("T1", "600519", "规划", 15, 17),
    ("T2", "000858", "规划", 15, 13),
    ("T3", "000568", "规划", 15, 15),
    ("T4", "600809", "探索", 3, 2),
    ("T5", "002304", "规划", 15, 34),
    ("T6", "600600", "探索", 3, 3),
    ("T7", "603288", "规划", 15, 16),
    ("T8", "000596", "规划", 15, 0),
]


def timeout_of(est):
    return max(est * OVER, MIN_TIMEOUT)


def verdict(act, tmo):
    if act == 0:
        return "失败"
    if act > tmo:
        return "超时"
    return "完成"

看到什么算成功(真实输出):

==============================================================================
  7.3 Demo:8 个任务的等待预算与对账
==============================================================================

  排期约定:轮询间隔 30 秒;超时上限 = 预估 × 2(不低于 10 分钟)
  批次上限:一批最多 6 个任务

一、逐任务:要等多久、超时线在哪
------------------------------------------------------------------------------
  任务  标的      模式  预估    超时线    实际    判定
  --------------------------------------------------------------------------
  T1    600519    规划  15 分   30 分     17 分   完成
  T2    000858    规划  15 分   30 分     13 分   完成
  T3    000568    规划  15 分   30 分     15 分   完成
  T4    600809    探索  3 分    10 分     2 分    完成
  T5    002304    规划  15 分   30 分     34 分   超时(34.0 分钟 > 30)
  T6    600600    探索  3 分    10 分     3 分    完成
  T7    603288    规划  15 分   30 分     16 分   完成
  T8    000596    规划  15 分   30 分     —       失败

二、时间预算(关键:这是分钟级,不是秒级)
------------------------------------------------------------------------------
  规划模式 6 个 × 约 15 分钟 = 90 分钟
  探索模式 2 个 × 约 3 分钟  = 6 分钟
  串行跑完整批(按预估)≈ 96 分钟(1.6 小时)
  若在扣子空间里多开会话并行 3 路 ≈ 32 分钟

  ⚠️ 一个任务跑十几分钟,RPA 的【等待】就必须可中断、可续跑——
     不能写死 sleep(900),要写【每 30 秒查一次、超过超时线上报】。

三、对账
------------------------------------------------------------------------------
  完成 6 + 超时 1 + 失败 1 = 8 ;本轮提交 8 个  ✅ 对得上 —— 没有任务丢失
  实际累计等待:100 分钟(1.7 小时)

四、读结果
------------------------------------------------------------------------------
  ① T5 用了 34 分钟——超过了 30 分钟的超时线,被判超时。
     这不是故障:通用智能体【思考多久】本身就不确定,
     所以超时线只能定成【预估的两倍】,宁可等,不要误杀。
  ② T4/T6 是探索模式,2~3 分钟就回来了。同一台 RPA 上,
     快任务和慢任务混着跑,等待逻辑必须按任务分档。
  ③ 对账那一行是本章从第六章搬过来的纪律——只是这里要等的
     从【几秒】变成了【十几分钟】,更需要对得上。
  ④ T8 的结果是空的:这一条既不在结果里,也没报错,
     只有靠那行加法才看得出来——和 6.4.2 那条纪律是同一条。

==============================================================================

读结果:

30 秒实验

打开手机计时器,做一件事:

计一次【你自己读完一份年报的"管理层讨论"部分】要多久。

常见误区

  1. 【写死 sleep 最简单】——它赌的是一个你不掌握的数。 通用智能体耗时波动大,写死 sleep 的脚本迟早会在某一次运行中翻车(要么白等,要么提前取到空结果)。
  2. 【超时了就判失败,重跑一条】——重跑的成本比多等贵。 超时线定两倍、宁可等:因为一个任务可能只是"慢",不是"坏"。
  3. 【跑完再看,中间不用管】——结果必须逐条落盘。 长任务里任何一次中断都意味着丢掉已经等到的那些分钟;落盘之后才可续跑。
  4. 【没报错就是都成功了】——本章的失败常常静默。 跑十几分钟的任务,失败的样子是"没有结果"。对账那一行加法,是唯一的兜底。
自测三问(点开对答案) 1. **本章的 RPA 为什么比第六章"轻"了?"轻"为什么反而更要小心?** **变轻的原因**:**"怎么拆任务"已经交给扣子空间自己做了**(这是 7.1 讲的形态变化)。第六章的 RPA 要编排送单→取结果→填 ERP 的完整流程、要懂字段映射;**本章的 RPA 只做三件事:送任务、等结果、搬成果。** **"轻"更要小心的原因**:**编排复杂时,出错你知道错在哪一格;自主规划时,出错你要重看它怎么想的**。所以 RPA 在自主规划的产品上跑,**最大的风险不是"它做错了",而是"它做了一半、你不知道它算不算做完了"。** **具体到本节**:这个风险全部集中在**"等待与对账"**上——**这也是本节只讲这两件事的原因。** 2. **"等待"的三条规则各解决什么问题?为什么超时线要定在"预估的两倍"?** 三条规则:**① 不写死 sleep,只轮询**——解决"它的耗时我不掌握"的问题(写死 `sleep` 是在赌一个不确定的数);**② 超时线 = 预估 × 2(不低于下限)**——解决"它可能只是慢"的问题;**③ 探索与规划分档等待**——解决"同一台机器上快慢任务混跑"的问题。 **超时线定两倍的原因**:**在"等"上,误杀比多等更贵。** 多等的成本是**占着一台机器十几分钟**;误杀的成本是**一个可能已经跑完的任务被判失败,人要再跑一轮**。 **一句话**:**宁可等,不要误杀。** 3. **为什么"结果必须落盘"这一条,在分钟级任务里比秒级任务里更重要?** 因为**中断的代价变了**。 **秒级任务里**:一次中断,最多丢几十秒——重跑一遍不心疼。 **分钟级任务里**:**你等的每一分钟都是真实成本**。如果结果留在内存里等整批跑完,**任何一次中断(网络断了、浏览器关了、脚本崩了)都会让前面等的所有分钟一起作废**。 **落盘之后,中断可以续跑**——只补没跑完的那几条。 **这条和 4.4.1 的"长任务的轮询+超时+落盘"是同一件事**,只是那时是"批量上传",现在是"批量分析",**而任务从几十秒变成了十几分钟**。 **本节的三句话可以带走**:**① 编排交出去了,稳定性就得自己扛——本章的难点全在"等"字上;② 不写死 sleep、超时线定两倍、快慢分档——等待的三条规则;③ 长任务的失败是静默的,结果必须逐条落盘。**

相关笔记