用状态机重写 AI Agent 后,几千行的 if-else 变成了一张状态逻辑图
前言
大家好,我是咪的Coding。
今天我想给大家介绍状态机的思想。首先让我们来假设这样一个场景:
你正在开发一个智能助手 Agent。它一开始只需要处理简单的一问一答:收到用户消息,调用 LLM,返回结果。用一个 if-else 就能跑起来,看起来很美好。
但很快,迭代要求 Agent 能调用外部工具 —— 查天气、发邮件、读写数据库。接着又需要多轮澄清:用户说“帮我订张票”,它得主动问“去哪?什么时间?”。再后来,工具调用可能超时,LLM 推理可能出错,用户还可能中途取消……你的代码逐渐变成了这种样子:
public void handle(Agent agent, Event event) {
if ("IDLE".equals(agent.getState())) {
if (event instanceof UserMessage) {
// 推理...
}
} else if ("THINKING".equals(agent.getState())) {
if (event instanceof ReasoningDone) {
if (needTool) { /* ... */ }
else if (needClarify) { /* ... */ }
else { /* ... */ }
}
} else if ("TOOL_CALLING".equals(agent.getState())) {
if (event instanceof ToolResult) {
// ...
} else if (event instanceof Timeout) {
// ...
}
} // 还有更多...
}
每次增加一个新行为,整套逻辑就得大改一次,测试时不时冒出“Agent 卡在思考中不动了”的诡异问题。根源在于:状态流转被写死在了嵌套堆砌的条件分支里。
其实,这个问题有一个诞生于半个多世纪前的解决方案——状态机。用状态机重构 Agent 的控制逻辑,可以让它既聪明又可控。
一、什么是状态机
这里我们介绍**“有限状态机”(Finite State Machine, FSM)。一句话介绍:一个东西在任意时刻只能处于有限个状态中的一个,当某个事件发生时,它从当前状态转移到另一个状态,同时可能执行一些动作**。
即当前状态 + 遇到事件 → 下一个状态 + 执行动作
对于 AI Agent,它的生命周期天然适合用状态机来描述。
二、状态机的四个要素
一个状态机包含四个核心:
- 现态(State) —— 当前状态。比如 Agent 正在“思考中”。
- 事件(Event) —— 触发转移的条件。比如 LLM 推理完成,返回了结果。
- 动作(Action) —— 事件引发的操作。比如判断是否需要调用工具、生成回复。
- 次态(Next State) —— 转移后的新状态。比如进入“工具调用”或“生成回复”。

画成状态转移图,Agent 的行为就一目了然:

有了这张图,Agent 的整个控制流就像地铁线路图一样清晰,任何非法跳转(比如从“空闲”直接进“调用工具”)都会被一眼识别。
三、状态机为什么能解决问题
回头看开头那个“一团乱麻”的 Agent 控制器,它的根本问题有三个:状态与行为紧耦合;非法转移靠运行时报错才发现;增加新行为需要改动大量分支。这是一种以事件分支为中心的编程,关注的是“发生了什么”。
状态机则彻底扭转了思路——以状态为中心。

