Skip to content

第二章 Agent Loop——为什么 OpenClaw 选择这条路

核心问题:OpenClaw 如何成为一个会自己动手的智能系统?


第一节 ReAct 的思想与 Agent Loop 的实现

这一节只回答一个问题:OpenClaw 想解决的问题,为什么不是普通聊天、固定脚本或单次工具调用能完整解决的。

1.1 问题变了

普通聊天模型所擅长的是你问一个问题,它回答;你给一段材料,它总结;你贴一段代码,它解释。这个模式很强,但默认只处理一件事:把当前这句回好。

OpenClaw 想做的却不是这件事。它想做的是:接过一项任务,自己判断从哪里开始,需要时调用工具,再根据中间结果继续往下推。

这意味着它面对的,不再是“回答一个问题”,而是“完成一个任务”。

可以看一个最简单的对比:

场景真正要解决什么
“解释一下虚拟内存”组织出一段清楚的答案
“帮我把项目里的测试修到通过”根据不断变化的现场持续决定下一步

前者更像答题,后者更像干活。

而“干活”和“答题”最大的区别,就是现场会变。

  • 跑一次测试,会多一份新的报错;
  • 读完几份文件,对问题的理解会更新;
  • 改完代码再跑一轮,后面的判断可能完全不同;
  • 某条路走不通时,还得换方向。

所以只要目标从“回答”变成“推进”,系统就一定会遇到一个核心问题:怎样根据中途不断变化的反馈继续做决定。

1.2 旧办法不够

明白了问题变了,下一步就要看:前面的做法为什么不够。

先看第一条路:聊天模式

text
收到消息
→ 生成回复
→ 结束

它的优点是简单、快、适合问答;问题也很明显:答完就停。它不会自己继续推进,也不会维护任务进度。

再看第二条路:固定脚本

它的思路是先把路径写好,再按步骤执行。优点是稳、可控;问题是太依赖预设。只要中途情况和预期不一样,脚本就会变脆。

第三个必须单独讲的,是:Function Calling

这个词听起来技术味很重,其实意思不复杂:模型不只是“建议你调用某个工具”,而是能明确输出“我要调用哪个工具、参数是什么”。这让模型真正有了“动手”的能力。

但这里要说严谨一点:Function Calling 不是一条应该被淘汰的“旧办法”。恰恰相反,它是 Agent 系统里非常关键的一层能力。没有它,模型往往连“怎么真正动手”都说不清。

问题在于,Function Calling 主要解决的是当前这一步怎么动手,并没有自动解决更大的问题:

  • 这一步做完以后,还要不要继续?
  • 如果工具失败了,后面怎么办?
  • 前一步结果怎样变成后一步判断的依据?
  • 什么情况下才算任务完成?

所以更准确地说,这里不是三条互相替代的路线,而是三种常见做法的边界:

做法它最擅长什么它缺什么
聊天模式当前回复质量不能持续推进
固定脚本执行预设流程不能灵活改路
Function Calling当前动作选择不负责多步闭环

真正缺的不是“会不会说”或“会不会调工具”,而是:能不能接住结果,再决定下一步。

所以 OpenClaw 走向 Agent Loop,并不是用它去“替代” Function Calling,而是在 Function Calling 之上,再加一层持续推进任务的运行机制。

1.3 ReAct 和 Agent Loop

走到这里,ReAct 的思想就变得很关键,它的核心在于:不要先把所有事情想完再做,而是边观察、边判断、边行动,再根据结果继续判断。

它的基本逻辑可以压成这样:

text
先看现在发生了什么
→ 再判断下一步该做什么
→ 然后真的去做
→ 拿到结果后继续判断下一步

如果还是觉得抽象,可以想想人怎么修 bug:

  1. 先看报错;
  2. 猜一个可能原因;
  3. 打开相关文件检查;
  4. 发现猜错了;
  5. 换个方向继续查;
  6. 改完以后再跑一遍验证。

这就是一种很典型的 ReAct 过程。它不是“先想完十步再执行十步”,而是“走一步,看一步,改一步”。

但这里还缺一块:如果系统真的要按这种方式工作,它到底怎么把这一轮一轮跑起来?

这时候就要讲 Agent Loop 了。

按照 OpenClaw 官方文档的定义,Agent Loop 不是一个抽象说法,而是一次 Agent 的完整真实运行。它大致会经历这样一条路径:

