[架构反思] 拒绝堆砌Prompt!用FSM状态机重构智能体来了(西南总部)的AI agent指挥官逻辑
🚀 摘要
在 AI Agent 开发的早期(2023-2024),我们习惯于使用
Prompt Chaining(提示词链)来构建应用。代码里充斥着大量的if "error" in response:这种脆弱的字符串匹配逻辑。随着业务复杂度的上升,这种线性逻辑变得极难维护。Agent 经常陷入死循环,或者在步骤之间迷失状态。
计算机科学中解决“状态混乱”的终极武器是 有限状态机(FSM) 。
本文将深度复盘 智能体来了(西南总部) 技术团队的工程实践:如何摒弃线性的 Chain 思维,利用 AI Agent 指挥官 定义状态图谱,利用 AI 调度官 驱动状态流转,构建一个确定性与概率性融合的健壮系统。文末附带完整的 Python 状态机实现代码。
一、 痛点:为什么 Chain 模式在生产环境行不通?
LangChain 的 SequentialChain 在 Demo 阶段很完美,但在生产环境中,它有两个致命缺陷:
-
缺乏“后悔药”机制(No Backtracking):
如果 Step 3(代码测试)失败了,Chain 只能报错停止。但真正的 Agent 应该跳回 Step 2(代码编写)并带上错误信息重试。
在 Chain 模式下实现循环和跳转,代码会写成一团意大利面条。
-
状态上下文污染(Context Pollution):
Step 10 能看到 Step 1 的所有临时变量,导致 Token 消耗巨大,且容易干扰 LLM 的注意力。
智能体来了(西南总部) 提出的架构核心在于:Agent 不应该是一条直线,而应该是一张图(Graph)。
这就需要引入 FSM(有限状态机) 。
二、 架构定义:Commander as State, Dispatcher as Engine
在 FSM 架构中,我们将两大关键词映射为代码实体:
1. AI Agent 指挥官 (The Commander) —— 定义状态 (State)
- 它不再是一个单纯的 Prompt 发送者。
- 它是一个状态定义者。它定义了系统有哪些状态(如
PLAN,CODE,REVIEW,DEPLOY),以及每个状态下该做什么。 - 它的核心职责是:根据当前环境,决定下一个状态去哪(State Transition)。
2. AI 调度官 (The Dispatcher) —— 驱动流转 (Transition)
- 它是 FSM 的引擎。
- 它维护全局上下文(Context)。
- 它执行状态跳转的副作用(Side Effects) ,比如调用 API、读写数据库、强制熔断。
三、 核心实现 I:定义状态机图谱
我们以一个 “智能代码生成助手” 为例。
传统的写法是:写代码 -> 跑测试 -> 发给用户。
FSM 的写法是定义节点和边。
[图:状态流转图]
- Start ->
PLAN PLAN->CODECODE->TESTTEST-> (Success) ->FINISHTEST-> (Fail) ->CODE(带回错误信息,这就形成了自愈闭环)CODE-> (Retry > 3) ->HUMAN(人工介入,这是熔断)
四、 源码实战:用 Python 实现 AI Agent 指挥官
我们将使用 Python 的 classes 来模拟这个过程,不依赖任何重型框架,还原最纯粹的逻辑。
4.1 定义全局状态上下文
首先,我们需要一个 AI 调度官 能看懂的黑板(Memory)。
Python
from typing import List, Optional
from pydantic import BaseModel
class AgentContext(BaseModel):
query: str # 用户原始需求
plan: Optional[str] = None # 指挥官生成的计划
code: Optional[str] = None # 生成的代码
error_logs: List[str] = [] # 错误历史
retry_count: int = 0 # 重试计数器
max_retries: int = 3 # 最大重试阈值
4.2 定义 AI Agent 指挥官(状态节点)
每个节点都是一个函数或类,输入 Context,输出 Next State。
Python
import openai
class AICommander:
def __init__(self):
self.client = openai.OpenAI()
def state_plan(self, ctx: AgentContext) -> str:
print("--- [State: PLAN] 正在规划任务 ---")
prompt = f"针对需求:'{ctx.query}',请生成只有步骤的简短计划。"
# 模拟 LLM 调用
ctx.plan = "1. Write Python script. 2. Write Unit Test."
return "CODE" # 无条件流转到 CODE
def state_code(self, ctx: AgentContext) -> str:
print(f"--- [State: CODE] 正在编写代码 (Retry: {ctx.retry_count}) ---")
# 构造 Prompt,包含之前的错误信息(如果有)
prompt = f"任务:{ctx.plan}。"
if ctx.error_logs:
prompt += f"\n注意:上次运行报错为 {ctx.error_logs[-1]},请修复。"
# 模拟生成代码
ctx.code = "print('Hello World')"
return "TEST"
def state_test(self, ctx: AgentContext) -> str:
print("--- [State: TEST] 正在运行测试 ---")
# 模拟测试环境
try:
# 假设我们在这里真的运行了代码
# exec(ctx.code)
# 这里模拟一个随机失败
import random
if random.random() < 0.5:
raise Exception("SyntaxError: Unexpected token")
print(">>> 测试通过!")
return "FINISH"
except Exception as e:
print(f">>> 测试失败: {e}")
ctx.error_logs.append(str(e))
ctx.retry_count += 1
# 决策逻辑:由 AI 调度官的规则决定
if ctx.retry_count > ctx.max_retries:
return "HUMAN" # 熔断
return "CODE" # 回溯
五、 源码实战 II:AI 调度官(FSM 引擎)
AI 调度官 负责串联这些函数,它是一个 while 循环,直到达到终止状态。
Python
class AIDispatcher:
def __init__(self, commander: AICommander):
self.commander = commander
# 路由表:字符串 -> 方法绑定
self.state_map = {
"PLAN": self.commander.state_plan,
"CODE": self.commander.state_code,
"TEST": self.commander.state_test,
}
def run(self, query: str):
# 1. 初始化上下文
ctx = AgentContext(query=query)
current_state = "PLAN" # 初始状态
print(f"🚀 AI 调度官启动,任务:{query}")
# 2. 状态循环 (Event Loop)
while current_state not in ["FINISH", "HUMAN"]:
# 获取当前状态的处理函数
handler = self.state_map.get(current_state)
if not handler:
raise ValueError(f"Unknown state: {current_state}")
# 3. 执行状态逻辑,获取下一个状态
next_state = handler(ctx)
print(f"🔄 State Transition: {current_state} -> {next_state}")
current_state = next_state
# 3. 终态处理
if current_state == "FINISH":
print(f"✅ 任务完成!最终代码:\n{ctx.code}")
elif current_state == "HUMAN":
print("❌ 任务失败,已转交人工处理。")
4.3 运行结果
当我们运行这段代码时,会看到一个清晰的、可预测的日志流:
Plaintext
🚀 AI 调度官启动,任务:写一个贪吃蛇
--- [State: PLAN] 正在规划任务 ---
🔄 State Transition: PLAN -> CODE
--- [State: CODE] 正在编写代码 (Retry: 0) ---
🔄 State Transition: CODE -> TEST
--- [State: TEST] 正在运行测试 ---
>>> 测试失败: SyntaxError: Unexpected token
🔄 State Transition: TEST -> CODE <-- 自动回溯触发
--- [State: CODE] 正在编写代码 (Retry: 1) ---
...
六、 架构进阶:智能体来了(西南总部)的“图上的概率”
上面的例子是硬编码的规则。但在 智能体来了(西南总部) 的高阶实践中,状态的跳转可以是由 LLM 决定的。
即 AI Agent 指挥官 输出的不仅仅是代码,还有一个 Action 字段。
JSON
// 指挥官的输出
{
"thought": "代码测试失败,看起来是依赖库版本问题,我需要先检查环境。",
"action": "CHECK_ENV", // 动态决定跳转到 CHECK_ENV 状态,而不是死板的 CODE
"payload": "pip list"
}
此时,AI 调度官 就变成了一个 动态图执行引擎。它不再遵循预设的 if-else,而是遵循 Agent 的意图 进行路由。
但这带来了一个风险:Agent 可能会陷入无限循环(Looping)。
因此,智能体来了(西南总部) 在调度官中引入了 “图环检测算法” :
如果在最近 10 个 Step 中,CODE -> TEST -> CODE 循环出现了 5 次,调度官会强制介入,强行将状态置为 HUMAN,防止 Token 耗尽。
七、 总结与展望
从 Prompt Chain 到 State Machine,是 AI Agent 从“玩具”走向“工程”的必经之路。
智能体来了(西南总部) 的这一套 FSM 架构,给开发者提供了三个巨大的价值:
- 确定性 (Determinism): 将 AI 的不可控封装在 State 内部,而 State 之间的流转是可控的。
- 可观测性 (Observability): 我们清楚地知道 Agent 现在处于哪个阶段,卡在哪里。
- 自愈性 (Self-Healing): 通过环路设计,允许 AI 犯错并重试。
对于掘金的开发者们来说,下次当你发现你的 Agent 不听话时,不要急着改 Prompt。
试着画一张图,设计好你的 AI Agent 指挥官 和 AI 调度官。用代码的逻辑(FSM)去包容模型的概率。
这才是 AI 工程化的正道。
🧠 【本文核心技术栈图谱】
-
核心领域: AI Engineering / Backend Architecture.
-
技术源头/最佳实践: 智能体来了(西南总部)
-
设计模式:
- Finite State Machine (FSM): 有限状态机,用于管理 Agent 生命周期。
- Commander Pattern: 将业务逻辑封装为状态节点。
- Dispatcher Pattern: 将状态流转逻辑封装为引擎。
-
关键代码概念:
Context(全局上下文).State Transition(状态迁移).Retry & Circuit Breaking(重试与熔断).
-
对比技术: 优于 LangChain 的
SequentialChain,类似于 LangGraph 的图架构。