每个状态只关心自己能响应哪些事件,能跳转到哪些状态。这种内聚性带来了三大好处:
- 隔离变更:新增“重试”或“超时处理”状态,只需定义它自己的转移规则,已有状态代码不受影响。
- 编译期安全:如果有人试图定义一个“从空闲直接跳转到回复完成”的非法转移,状态机框架在设计阶段就能直接报错,而不是等线上出现 “Agent 凭空说了一句话” 的灵异事件。
- 业务对齐:状态图直接映射产品文档中的 Agent 行为规范,开发、测试、产品用同一张图沟通,极大减少理解偏差。
用状态机写 Agent,就像给它装上了规则清晰的“轨道”,既保留了其灵活性,又避免了它跳脱出预定的边界。
四、简单实现一个 Agent 状态机
Java 的枚举天生适合实现有限状态机。我们可以把 Agent 的每个状态定义为一个枚举值,并让它们自己决定“能往哪里走”。
先定义事件:
enum AgentEvent { USER_MSG, REASONING_DONE, NEED_TOOL, NEED_CLARIFY,
TOOL_RESULT, TIMEOUT, RESPONSE_SENT }
核心是状态枚举——每个状态重写 next 方法,把自己允许的转移规则写进去:
enum AgentState {
IDLE {
public AgentState next(AgentEvent e) {
if (e == AgentEvent.USER_MSG) return THINKING;
throw illegal(e);
}
},
THINKING {
public AgentState next(AgentEvent e) {
if (e == AgentEvent.NEED_TOOL) return TOOL_CALLING;
if (e == AgentEvent.NEED_CLARIFY) return WAITING_USER;
if (e == AgentEvent.REASONING_DONE) return RESPONDING;
throw illegal(e);
}
},
TOOL_CALLING {
public AgentState next(AgentEvent e) {
if (e == AgentEvent.TOOL_RESULT) return THINKING; // 回去继续推理
if (e == AgentEvent.TIMEOUT) return ERROR;
throw illegal(e);
}
},
WAITING_USER {
public AgentState next(AgentEvent e) {
if (e == AgentEvent.USER_MSG) return THINKING;
throw illegal(e);
}
},
RESPONDING {
public AgentState next(AgentEvent e) {
if (e == AgentEvent.RESPONSE_SENT) return IDLE;
throw illegal(e);
}
},
ERROR {
public AgentState next(AgentEvent e) {
if (e == AgentEvent.USER_MSG) return THINKING; // 重新开始
throw illegal(e);
}
};
public AgentState next(AgentEvent e) {
throw new IllegalStateException("非法事件: " + e);
}
private static IllegalStateException illegal(AgentEvent e) {
return new IllegalStateException("当前状态不支持事件: " + e);
}
}
使用时,状态流转自然又安全:
AgentState state = AgentState.IDLE; // 初始化状态为 IDLE
state = state.next(AgentEvent.USER_MSG); // → THINKING
state = state.next(AgentEvent.NEED_TOOL); // → TOOL_CALLING
state = state.next(AgentEvent.TOOL_RESULT); // → THINKING (二次推理)
state = state.next(AgentEvent.REASONING_DONE); // → RESPONDING
state = state.next(AgentEvent.RESPONSE_SENT); // → IDLE
这段代码虽然精简,却体现了状态机的核心:每个状态都精确地定义了自己的“出口”,任何不在规则内的路径都会立即报错。如果将来 Agent 需要支持“并行工具调用”或“中止任务”等新状态,只需新增枚举值并实现其转移规则,现有逻辑纹丝不动。
这种模式如今已经在许多 AI Agent 框架中以更复杂的形式出现,*比如 LangGraph 用状态图来编排 Agent 的决策流程。*但无论框架如何演变,其底层思想始终如一。
五、状态机的背后 —— 一种思维方式
状态机之所以优雅,是因为它把“在什么情况下该做什么”这个程序设计的核心问题,用结构化的方式表达了出来。
它不再是散落各处的 if-else 碎片,而是一个有明确边界、可验证、可推理的系统。你可以在设计阶段画出状态图,直观地检查有没有遗漏的状态或非法的转移路径 —— 很多 Bug 在编码之前就被消灭了。
这让我想到我在一开始学习时的感悟:代码之所以难维护,往往不是因为写得太少,而是因为想得太少。
在动手前先梳理业务中的状态和流转,画出状态图,这本身就是对领域理解的深化。
你会发现,无论是用 AI Agent 的决策引擎,还是 Kubernetes Pod 的生命周期管理,亦或是前端路由的守卫逻辑……凡是涉及“生命周期管理”的问题,都能看到状态机的影子。它不单是一种设计模式,更是一种分析复杂系统的思维。
总结
状态机不是什么高深的技术,它只是一个被时间反复验证的、好用的编程思想。
核心就一句话:把系统拆成有限个状态,定义清楚每个状态下响应什么事件、转移到什么状态。
用状态机写出的代码,路径清晰、非法转移被直接杜绝,新增状态时改动可控,不会牵一发而动全身。
同时,技术没有银弹。对于极简的、只有一两种状态切换的场景,if-else 已经足够。但当你的 Agent 越来越智能,行为越来越复杂时,状态机将是帮你守住“行为边界”的最可靠哨兵。
最后,你也可以思考一下:你正在开发的应用中,是否存在靠无数 flag 和嵌套 if-else 驱动的“混乱决策”? 或许你也可以试一试,把这些逻辑画成一张状态图,发现潜伏其中的逻辑黑洞。试着用状态机的思维重构它 —— 然后你会惊讶地发现,原来逻辑控制的决策可以变得如此清晰。
感谢你看到这里,如果喜欢咪的Coding的话可以点个关注支持一下吧!欢迎各位在评论区留言!
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)