text
接收请求
→ 组装这次运行要用的上下文
→ 调用模型判断下一步
→ 需要时执行工具
→ 持续把过程和结果流出来
→ 最后把这次执行保存下来

这个定义里最重要的是:Agent Loop 不是一句回复,也不是一次工具调用,而是系统把一件事从开始接住到最后收尾的整段过程。官方文档还强调,同一段任务现场里它是串行推进的,不会让多个执行同时乱写同一个现场。

这样一来,ReAct 和 Agent Loop 的关系就清楚了:

  • ReAct 是方法:告诉系统每一步该怎样观察、思考、行动。
  • Agent Loop 是机制:让系统能把这种方法一轮一轮真正跑起来。

可以把两者的关系理解成这样:

概念更像什么解决什么问题
ReAct做事方法每一步如何推进
Agent Loop运行机制系统怎样把多步执行串起来

这就是 OpenClaw 为什么最终会走到 Agent Loop。因为它面对的很多任务,本来就不适合一次想完、一次做完。更靠谱的方式通常都是:

  1. 先探一小步;
  2. 根据结果更新判断;
  3. 再决定下一步读什么、改什么、跑什么;
  4. 直到完成、卡住,或者需要人拍板。

所以 OpenClaw 选择 Agent Loop,不是因为“循环听起来高级”,而是因为它需要一个真正的运行框架,去承载 ReAct 这种方法。ReAct 负责告诉系统“这一步怎么推进”,Agent Loop 负责保证“这件事能一轮轮推进下去,而且中间状态不会乱”。

如果把第一节收成一句话,就是:问题一旦从“回答”变成“推进”,系统就不能停在聊天、脚本或单次工具调用,而会自然走向 ReAct,并最终落到 Agent Loop。

第二节 Agent Loop 改变了什么

这一节的核心问题在于:Agent Loop 是如何运行的,它让 OpenClaw 拥有了什么能力?

2.1 从消息到 run

对普通聊天系统来说,最自然的单位是“消息”。你发一句,它回一句,这一轮就结束。

但 Agent Loop 不一样。它真正管理的,不是一条消息,而是一整段执行过程

这里有三个词要先分清:

  • message:一条输入消息;
  • session:这一段长期协作共用的上下文和历史;
  • run:系统为了处理这次任务而启动的一次完整执行。

上一节已经说过,Agent Loop 不是一句回复,也不是一次工具调用,而是一整段完整运行。到了这里,关键就变成:系统怎样把这段运行当成一个真正的对象来管理。

所以系统开始关心的,已经不只是“用户刚刚说了什么”,而是:

  • 这次执行有没有被接收?
  • 它现在是在排队、运行,还是已经结束?
  • 它是正常结束、报错结束,还是超时中止?

这也是为什么 OpenClaw 会把 run 做成显式对象。官方文档里写得很清楚:

  • agent 是入口;
  • 调用 agent 后,会先返回 { runId, acceptedAt }
  • agent.wait 等的是这个 runId 的生命周期结束。

从源码看,这条链路也很清楚:

text
agent
→ agentCommand
→ runEmbeddedPiAgent
→ runEmbeddedAttempt

所以,在 OpenClaw 里,消息只是入口,run 才是系统真正盯住的对象。

2.2 从回复到现场

很多人第一次理解 Agent Loop 时,会把它简单理解成“多次调用模型”。这个说法不算错,但还是太薄了。更准确的说法是:OpenClaw 让每一步得到的新信息,都能进入下一步判断。

这里要先解释一个很常见的词:context。在 OpenClaw 里,context 的意思很直接:这一轮真正发送给模型的全部内容。

官方 Context 文档 明确说,context 里不仅有聊天历史,还包括:

  • OpenClaw 自己构建的 system prompt;
  • 当前 session 的历史消息;
  • 工具调用和工具结果;
  • 附件和外部读入内容;
  • 必要时的压缩摘要。

文档还特别强调:context 不是 memory。

这两个词很容易混,可以顺手分清:

概念更像什么它负责什么
context当前桌面上摊开的材料这一轮模型真正能看到的东西
memory磁盘上的长期记忆层一部分会在会话开始前带入,剩下的再按需召回

