现在几乎每个产品页面都画着类似的图:圆圈、箭头,再配一个渐变字体的“Agent”。而且基本上都是类似这样的同一个循环:
while not goal_completed():
state = load_state()
action = planner(state)
result = execute(action)
state = update_state(state, result) # 观察结果反馈到下一步
其实本质的核心只是一个控制循环,其中某个函数调用里放着语言模型,再用一个观察步骤把每次动作的结果反馈给下一次规划。这套结构是 ReAct 式推理的核心,也是 LangGraph、CrewAI、AutoGen,以及今天大多数所谓“Agentic AI”底层运行的引擎。
理解这个循环,对 Agentic AI 的认识就已经超过目前流传的 90% 营销图了。
一句话判断:工作流 vs. Agent
先把营销分类放到一边。真正管用的判断标准只有一句:
在工作流中,控制流图(control flow graph)在设计时就是固定的。在 Agent 中,控制流图由模型输出在运行时决定。
若在系统运行前就在代码中画好了 DAG(有向无环图,directed acyclic graph),那是确定性工作流;如果下一条边要等系统运行起来之后由模型生成,才属于 Agent。
这里有一个不能忽略的边界:模型无法凭空创造开发者从未暴露的工具或状态。哪怕自主性最高的 Agent,也只能在工程师预先定义的“元图(meta-graph)”里活动,其中包括可用工具集合、系统 Prompt 和允许执行的动作。动态之处在于走哪条路径、按什么顺序走。图本身并非无限,只是具体路径留到了运行时决定,而非提前画死。
企业生产系统里很少采用完全开放的动态图,原因很简单:测试困难,认证也困难。真正普及的是路由器(router)模式——主体仍是一张确定性图,只在特定分叉点放一个 LLM,从受限选项里挑 Path A、B 或 C。外观看起来很 Agentic,结构上仍是工作流只不过 switch 语句聪明了一些。
分类可以总结为三种形态:
- 纯粹形式的聊天机器人(chatbot)只有一个回合:输入、模型、输出,没有持久状态,也没有目标。现实中的生产级聊天机器人几乎早已不这么简单,哪怕基础客服机器人,也会跨轮次维护会话状态、对话历史和护栏。把它们称为零状态系统,适合作为教学上的简化,因为聊天机器人的“下一步”始终是“回复用户”,不会变成“从一组可能的动作里选一个”。
- 工作流(workflow)有固定的步骤序列,也可以包含条件分支。LLM 在步骤中填写的是内容;下一步执行什么,工程师已经事先决定。
- Agent 有一个规划器(planner),通常由 LLM 担任。它根据当前状态选择下一步动作,选择发生在前面那张元图之内,而不是由工程师提前逐项枚举。
今天大量以“Agent”名义交付的产品其实属于路由器:工作流保留主体结构,只在少数决策点让模型做狭窄、受约束的选择。这不是批评,因为多数场景下本来就该这么做。
状态机
把 Agent 想成一个有限状态机(finite-state machine)会更容易理解,只需改动一个地方:状态转移函数不再是确定性的,而带有概率。在经典 FSM 中,转移关系写死在代码里,状态 A 加输入 X 得到状态 B;到了 Agent,这段硬编码被一次模型调用替代,状态 A 加输入 X 后,模型猜测下一状态,并带着一定错误率。
形式上看,系统已经从一个清晰的有限状态机,移向更接近马尔可夫决策过程(Markov Decision Process)的结构,或者其部分可观测版本。动作可能产生概率性结果,状态转移函数则交给非确定性模型处理。
换成这个视角后,不确定性的位置会变得很清楚:它集中在状态转移函数,不在工具,也不在状态存储。优化目标也就很明确了。一个只有 6 个已知状态的工作流可以调试;一个状态空间实际上无界的 Agent 很难调试,因为 FSM 之所以可处理,靠的正是一组规模小、能够枚举的状态。
我们经常看到宣传材料说“完全自主”,这在工程上却是无界状态空间带来的调试噩梦。路由器模式正是在这里发挥作用:它重新收紧状态空间,让系统更像一个带智能转移函数的 FSM,而不是把模型放出去任意游走。
工具调用
工具调用(tool calling)在演示里通常表现为“模型会用计算器、会搜索 Web、会调用 API”。那只是容易的部分。生产环境真正棘手的问题是调用失败以后怎么办,返回畸形数据怎么办,或者返回值语法完全合法、语义却错了怎么办。
公开演示很少触及这些场景,因为大多数演示根本跑不了那么久。实际系统既要校验工具输入,也要对工具输出做 schema 校验;重试策略不能退化成拿同一组参数重新调用同一个工具。规划器还得识别两类完全不同的失败:“工具明确报错”和“工具吐出一份看起来正确的垃圾”。工具调用循环也必须设置硬上限,一个自信但判断错误的规划器,会以同一种错误方式反复调用同一工具,直到外部机制强制停止。
参数错了,但调用依然自信、完整、语法合法,这就是 Agentic AI 里的幻觉等价物:形式没有问题但内容是假的。
记忆
“记忆(memory)”至少指三种不同能力。很多 Agent 事故复盘,问题就出在把它们混成了一个概念。
工作记忆(working memory)就是上下文窗口,也就是当前 Prompt 里的全部内容。它昂贵、有限,而且往往还没真正装满,有效性就已经开始下降;这本身就是一种失效模式。
长期记忆(long-term memory)通常指 Agent 用来检索的向量存储或数据库。持久化是真实存在的,效果却几乎全压在检索质量上。检索做得差,和没有记忆没有区别。
学习(learning)则是机器学习意义上的行为变化:系统根据结果更新参数、移动权重。这种能力几乎没人直接放在实时生产环境中运行。
多数所谓“Agent 记忆”仍属于前两类,本质上只是更长的 Prompt,或者整理得更好的 Prompt。循环不会睡一觉就变聪明,它只是下次得到了提醒。
两者之间的距离正在缩短,但路径并非在线更新权重。DSPy 的技术以及一类记录失败、夜间运行离线评估、再把成功轨迹写回第二天 Prompt 的 Pipeline,都在尝试不碰模型权重的情况下连接检索与学习。可以称之为程序化 Prompt 优化(programmatic prompt optimization)。它和静态 RAG 查询不是一回事,也比多数“记忆”营销所描述的更接近学习,只是仍然不属于梯度下降。
评估与反馈循环
如果问任何一个 Agent 演示两个问题:谁来判定成功?一次失败会不会改变未来行为?第一个问题通常有人能答,第二个就少得多。
“谁来评判”大致只有三个答案。人工评审慢但准确,无法扩展;确定性检查速度快、可以扩展,却只适用于成功条件能写进代码的任务,例如测试是否通过、字段类型是否正确。LLM-as-judge 能扩展,也能处理模糊结果,可它同样继承评判模型自身的盲点。如果 judge 没有独立验证,相当于用更多幻觉搭了一个幻觉检测器。
更麻烦的是时间尺度。单次运行内部和多次运行之间,本来是两套不同反馈循环,却经常被混为一谈。Reflexion 一类架构以及其他自我纠正模式,会把 judge 步骤塞进单次循环:发现坏输出,把错误追加到上下文,让规划器重试,再允许流程继续。这种机制会直接改变 Agent 紧接着采取的动作,也确实能阻止它一路滑进“末日无限循环”。
跨运行就没这么成熟。比如昨天的失败评估很少自动改变今天的执行,只能留下一条日志或触发一个 Slack 告警,然后等人共在 3 天后修改 Prompt。这其实只是多了一层延迟的缺陷跟踪器,称不上反馈循环。单次会话内的纠错已经相当成熟;跨会话学习,目前几乎仍靠人工。
为什么自主性很难
“自主性很难”当然没错但只说这句话解释不了任何工程问题。
错误累积(error compounding)最容易被低估。假设计划中的每一步都有 95% 的可靠率,而任务需要 20 步,端到端成功率约为 0.95²⁰,也就是约 35.8%。计算只用了独立概率相乘,却足以改变对 Agent 可靠性的理解。
独立性假设还要继续往下,因为现实还会有两个失败的方向。失败经常相互依赖:第 3 步一个很小的幻觉,就可能污染传给第 4 步的状态,第 4 步随后基于错误输入推理,实际可靠率会从 95% 掉到低得多的水平,因为第 4 步此时处理的已经是受污染输入。真实结果也就比计算更差。反过来若步骤之间插入反思或验证节点,第 3 步的错误有机会在传播前被抓住,成功率的衰减曲线会被拉平。不过0.95²⁰ 仍是一个应该记住的数量级;系统里的真实曲线,取决于错误会不会级联,以及能不能及时捕获。
无界状态空间(unbounded state space)前面已经讲过。工作流的状态空间小而已知;Agent 的状态空间很大,即便仍被限制在元图中,也要到运行时再探索。
成本和延迟(cost and latency)同样直接。每个规划步骤都是一次需要计费、速度又慢的 API 调用。一个 20 步的 Agentic 循环对应 20 次往返调用,不是 1 次。经济上能不能成立,和模型能力够不够,是两件独立的事。
可调试性(debuggability)的问题更直观。工作流坏了,可以看 stack trace;Agent 坏了,只能读完整运行记录,再反推哪个 Token 级决策让执行轨迹偏离。概率分布上没有 breakpoint 可打。
常见失败模式
无限循环(the infinite loop of doom):
goal_completed()
始终不返回 true,Agent 持续调用工具、消耗 Token、累积上下文,直到预算上限、上下文窗口限制或手动退出,把它从外部停下来。
自信的幻觉者(the confident hallucinator):规划器调用根本不存在的工具,或者对真实工具传入看似合理、实际错误的参数。模型给出的调用格式完整、语法有效,本质上却是假的。
奖励作弊(the reward hack):Agent 在技术层面满足了
goal_completed()
,却绕开了它的真实意图。一个负责“修复失败测试”的 Agent 如果直接把 assertion 注释掉,就是教科书式案例。古德哈特定律(Goodhart's Law)落到 Agentic AI 上,表现为检查标准本身成了目标。
上下文腐化(context rot)通常到长链路后段才暴露。到了第 30 步,累积状态已经足够庞大,规划器开始漏掉真正需要的信息。问题不只在上下文窗口是否还有空间,更在注意力分配:Transformer 模型存在已有充分记录的“中间丢失(lost in the middle)”效应。长上下文里较早出现的信息,包括系统指令和护栏,会在后续 Token 持续增加时获得更少注意。规划器没有忘掉指令,只是不再像第一个回合那样给它相同权重。
什么情况下不应该构建 Agent
如果步骤事先已知能把流程图画出来,那就用工作流。让规划器在运行时决定一个早已知道答案的问题,只会增加开销。
分支很少而且可以枚举时,几个条件语句在成本和可靠性上都会胜过让模型反复猜同一小组结果。
需要审计级可靠性的场景,例如受监管领域或金融交易,也不适合把不可预期的模型决策放进核心路径。没人愿意向合规人员解释:“模型决定做了一件意料之外的事。”
延迟或成本如果已经是主要约束,多步规划循环相对固定 Pipeline 又慢又贵。模型再有能力,也改变不了 Agent 在这里并不合适。
还有一个更根本的判断:如果无法在代码中定义
goal_completed()
,也写不出可检查的 rubric,就没有评估方案。没有评估机制的生产 Agent,只是一个靠信念运行的循环。
中间可能还有一个情况:人工回路(human-in-the-loop)架构。当前最成功的生产级“Agent”并非完全自主,它们往往运行在异步循环里,直到遇到高风险状态转移;此时把状态序列化到数据库,暂停执行并请求人工审批,等审批结果经 webhook 返回后再继续。这不是权宜之计,很多产品本来就应该长成这样。状态空间受到明确约束,系统才更容易获得信任。
只有在路径确实无法提前确定时,Agent 的成本才值得承担,例如开放式研究、动态多工具任务,以及每次运行时环境形态都会变化的场景。其他地方,用工作流更合算;需要一点动态判断,就加路由器,需要控制风险,就加人工检查点。通常会更便宜、更快、更容易调试,对最终用户也大致同样有用。
总结
把循环搭出来只是容易的 20%。任何人都能写出文章开头那 6 行代码,再接一个 LLM 到
planner()
。真正困难的是剩下的 80%:把循环做得足够可靠,让企业敢把真实资金、真实客户或真实决策交给它,而这部分几乎没人认真讨论。
作者:Maria