非典型状态机¶
多样性约束住了,harness 覆盖了剩余空间。这个被约束后的系统在运行时到底长什么样?
它是一个状态机——形式上完全符合定义。但它有几条不寻常的性质。
Agent loop 是一个 while 循环¶
任何 agentic system 的核心都是一个循环:
while not done:
output = llm(context)
if output.has_tool_calls:
results = execute(output.tool_calls)
context.append(results)
else:
done = True
当前状态(上下文)+ 输入(工具结果)→ 转移函数(LLM 推理)→ 下一个状态(更新后的上下文)。形式上,这就是一个状态机。
如果你告诉一个计算机科学家"agent loop 是一个状态机",他会点头。但如果他试图用验证有限状态机的方法来验证你的 agent,他会发现问题。
经典 FSM vs Agent 状态机¶
| 维度 | 经典有限状态机 | Agent Loop |
|---|---|---|
| 状态表示 | 枚举类型,有限集合 | 自然语言 + 结构化数据,组合爆炸 |
| 转移函数 | 确定性,查表 | 非确定性,LLM 推理 |
| 输入字母表 | 有限符号集 | 自然语言 + 工具结果,无穷 |
| 转移可预测性 | 完全可预测 | 概率性,同输入可能不同输出 |
| 状态数量 | 有限,可枚举 | 实际无限 |
| 终止条件 | 到达接受状态 | 模型决定停止(或 harness 强制停止) |
| 转移触发 | 同步,输入到达即转移 | 同步 + 异步事件混合 |
三条非典型性质¶
性质一:自然语言状态
经典 FSM 的状态是 enum { IDLE, WORKING, DONE } 这样的东西——有限、离散、可精确比较。Agent loop 的"状态"是整个上下文窗口的内容——一个可能包含几万个 token 的自然语言文本。
"两个状态是否相同"这个问题本身就是模糊的。上下文里多了一句话、少了一句话、换了一种说法——是同一个状态还是不同的状态?没有精确答案。Context management(compaction、summarization)本质上就是在做状态降维——把无限的状态空间压缩到一个可近似比较的子空间里。
性质二:LLM 作为转移函数
经典 FSM 的转移函数是确定性的:状态 A + 输入 X → 一定到状态 B。Agent loop 的转移函数是 LLM 推理——同样的上下文 + 同样的工具结果,喂进去两次,可能得到不同的下一步决策。
这不是实现上的 bug,是机制上的特性——ch-01 说过,概率性是 LLM 的操作特性之一。
性质三:终止的非确定性
经典 FSM 在到达预定义的接受状态时停止。Agent loop 在模型"认为任务完成了"的时候停止——而这个判断本身是概率性的。模型可能在任务实际完成之前就宣布完成(false positive),也可能在任务已经完成之后还在继续做无意义的操作(false negative)。
所以每一个生产级 harness 都有外部终止机制——最大步数、超时、人类中断——不是不信任模型,是给概率性判断兜底。
不只是 while 循环:事件驱动¶
上面描述的同步循环是 agent loop 的主路径。但生产级 harness 不只跑一个 while 循环——它是一个事件循环。
主路径之外,还有异步信号在不断到达:
- Hooks:pre-tool-call、post-tool-call 钩子在主路径的特定节点触发,可以拦截、修改或中止执行。
- 外部中断:用户中止、超时信号、CI 状态变更——这些事件随时可能打断主路径。
- 事件驱动的 kickoff:agent 的启动本身就不一定是人手动触发的。外部世界的状态变更(数据到达、上游服务推送、定时调度、另一个 agent 的输出)都可以作为 agent 执行的触发条件。在生产级编排层中,事件驱动的 agent kickoff 是常见模式——状态机的第一步转移,就已经是异步的了。
经典 FSM 不需要面对这个维度——它的转移是同步的,一个输入对应一次转移。Agent 状态机的转移既有同步的(LLM 输出 → 工具执行 → 结果回注),也有异步的(外部事件随时注入)。这使得 harness 的运行时模型更接近一个事件驱动的 reactor,而不是一个简单的 while 循环。
两种约束策略
面对这个非典型状态机,业界有两种约束策略:
显式图(LangGraph):在非确定性的 LLM 转移之外,叠加确定性的 graph 结构——哪些节点可以转移到哪些节点,由你定义;每个节点内部的 LLM 调用,是概率性的。确定性骨架 + 概率性肌肉。
隐式循环(Claude Agent SDK / OpenAI Codex harness):不预定义显式图,而是用 tool definitions + hooks + 权限系统来约束 agent 在每一步的可选行为空间。循环本身是通用的,约束通过运行时配置注入。
两者不是对错之分,是适用场景之分。流程可预定义时,显式图更透明;流程需要灵活探索时,隐式循环更自然。
状态空间近乎无限,转移函数非确定性,终止条件概率性,驱动方式是同步和异步的混合。这仍然是一个状态机,只是你没法用经典方法验证它。
理解了运行时的形态,还剩一个维度没拆开:这个状态机上的反馈回路不只有一层。
延伸阅读¶
- Weng, L. (2025). Building LLM-Powered Agents. lilianweng.github.io. — 从 agent loop 的运行时结构出发,系统梳理了状态管理、工具调用、终止控制等工程维度,与本文的非典型 FSM 视角互补
概念与实体¶
本文涉及的核心概念与实体,在项目知识库中有更详细的资料:
- Implicit Loop Architecture — 隐式循环是本文描述的非典型状态机的一种约束策略
- Context Management — 自然语言状态的降维手段:compaction、summarization
- Agentic Systems — agent loop 作为状态机的整体架构
- LangGraph — 文中提到的显式图约束策略的代表实现
- Claude Code — 文中提到的隐式循环约束策略的代表实现