所以更稳的说法是:context 不等于 memory,但 memory 也不是和 context 完全断开。
memory 的“真相”在磁盘上,OpenClaw 会把其中最适合当前 run 的一部分先喂进 context,其余再通过工具和记忆机制补回来。

一旦把 context 理解成“当前桌面”,OpenClaw 的执行流程就很好懂了:

text
先把当前桌面搭好
→ 让模型看着这张桌面判断下一步
→ 需要时调用工具
→ 把工具结果再摆回桌面
→ 继续下一轮判断

这就是为什么 Agent Loop 的关键不是“模型调了几次”,而是“系统有没有把现场接起来”。

OpenClaw 官方 System Prompt 文档 还补上了另一块关键拼图:system prompt 是 OpenClaw 自己构建的,而且每个 run 都会重建一次

源码也能对上这条线:

text
createAgentSession(...)
→ applySystemPromptOverrideToSession(session, systemPromptText)
→ activeSession 开始这一轮 prompt

这件事的意义很大。它说明 OpenClaw 不是把用户原话直接扔给模型,而是会先把“这一轮工作现场”搭起来,再让模型开始判断。

这也解释了为什么长任务里,压缩上下文不是可有可无的小优化,而是 loop 能不能继续跑下去的一部分。官方给了 /compact,运行时也支持 auto-compaction。旧历史会被压成摘要,好让后面的 run 继续有空间工作。

所以 2.2 最重要的理解是:OpenClaw 不是靠“多转几圈”变成 Agent,而是靠“每一步都能读懂当前现场,并把新观察接回现场”变成 Agent。

2.3 从生成到控制

如果系统真的要靠 Agent Loop 跑长任务,只会循环还不够。它还必须把边界管好。否则系统很快就会出现三种问题:顺序乱了、过程黑了、停不下来了。

先看第一层:顺序边界

很多任务天然有先后关系。比如:

  • 先创建文件,再往里写内容;
  • 先跑测试,再根据报错决定改哪;
  • 先看到搜索结果,再决定下一步要不要继续查。

所以 OpenClaw 文档才会强调:同一个 session key 上的 run 要串行。源码里 runEmbeddedPiAgent() 也会先解析 sessionLaneglobalLane,再把真正执行包进 enqueueSession(() => enqueueGlobal(...))
也就是说,系统并不是只有“同 session 串行、不同 session 并行”这么简单,而是先保证单 session 不乱,再通过 global lane 和 maxConcurrent 收住整体并发。

这背后的直觉很简单:同一段任务现场要讲因果顺序,不同 session 才适合并行,但整体并发也要有总闸门。

再看第二层:可见边界

长任务如果一直黑着跑,用户根本不知道系统是在正常推进、卡住了,还是已经结束。所以 OpenClaw 不只关心最后一句答案,也关心过程能不能被看见

官方文档里,agent stream 把这个过程拆成了三类事件。这里可以把它们理解成三种不同的问题:

  • lifecycle:这次运行现在到哪一步了?
  • assistant:模型现在正在说什么?
  • tool:系统刚才调用了什么工具,结果怎样?

如果还是抽象,可以想象一个“修测试”的任务:

  1. 系统刚开始接手任务
    这属于 lifecycle
  2. 模型先告诉你“我先去跑一下测试看看报错”
    这属于 assistant
  3. 系统真的去运行测试命令
    这属于 tool
  4. 测试跑完,返回报错结果
    这也属于 tool
  5. 模型根据报错继续说“我已经定位到问题,接下来改这个文件”
    这又回到 assistant
  6. 整个任务结束
    这再回到 lifecycle

这样看就很清楚了:

  • lifecycle 负责告诉你“这次 run 开始了没有,结束了没有,是否报错”;
  • assistant 负责告诉你“模型当前在怎样理解和汇报这件事”;
  • tool 负责告诉你“系统刚才动了什么手,拿回了什么结果”。

这意味着系统不只关心“最后给什么结果”,也关心“中间发生了什么,要不要让用户看见”。

官方 Streaming 文档 又进一步把对外展示拆成了两层:

  • block streaming:把已经成形的内容分块发出来;
  • preview streaming:在 Telegram、Discord、Slack 这类平台里持续更新一条预览消息。

也就是说,OpenClaw 的目标已经不是“最后吐一句答案”,而是“把一段执行过程尽量可见地呈现出来”。

最后看第三层:停止边界

