从 Loop 到 Graph:为什么 Agent 工作流本质上是状态机
这两年做 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.
状态机最有价值的地方,不只是“组织代码更清晰”,而是它能把一整类矛盾状态直接从模型层面删掉。
状态机带来的两个硬约束
一旦你显式建模,立刻得到两个非常强的保证:
- 系统任意时刻只处于一个明确状态
- 系统只能沿着你定义过的转移路径移动
第二点尤其重要。
在散乱的 flag 代码里,任何事件处理器都可能随时改动任意东西;但在状态机里,如果当前状态没有定义某个事件的转移,那这个事件就什么都做不了。
这意味着很多“补救型工程技巧”会自然消失。
比如用户双击提交按钮:
- • 第一次
SUBMIT:idle -> 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 会卡在这里:
现实系统里还有表单内容、时间戳、数组、计数器,这些怎么可能是有限的?
答案是把状态拆成两层:
- • 有限状态:系统处于哪种模式,比如
idle、loading、editing - • 上下文(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. 不要让模型直接控制流程
如果你把“是否结束”“是否安全”“是否要重试”直接交给模型自由发挥,系统很容易出现一种经典事故:
任务其实没完成,但模型说自己完成了。
状态机的做法不是让模型直接决定下一步,而是先把模型输出归类成事件,比如:
- •
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
平面状态机也有自己的扩展性上限。
比如一个编辑器里,bold、italic、underline 都能独立切换。如果你硬把它们全部拍平成状态,很快就会组合爆炸。
这时就会进入 statechart 的世界:在普通状态机基础上,引入层级、并行区域和历史状态。
这部分可以展开很多,但对大多数工程实践来说,记住一句就够了:
statechart 不是推翻状态机,而是给大状态机做压缩和组织。
所以无论是 UI 框架、工作流引擎,还是 Agent orchestration library,只要开始认真处理复杂控制流,最后大概率都会朝这个方向靠。
最后的判断标准
以后再看到新的工作流框架、agent runtime 或 orchestration 抽象,其实可以只问三个问题:
- 它有没有清楚定义状态?
- 它有没有清楚定义事件?
- 它有没有清楚定义转移?
如果这三件事都能回答清楚,那它大概率只是一个状态机的变体,值得你用工程方法去分析、测试和验证。
如果回答不清,那往往只是把控制流重新打散,再换一套营销语言包装出来。
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%免费】

更多推荐


所有评论(0)