← 数据分析 Agent

归因需要逐层下钻时,怎么用状态图决定往下查、往上查还是结束?

困难 第 14 / 18 题 更新于 2026/09/27
数据分析AgentLangGraph状态图条件边归因分析
学习 AI 实战项目

简化版

逐层下钻的特点是下一步查什么取决于上一步的检验结果,写不进一份事先列好的计划。状态图正好表达这种编排:节点做具体的事(提假设、取数检验、判定、成文、校验),条件边根据运行时的结果决定去向,环让流程可以回头再验下一条假设或回炉重写。比如判定出「只有这个板块在跌」就往下查供给和区域事件,「全区都在跌」就往上查全市,「全市都在跌」就横向比其他城市。两个关键护栏:每个环都有轮数上限,并且轮数从数据库里数而不是放在内存变量里;超上限时明确收口——没验到的假设标为未验证,结论一条都过不了就标失败,不输出空洞的报告。

详细版

一个典型的归因状态图:

假设生成 ──► 取数与检验 ──► 路由判定 ──┬──► 取数与检验(外环:验下一条假设 / 下钻 / 放宽粒度重查)
                                      └──► 归因成文 ──► 证据校验 ──┬──► 归因报告
                                                                   ├──► 归因成文(内环:带改进指令回炉)
                                                                   └──► 归因失败
组成作用
节点每个节点做一件事,具体动作由业务层注入
条件边一(路由判定之后)还有假设没验且外环有轮数 → 回取数检验;否则 → 去成文
条件边二(证据校验之后)有结论通过 → 出报告;全部驳回且内环有轮数 → 回炉;轮数用尽 → 失败
外环围绕「验证假设」的循环,处理下钻、换假设、数据不足
内环围绕「写对结论」的循环,处理证据校验不通过

下钻方向的决策示例:

本板块跌、同区其他板块不跌 → 问题在本板块 → 往下查:供给、区域事件、小区口碑
同区其他板块也在跌         → 不是本板块的问题 → 往上查:全市大盘
全市都在跌                 → 横向比:其他城市同期走势

完整版教学

一、为什么固定计划不够用

计划—执行(Plan-and-Execute)适合维度可以事先列出的分析:先列好五个步骤,逐个执行。但归因往往不是这样:

第 1 步发现:A 板块近一年跌了 12%,同区平均跌 4%
  → 下一步应该查 A 板块自身:供给是否激增、有没有区域事件
第 1 步如果发现:同区平均也跌了 11%
  → 下一步应该往上查:全市是不是都在跌

同一个起点,下一步完全不同,取决于检验结果。硬写成固定计划,要么把所有分支都列进去(浪费大量取数),要么漏掉关键方向。这种「运行时分岔」正是状态图的用武之地。

二、状态图的三个原生能力

用一串 if-else 或 while 循环也能写出来,但状态图把三件事变成了显式结构:

条件边。 一个节点之后有多个去向,走哪条由运行时状态决定。判定节点可能有「成立 / 证伪 / 数据不足」三个出口,但去向只有「接着验」和「去成文」两种——出口名和去向不是一回事,出口名要单独记录下来,页面上才能反查每一步做了什么决定。

环。 验完一条假设回去验下一条,结论不合格回去重写,这些都是环。环必须有退出条件,否则就是死循环。

可中断。 一次归因要跑多轮模型调用和检验,可以按入口和停点分段推进,每次只推进一轮,页面上边跑边看。

三件事手写也能实现,但写完是一张没人看得懂的调用关系;状态图本身就是一张可读的流程图,和代码一一对应。

记忆钩子:节点回答「做什么」,条件边回答「接下来去哪」,环回答「什么时候回头」,轮数上限回答「什么时候必须停」。

三、图只管编排,不碰数据库和模型

一个好的分层是:图只负责「什么时候调谁、能不能停」,每个节点具体做什么由业务层注入。

图(编排层):节点、条件边、环、轮数上限
钩子(业务层):提假设怎么调模型、取数用哪个工具、判定用什么规则、结论怎么落库

好处是图可以脱离数据库和模型单独测试(注入假的钩子,验证各种分支走向是否正确),业务改动也不会碰到编排逻辑。

四、两个环各管什么