Agent 能持续推进,不等于它应该无限推进。Anthropic 在 Building effective agents 里强调过:每一步都要尽量拿到真实反馈,同时也要有明确的 stopping conditions。

OpenClaw 也在工程上把这件事做成了边界:

  • 任务完成,可以正常结束;
  • 运行报错,可以以 error 结束;
  • 运行超时,runEmbeddedPiAgent 会中止;
  • 用户或系统发出 abort,可以提前停止;
  • 遇到高风险动作或信息不足时,系统也可以停下来等确认。

说到这里,大家应该就能明白:OpenClaw 选了 Agent Loop 以后,变化的不是某个功能点,而是整套运行方式。系统开始管理 run,开始维护现场,也开始认真处理顺序、可见和停止。

第三节 我们该怎么用

上面已经讲清了 Agent Loop 怎样运行。接下来要回答的问题是:既然 OpenClaw 擅长推进多步任务,我们实际应该怎么用它。

3.1 先判断是不是复杂任务

很多人第一次接触 OpenClaw,会很自然地把它当成一个“可以定制的聊天 AI”来用。

这并不奇怪。OpenClaw 的定制门槛相对低,可能很多人第一次接触定制 Agent,就是从它开始的。问题是,如果你还没理解它真正强在哪里,就很容易把一些普通对话任务也交给它,比如:

  • 解释一个概念;
  • 翻译一段文字;
  • 润色一段邮件;
  • 总结一段材料。

这些事情它当然也能做,但做出来往往和普通聊天模型没有本质区别。于是很多人就会得出一个错误结论:OpenClaw 好像也没什么特别的。

问题不在 OpenClaw 没能力,而在于任务没用到它真正的能力。

前面我们已经讲过,OpenClaw 的独特之处不在于“更会回话”,而在于它能把一段任务接过来,自己推进下去。也就是说,它的优势主要出现在那些不是一轮回复就能解决的事情上。

所以,了解了 Agent Loop 之后,用户首先要学会的,不是某个命令怎么敲,而是先判断:这是不是一个适合交给 OpenClaw 的复杂任务。

这里说的“复杂”,不一定是字面上很难,也不一定非得特别大。更准确地说,是看它有没有下面这些特征:

  • 步数不固定;
  • 中间反馈会改变路线;
  • 需要工具、文件、命令或外部环境参与;
  • 目标能说清,但路线不该提前写死。

比如:

  • “解释一下虚拟内存”
    这更像问答。重点在答案本身,不在过程。
  • “帮我把项目里的测试修到通过”
    这更像任务。重点不在一句话怎么说,而在后面要不要读代码、跑测试、看报错、继续修改。

所以对初学者来说,一个很重要的转变就是:不要先问“OpenClaw 能不能做”,而要先问“这件事是不是只有靠多步推进,才能真正做好”。

如果答案是“不是”,那普通聊天模型往往已经够用。

如果答案是“是”,那 OpenClaw 的优势才会真正出来。

一句话说,只有先把任务选对,OpenClaw 的优势才会被用出来;如果任务本来就只是一次对话,它当然不会凭空创造出什么不同。

3.2 再学会交任务

如果你已经判断,这件事应该当成一个任务来交给 OpenClaw,那么下一步要学的,就是怎么把任务交清楚。

最不适合的方式,往往是“给它一张写死的步骤表”。

比起这样:

text
先做 A,再做 B,再做 C,最后输出 D。

通常更适合 Agent Loop 的,是这种更接近真实任务的交法:

text
帮我把这个仓库里的 failing test 修到通过。
优先用最小改动解决,不要顺手重构无关文件。
如果你判断需要改公共接口,先停下来问我。
最后给我一份改动说明,并告诉我测试是否真的跑过。

为什么这种写法更合适?因为它把系统真正需要的信息给全了:

  1. 目标:最终要做成什么;
  2. 边界:哪些能做,哪些不能做;
  3. 完成标准:做到什么程度算结束;
  4. 风险阈值:遇到什么情况必须先问人;
  5. 汇报方式:最后要怎样交代结果。

它没有把路径写死,这一点反而很关键。因为 OpenClaw 的价值就在于它能根据中间反馈调整路线。你如果把路线提前钉死,系统就只能机械照做;你如果把目标和边界说清,它才有空间把任务一步步推进下去。

