第二章 Agent Loop——为什么 OpenClaw 选择这条路
核心问题:OpenClaw 如何成为一个会自己动手的智能系统?
第一节 ReAct 的思想与 Agent Loop 的实现
这一节只回答一个问题:OpenClaw 想解决的问题,为什么不是普通聊天、固定脚本或单次工具调用能完整解决的。
1.1 问题变了
普通聊天模型所擅长的是你问一个问题,它回答;你给一段材料,它总结;你贴一段代码,它解释。这个模式很强,但默认只处理一件事:把当前这句回好。
OpenClaw 想做的却不是这件事。它想做的是:接过一项任务,自己判断从哪里开始,需要时调用工具,再根据中间结果继续往下推。
这意味着它面对的,不再是“回答一个问题”,而是“完成一个任务”。
可以看一个最简单的对比:
| 场景 | 真正要解决什么 |
|---|---|
| “解释一下虚拟内存” | 组织出一段清楚的答案 |
| “帮我把项目里的测试修到通过” | 根据不断变化的现场持续决定下一步 |
前者更像答题,后者更像干活。
而“干活”和“答题”最大的区别,就是现场会变。
- 跑一次测试,会多一份新的报错;
- 读完几份文件,对问题的理解会更新;
- 改完代码再跑一轮,后面的判断可能完全不同;
- 某条路走不通时,还得换方向。
所以只要目标从“回答”变成“推进”,系统就一定会遇到一个核心问题:怎样根据中途不断变化的反馈继续做决定。
1.2 旧办法不够
明白了问题变了,下一步就要看:前面的做法为什么不够。
先看第一条路:聊天模式。
收到消息
→ 生成回复
→ 结束它的优点是简单、快、适合问答;问题也很明显:答完就停。它不会自己继续推进,也不会维护任务进度。
再看第二条路:固定脚本。
它的思路是先把路径写好,再按步骤执行。优点是稳、可控;问题是太依赖预设。只要中途情况和预期不一样,脚本就会变脆。
第三个必须单独讲的,是:Function Calling。
这个词听起来技术味很重,其实意思不复杂:模型不只是“建议你调用某个工具”,而是能明确输出“我要调用哪个工具、参数是什么”。这让模型真正有了“动手”的能力。
但这里要说严谨一点:Function Calling 不是一条应该被淘汰的“旧办法”。恰恰相反,它是 Agent 系统里非常关键的一层能力。没有它,模型往往连“怎么真正动手”都说不清。
问题在于,Function Calling 主要解决的是当前这一步怎么动手,并没有自动解决更大的问题:
- 这一步做完以后,还要不要继续?
- 如果工具失败了,后面怎么办?
- 前一步结果怎样变成后一步判断的依据?
- 什么情况下才算任务完成?
所以更准确地说,这里不是三条互相替代的路线,而是三种常见做法的边界:
| 做法 | 它最擅长什么 | 它缺什么 |
|---|---|---|
| 聊天模式 | 当前回复质量 | 不能持续推进 |
| 固定脚本 | 执行预设流程 | 不能灵活改路 |
| Function Calling | 当前动作选择 | 不负责多步闭环 |
真正缺的不是“会不会说”或“会不会调工具”,而是:能不能接住结果,再决定下一步。
所以 OpenClaw 走向 Agent Loop,并不是用它去“替代” Function Calling,而是在 Function Calling 之上,再加一层持续推进任务的运行机制。
1.3 ReAct 和 Agent Loop
走到这里,ReAct 的思想就变得很关键,它的核心在于:不要先把所有事情想完再做,而是边观察、边判断、边行动,再根据结果继续判断。
它的基本逻辑可以压成这样:
先看现在发生了什么
→ 再判断下一步该做什么
→ 然后真的去做
→ 拿到结果后继续判断下一步如果还是觉得抽象,可以想想人怎么修 bug:
- 先看报错;
- 猜一个可能原因;
- 打开相关文件检查;
- 发现猜错了;
- 换个方向继续查;
- 改完以后再跑一遍验证。
这就是一种很典型的 ReAct 过程。它不是“先想完十步再执行十步”,而是“走一步,看一步,改一步”。
但这里还缺一块:如果系统真的要按这种方式工作,它到底怎么把这一轮一轮跑起来?
这时候就要讲 Agent Loop 了。
按照 OpenClaw 官方文档的定义,Agent Loop 不是一个抽象说法,而是一次 Agent 的完整真实运行。它大致会经历这样一条路径:
接收请求
→ 组装这次运行要用的上下文
→ 调用模型判断下一步
→ 需要时执行工具
→ 持续把过程和结果流出来
→ 最后把这次执行保存下来这个定义里最重要的是:Agent Loop 不是一句回复,也不是一次工具调用,而是系统把一件事从开始接住到最后收尾的整段过程。官方文档还强调,同一段任务现场里它是串行推进的,不会让多个执行同时乱写同一个现场。
这样一来,ReAct 和 Agent Loop 的关系就清楚了:
- ReAct 是方法:告诉系统每一步该怎样观察、思考、行动。
- Agent Loop 是机制:让系统能把这种方法一轮一轮真正跑起来。
可以把两者的关系理解成这样:
| 概念 | 更像什么 | 解决什么问题 |
|---|---|---|
| ReAct | 做事方法 | 每一步如何推进 |
| Agent Loop | 运行机制 | 系统怎样把多步执行串起来 |
这就是 OpenClaw 为什么最终会走到 Agent Loop。因为它面对的很多任务,本来就不适合一次想完、一次做完。更靠谱的方式通常都是:
- 先探一小步;
- 根据结果更新判断;
- 再决定下一步读什么、改什么、跑什么;
- 直到完成、卡住,或者需要人拍板。
所以 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的生命周期结束。
从源码看,这条链路也很清楚:
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 的执行流程就很好懂了:
先把当前桌面搭好
→ 让模型看着这张桌面判断下一步
→ 需要时调用工具
→ 把工具结果再摆回桌面
→ 继续下一轮判断这就是为什么 Agent Loop 的关键不是“模型调了几次”,而是“系统有没有把现场接起来”。
OpenClaw 官方 System Prompt 文档 还补上了另一块关键拼图:system prompt 是 OpenClaw 自己构建的,而且每个 run 都会重建一次。
源码也能对上这条线:
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() 也会先解析 sessionLane 和 globalLane,再把真正执行包进 enqueueSession(() => enqueueGlobal(...))。
也就是说,系统并不是只有“同 session 串行、不同 session 并行”这么简单,而是先保证单 session 不乱,再通过 global lane 和 maxConcurrent 收住整体并发。
这背后的直觉很简单:同一段任务现场要讲因果顺序,不同 session 才适合并行,但整体并发也要有总闸门。
再看第二层:可见边界。
长任务如果一直黑着跑,用户根本不知道系统是在正常推进、卡住了,还是已经结束。所以 OpenClaw 不只关心最后一句答案,也关心过程能不能被看见。
官方文档里,agent stream 把这个过程拆成了三类事件。这里可以把它们理解成三种不同的问题:
lifecycle:这次运行现在到哪一步了?assistant:模型现在正在说什么?tool:系统刚才调用了什么工具,结果怎样?
如果还是抽象,可以想象一个“修测试”的任务:
- 系统刚开始接手任务
这属于lifecycle - 模型先告诉你“我先去跑一下测试看看报错”
这属于assistant - 系统真的去运行测试命令
这属于tool - 测试跑完,返回报错结果
这也属于tool - 模型根据报错继续说“我已经定位到问题,接下来改这个文件”
这又回到assistant - 整个任务结束
这再回到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,那么下一步要学的,就是怎么把任务交清楚。
最不适合的方式,往往是“给它一张写死的步骤表”。
比起这样:
先做 A,再做 B,再做 C,最后输出 D。通常更适合 Agent Loop 的,是这种更接近真实任务的交法:
帮我把这个仓库里的 failing test 修到通过。
优先用最小改动解决,不要顺手重构无关文件。
如果你判断需要改公共接口,先停下来问我。
最后给我一份改动说明,并告诉我测试是否真的跑过。为什么这种写法更合适?因为它把系统真正需要的信息给全了:
- 目标:最终要做成什么;
- 边界:哪些能做,哪些不能做;
- 完成标准:做到什么程度算结束;
- 风险阈值:遇到什么情况必须先问人;
- 汇报方式:最后要怎样交代结果。
它没有把路径写死,这一点反而很关键。因为 OpenClaw 的价值就在于它能根据中间反馈调整路线。你如果把路线提前钉死,系统就只能机械照做;你如果把目标和边界说清,它才有空间把任务一步步推进下去。
这里还有一个特别容易被低估、但实际非常重要的点:上下文预算是真成本。
官方 Context 文档 明确写着,一次 run 的 context 里会包括 system prompt、历史、工具调用和结果、附件,甚至工具 schema 本身;官方 System Prompt 文档 也说明,像 AGENTS.md、SOUL.md、TOOLS.md、IDENTITY.md、USER.md、MEMORY.md 这类工作区文件会作为 Project Context 注入,而 BOOTSTRAP.md、daily memory 这类内容则只会在特定条件下出现,不能把它们都理解成“永远常驻全文”。
翻成人话就是:你给的任务描述、常驻工作区文件、之前的对话、工具输出,都会一起竞争同一个上下文窗口;而一些生命周期文件和记忆召回则只会在特定时机加入。
这会直接带来两个使用上的后果:
- 真正长期有效的约束,应该尽量写得清楚、稳定,而不是散落在大量闲聊里;
- 长任务跑久了,要开始有意识地管理上下文,而不是默认“模型自己会一直记着”。
OpenClaw 官方已经给了这套管理入口:
/status:看当前窗口压力和会话设置;/context list:看当前注入了什么;/context detail:看更细的拆分;/compact:把旧历史压成摘要,给后面的 run 腾空间。
所以从使用角度看,当你把事情当任务交给 OpenClaw 时,就不只是“提个需求”这么简单了,你还要开始像管理一段执行一样管理上下文。
3.3 最后学会协作
当一件事真的进入多步执行以后,用户和系统的关系也会跟着变化。
在普通聊天里,用户更像“提问的人”;在任务执行里,用户更像“协作的人”。这不是一句空话,而是会直接落到几个很具体的习惯上。
第一,要学会看过程。
长任务里出现检查、试错、回退、再尝试,都是正常现象。它不是在“磨蹭”,而是在根据新的观察修正方向。
第二,要尽早补关键信息。
如果你突然想起下面这类限制,不要等它全做完再说:
- 不要改公共接口;
- 先只读,不要直接写;
- 这个目录先不要碰;
- 遇到删文件、发消息、危险命令先问我。
这些限制越早说,loop 走歪的概率就越低。
第三,要及时纠偏。
Agent 有自我修正能力,但这不等于它一定会自己拐回来。发现方向明显不对时,更有效的做法通常不是沉默等待,而是直接重设边界,比如:
先停一下,不要继续这个方向。
先告诉我你为什么会这样判断。或者:
不要继续修改。
先只做检查,把当前结论和依据告诉我。第四,要把“确认”当成协作的一部分,而不是系统失灵。
OpenClaw 的工程边界本来就承认:有些动作应该停下来等人拍板,尤其是高风险、不可逆、影响面大的动作。能在这些地方停下来问,恰恰说明系统边界是清楚的。
所以如果把这一节压成几条最实用的原则,就是:
- 不是所有事情都要当任务来交;
- 提任务时,目标、边界和完成标准比死步骤更重要;
- 长任务要看过程,不要只盯最终一句;
- 发现方向不对,要尽早补信息和纠偏;
- 高风险节点上的确认,不是打断,而是协作的一部分。
如果把第三节收成一句话,就是:OpenClaw 选了 Agent Loop,意味着我们使用它时,并不是在等待答案,而是与它一起完成任务。
本章小结
这一章其实就讲明白了一件事:OpenClaw 为什么不是一个“更会聊天”的工具,而是一个能推进任务的 Agent。
因为它要解决的,不是“把一句话答好”,而是“把一件事做下去”。光会聊天不够,光会按脚本跑也不够,只会调一次工具也不够。要想把任务一步一步往前推,系统就得能看结果、改判断、再继续做。
这就是 ReAct 和 Agent Loop 的意义。ReAct 讲的是怎么一步一步推进,Agent Loop 讲的是怎么把这套方法真正跑起来。
所以到了 OpenClaw 这里,系统处理的就不只是消息了,而是一整段执行过程。我们用它的时候,也不能只把它当聊天框,而要先判断任务适不适合,再把任务交清楚,然后在过程中和它协作。
一句话总结就是:OpenClaw 的价值,不在于多会说,而在于能不能把任务接过来,真的往前推。
下一章: 第三章 提示词系统