这两年做 AI Agent 的人,几乎隔一阵子就会换一个说法。

先是 chain,然后是 loop,现在又轮到 graph。看起来像是范式升级,实际上很多时候只是把同一件事换了个名字。

这件事就是:有限状态机(Finite State Machine, FSM)

如果你把一个系统里“当前处于什么状态”“发生了什么事件”“接下来应该去哪里”这三件事单独拎出来看,你会发现很多工作流框架最后都在逼近同一个结构。

这不是学院派的抽象游戏,而是一个非常务实的工程结论。因为一旦你把控制流显式建模成状态机,很多原本靠经验、注释和补丁维持的复杂逻辑,就会变得可枚举、可测试、可恢复。

先把核心问题讲透

状态机只回答一个问题:

在当前状态下,发生某个事件后,系统应该进入哪个下一个状态?

写成函数就是:

transition

几乎所有程序都在做这件事。

  • • React 组件会根据当前状态和用户动作更新 UI
  • • 后端服务会根据请求结果决定成功、失败还是重试
  • • 游戏循环会根据输入和碰撞事件切换行为
  • • AI Agent 会根据工具结果、评估结果和人工反馈继续执行、重试、暂停或结束

也就是说,程序天然就有状态机的形状。差别只在于:你是把这套逻辑显式写出来,还是让它散落在各个 if、回调和布尔变量里。

为什么很多系统会失控

看一个最常见的前端例子:

let falselet falselet falselet nulllet null

乍看很正常,但问题马上就来了。

3 个布尔值会产生 2^3 = 8 种组合,可真正有意义的状态可能只有 3 种。于是像 isLoading && isError 这种组合,在语义上根本说不通,却完全可能在竞态条件下出现。

这就是很多线上诡异 bug 的来源:

  • • 加载中转圈还没消失,错误提示已经弹了
  • • 成功态的数据还在页面上,失败态的 toast 又叠了一层
  • • 用户双击提交后,两个请求同时跑起来

本质原因不是“你防守不够严”,而是你的状态表示方式允许不合法状态存在

如果改成:

type State 'idle' 'loading' 'success' 'failure'

那“既在 loading 又在 error”这种状态根本写不出来。

这就是函数式编程里常说的那句话:

Make illegal states unrepresentable.

状态机最有价值的地方,不只是“组织代码更清晰”,而是它能把一整类矛盾状态直接从模型层面删掉。

状态机带来的两个硬约束

一旦你显式建模,立刻得到两个非常强的保证:

  1. 系统任意时刻只处于一个明确状态
  2. 系统只能沿着你定义过的转移路径移动

第二点尤其重要。

在散乱的 flag 代码里,任何事件处理器都可能随时改动任意东西;但在状态机里,如果当前状态没有定义某个事件的转移,那这个事件就什么都做不了。

这意味着很多“补救型工程技巧”会自然消失。

比如用户双击提交按钮:

  • • 第一次 SUBMITidle -> loading
  • • 第二次 SUBMIT:此时还在 loading
  • • 因为 loading 没定义 SUBMIT,第二次事件直接无效

于是你不需要额外再发明一个 isSubmitting 来兜底,也不需要手搓 debounce 才能避免重复提交。

最朴素的状态机实现

最简单、也最干净的方式,就是把转移逻辑当成数据表:

const  initial 'idle'  states    idle      FETCH 'loading'    loading      RESOLVE 'success'      REJECT 'failure'      CANCEL 'idle'    success      REFETCH 'loading'    failure      RETRY 'loading'function transitionstate, event  returnstates

这个实现有几个非常实在的好处:

  • • 行为全集能在一个地方看全
  • • 代码评审时,diff 直接对应行为变化
  • • 规则可以序列化、存库、网络传输,甚至自动画图
  • • 测试可以把“状态 × 事件”的有限表完整遍历一遍

当你的系统能被枚举,测试方式就会从“抽样碰碰运气”变成“系统性穷举”。

真正的程序为什么还能叫“有限”状态机

很多人第一次接触 FSM 会卡在这里:

现实系统里还有表单内容、时间戳、数组、计数器,这些怎么可能是有限的?

答案是把状态拆成两层:

  • 有限状态:系统处于哪种模式,比如 idleloadingediting
  • 上下文(context):和模式同行的具体数据,比如输入值、重试次数、拉取结果

于是转移函数从:

transition

扩展成:

transition

比如失败后允许最多重试 3 次:

function transitionstate, ctx, event  if 'failure'type 'RETRY'    ifretries 3      return'loading' retriesretries 1'fetch'    return'gaveUp''notifyUser'

这里顺手带出三个很重要的概念:

  • Guard:守卫条件,决定同一个事件在不同条件下走哪条边
  • Action:副作用描述,状态机负责决定“应该做什么”,真正执行动作的是外部解释器
  • Entry/Exit Action:进入或离开某个状态时统一触发的行为,比如进入 loading 开 spinner,退出 loading 统一清理 timer