这里还有一个特别容易被低估、但实际非常重要的点:上下文预算是真成本。

官方 Context 文档 明确写着,一次 run 的 context 里会包括 system prompt、历史、工具调用和结果、附件,甚至工具 schema 本身;官方 System Prompt 文档 也说明,像 AGENTS.mdSOUL.mdTOOLS.mdIDENTITY.mdUSER.mdMEMORY.md 这类工作区文件会作为 Project Context 注入,而 BOOTSTRAP.md、daily memory 这类内容则只会在特定条件下出现,不能把它们都理解成“永远常驻全文”。

翻成人话就是:你给的任务描述、常驻工作区文件、之前的对话、工具输出,都会一起竞争同一个上下文窗口;而一些生命周期文件和记忆召回则只会在特定时机加入。

这会直接带来两个使用上的后果:

  • 真正长期有效的约束,应该尽量写得清楚、稳定,而不是散落在大量闲聊里;
  • 长任务跑久了,要开始有意识地管理上下文,而不是默认“模型自己会一直记着”。

OpenClaw 官方已经给了这套管理入口:

  • /status:看当前窗口压力和会话设置;
  • /context list:看当前注入了什么;
  • /context detail:看更细的拆分;
  • /compact:把旧历史压成摘要,给后面的 run 腾空间。

所以从使用角度看,当你把事情当任务交给 OpenClaw 时,就不只是“提个需求”这么简单了,你还要开始像管理一段执行一样管理上下文

3.3 最后学会协作

当一件事真的进入多步执行以后,用户和系统的关系也会跟着变化。

在普通聊天里,用户更像“提问的人”;在任务执行里,用户更像“协作的人”。这不是一句空话,而是会直接落到几个很具体的习惯上。

第一,要学会看过程

长任务里出现检查、试错、回退、再尝试,都是正常现象。它不是在“磨蹭”,而是在根据新的观察修正方向。

第二,要尽早补关键信息

如果你突然想起下面这类限制,不要等它全做完再说:

  • 不要改公共接口;
  • 先只读,不要直接写;
  • 这个目录先不要碰;
  • 遇到删文件、发消息、危险命令先问我。

这些限制越早说,loop 走歪的概率就越低。

第三,要及时纠偏

Agent 有自我修正能力,但这不等于它一定会自己拐回来。发现方向明显不对时,更有效的做法通常不是沉默等待,而是直接重设边界,比如:

text
先停一下,不要继续这个方向。
先告诉我你为什么会这样判断。

或者:

text
不要继续修改。
先只做检查,把当前结论和依据告诉我。

第四,要把“确认”当成协作的一部分,而不是系统失灵

OpenClaw 的工程边界本来就承认:有些动作应该停下来等人拍板,尤其是高风险、不可逆、影响面大的动作。能在这些地方停下来问,恰恰说明系统边界是清楚的。

所以如果把这一节压成几条最实用的原则,就是:

  • 不是所有事情都要当任务来交;
  • 提任务时,目标、边界和完成标准比死步骤更重要;
  • 长任务要看过程,不要只盯最终一句;
  • 发现方向不对,要尽早补信息和纠偏;
  • 高风险节点上的确认,不是打断,而是协作的一部分。

如果把第三节收成一句话,就是:OpenClaw 选了 Agent Loop,意味着我们使用它时,并不是在等待答案,而是与它一起完成任务。


本章小结

这一章其实就讲明白了一件事:OpenClaw 为什么不是一个“更会聊天”的工具,而是一个能推进任务的 Agent。

因为它要解决的,不是“把一句话答好”,而是“把一件事做下去”。光会聊天不够,光会按脚本跑也不够,只会调一次工具也不够。要想把任务一步一步往前推,系统就得能看结果、改判断、再继续做。

这就是 ReAct 和 Agent Loop 的意义。ReAct 讲的是怎么一步一步推进,Agent Loop 讲的是怎么把这套方法真正跑起来。

所以到了 OpenClaw 这里,系统处理的就不只是消息了,而是一整段执行过程。我们用它的时候,也不能只把它当聊天框,而要先判断任务适不适合,再把任务交清楚,然后在过程中和它协作。

一句话总结就是:OpenClaw 的价值,不在于多会说,而在于能不能把任务接过来,真的往前推。

下一章: 第三章 提示词系统