外环内环
目的验证假设写出能通过证据校验的结论
起点路由判定之后证据校验之后
回到取数与检验归因成文
触发还有假设没验,或需要下钻、放宽粒度结论全部被驳回
用尽时剩余假设标为未验证,按已有结果成文收口标失败,保留每轮驳回原因

外环:验证假设。 每一轮取一条待验证的假设,取数、检验、判定。判定结果决定下一步:成立或证伪都记下来,继续验下一条;数据不足时可以放宽一层粒度重查(小区 → 板块);还可以根据结果提出新的假设(比如往上查全市)。外环轮数用尽时,剩下的假设留在「待验证」,报告里明确写「没验到」,不假装它们成立。

内环:写对结论。 归因成文后做证据校验,全部驳回时带着改进指令回炉重写。回炉不是简单地「再来一次」:

点名式改进指令:第几条结论、正文是什么、被什么原因驳回、应该怎么改
末尾补一句:没有被点名的结论保持不变

因为成文每一轮是整份重写,不点名的话,上一轮已经过关的结论可能被顺手改坏,序号一变,报告里引用的「第几条」「第几步」就全对不上了。内环轮数用尽仍没有结论通过,就收口标失败,每一轮被驳回的原因留在各自的步骤记录里。

五、轮数为什么要从数据库里数

一次归因要跨多次请求推进,进程也可能中途重启。如果轮数存在内存变量里:

进程重启 → 计数归零 → 模型又拿到一整轮预算 → 轮数上限形同虚设

做法是:每次进入某个节点前,数一下这个任务在这个节点上已经落过几条步骤记录,加一就是本次的轮次号。步骤记录本来就要写,轮数顺带就数出来了,不需要额外的计数表,也天然支持断点续跑。

六、分段推进和失败恢复

分段推进。 同一张图可以按不同的入口和停点编译:首轮从「假设生成」进、在「取数与检验」后停;之后每次从「取数与检验」进、在「路由判定」后停,一次恰好推进一轮。续跑时直接从取数检验进入,不会让模型把同一批假设重提一遍。停点要用框架确实支持的机制实现,最好通过测试确认「真的停住了」,否则图会一路跑到底。

失败恢复。 失败后能不能重跑,要看断在哪一步:断在模型调用的环节(成文、报告),通常是调用偶发失败,可以允许重跑;断在取数、校验这些确定性环节,多半是数据、工具或代码的问题,同样的路再走一遍还是同样的结果,应该先修复原因。

七、状态里放什么

状态图的状态(State)要精简,只放决定流程走向和节点之间传递所需的信息:

任务 ID、分析对象、问题类型
当前假设、待验证假设列表
最近一步的判定结果和出口名
当前结论与校验结果

大块的取数结果、完整的步骤历史应该落库,状态里只放引用(ID)。状态太大,每次续跑重建状态的成本就高,也容易出现状态和数据库不一致。

八、常见误区与追问

  • 误区:逐层下钻也可以事先列成固定计划。 下一步查什么取决于检验结果,固定计划要么浪费取数,要么漏掉方向。
  • 误区:状态图就是把 if-else 换个写法。 它把条件边、环和可中断变成显式结构,流程图和代码一一对应,可读可测。
  • 误区:环的计数用内存变量就行。 进程重启后计数归零,上限失效,应该从数据库的步骤记录里数。
  • 误区:结论不合格就让模型整份重写。 要点名到条并声明未点名的保持不变,否则已过关的结论会被改坏。
  • 误区:轮数用尽了就用现有内容凑一份报告。 没验到的假设要明确标为未验证,一条结论都没过关就收口标失败。
  • 追问:什么时候用状态图,什么时候用计划—执行? 维度能事先列出用计划—执行;下一步取决于中间结果时用状态图。
  • 追问:失败后都能重跑吗? 断在模型调用环节可以重跑;断在取数、校验这类确定性环节,要先修复原因。

九、加强记忆

归因下钻的下一步取决于检验结果,写不进固定计划,所以用状态图:节点做事,条件边决定去向,环用来回头,轮数上限决定何时必须停。一种可行的结构是两条条件边加两个环:外环验证假设,按结果往下查、往上查或横向比,轮数用尽剩下的标未验证;内环写对结论,全部驳回带点名指令回炉,并声明未点名的保持不变,用尽标失败。图只管编排,业务动作由钩子注入,可单测。轮数从数据库数,支持重启续跑;按入口和停点分段推进;断在模型环节可重跑,断在确定性环节先修因。