这套设计的妙处在于:控制流和副作用被拆开了

也正因为如此,状态转移函数可以保持纯净,测试时不需要一堆 mock。

这和 Agent Graph 有什么关系

关键就在这里。

一个 Agent Graph,本质上就是在描述:

  • • 当前处于哪个节点
  • • 收到什么结果或信号
  • • 下一步跳到哪里

把它翻译成状态机语言,就是:

  • • 节点 = S
  • • 事件 = Σ
  • • 边 = δ
  • • 起点 = s0
  • • 终点 = F

也就是说,graph 并没有摆脱状态机,它只是把状态机画出来了

一个很典型的 Agent 工作流可能长这样:

const  initial 'planning'  states    planning      PLAN_READY 'executing'      NEEDS_INFO 'awaitingHuman'    executing      TOOL_RESULT 'evaluating'      TOOL_ERROR 'executing'      BUDGET_EXCEEDED 'failed'    evaluating      VERIFIED 'done'      NOT_GOOD_ENOUGH 'planning'      UNSAFE 'awaitingHuman'    awaitingHuman      APPROVED 'executing'      REJECTED 'failed'      CLARIFIED 'planning'    done    failed

这就是一个标准状态机,只不过现在大家更喜欢叫它“agent graph”。

为什么这对 Agent 尤其重要

Agent 和普通程序相比,有两个额外麻烦:

  1. 模型输出本身是不稳定的
  2. 工作流经常需要长时间运行、暂停、恢复、人工介入

显式状态机刚好能处理这两个问题。

1. 不要让模型直接控制流程

如果你把“是否结束”“是否安全”“是否要重试”直接交给模型自由发挥,系统很容易出现一种经典事故:

任务其实没完成,但模型说自己完成了。

状态机的做法不是让模型直接决定下一步,而是先把模型输出归类成事件,比如:

  • VERIFIED
  • NOT_GOOD_ENOUGH
  • UNSAFE

然后再由状态机检查:

这个事件在当前状态下是否有合法转移?

模型可以胡说,但胡说出来的事件如果没有合法边,就不会改变系统状态

这比“把规则写进 system prompt 里希望模型听话”可靠得多。

2. Retry 逻辑终于能被结构化表达

很多 agent loop 之所以失控,是因为重试逻辑只是一个 while 加计数器,靠人记得在合适的时候停。

如果改成状态机,重试就是一条带 guard 的边:

  • evaluating -> planning,前提是 attempts < maxAttempts

这样一来,死循环不是“希望不要发生”,而是模型结构上就不允许无限发生

3. 长任务可以自然持久化

一个等待人工审批 3 天的 agent,不需要整个进程一直活着。

你只要把下面这对值存起来:


(currentState, context)

等审批 webhook 到了,再把它恢复出来继续跑就行。

这也是为什么很多工作流引擎,比如 Temporal、AWS Step Functions,会天然跟状态机思路靠得很近。

状态机不是万能钥匙

也别走到另一个极端。

以下情况就不一定值得上状态机:

  • • 纯顺序流程,A 跑完接 B,B 跑完接 C,中间没有等待、分支、失败恢复
  • • 连续数值系统,比如物理模拟、数值求解
  • • 简单到只需要一个二元开关的场景

一个很实用的判断信号是:

当你代码里出现第二个会互相影响的布尔变量,或者开始写“只有当前处于某种状态时才能……”这种注释时,基本就该考虑状态机了。

进一步扩展:为什么还会有 statechart

平面状态机也有自己的扩展性上限。

比如一个编辑器里,bolditalicunderline 都能独立切换。如果你硬把它们全部拍平成状态,很快就会组合爆炸。

这时就会进入 statechart 的世界:在普通状态机基础上,引入层级、并行区域和历史状态。

这部分可以展开很多,但对大多数工程实践来说,记住一句就够了:

statechart 不是推翻状态机,而是给大状态机做压缩和组织。

所以无论是 UI 框架、工作流引擎,还是 Agent orchestration library,只要开始认真处理复杂控制流,最后大概率都会朝这个方向靠。

最后的判断标准

以后再看到新的工作流框架、agent runtime 或 orchestration 抽象,其实可以只问三个问题:

  1. 它有没有清楚定义状态?
  2. 它有没有清楚定义事件?
  3. 它有没有清楚定义转移?

如果这三件事都能回答清楚,那它大概率只是一个状态机的变体,值得你用工程方法去分析、测试和验证。

如果回答不清,那往往只是把控制流重新打散,再换一套营销语言包装出来。

AI Agent 领域现在从 loop 走向 graph,看起来像升级;但从计算机科学的视角看,更像是大家终于开始重新发明那个几十年前就已经很好用的轮子。

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

在这里插入图片描述

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

在这里插入图片描述

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