乐于分享
好东西不私藏

OpenClaw源码解析(八):OpenClaw 的 Agent 范式:内部求解循环、外层恢复循环

OpenClaw源码解析(八):OpenClaw 的 Agent 范式:内部求解循环、外层恢复循环

建议结合这些文件一起读:

– src/agents/pi-embedded-runner/run.ts– src/agents/pi-embedded-runner/run/attempt.ts– src/agents/pi-embedded-subscribe.ts– src/context-engine/types.ts– src/agents/tools/memory-tool.ts


这一篇的目标

上一篇主要讲的是真实执行链,这一篇我们的视角再往上提一层,回答以下问题:

  • OpenClaw 的主 agent 到底属于哪种范式。
  • 为什么你在代码里看到两层 loop,但它们不属于同一个分析层级。
  • 一个复杂任务在 OpenClaw 里是如何被“持续推进”的。

先给一个准确定位

OpenClaw 当前的主 agent 是一个 ReAct-like single-agent execution loop,外面包了一层 runtime recovery loop,再由 context 和 memory 系统为它提供可持续工作记忆。

拆开看就是:

  1. single-agent

主决策者通常只有一个,没有显式的 planner / critic / judge 多角色。

  1. ReAct-like

模型会根据当前上下文决定是直接回答还是调用工具,工具结果再回流到同一条 transcript。

  1. runtime recovery loop

环境失败时不是直接结束,而由 run.ts 外层重试、切换账号、切换模型、压缩上下文。

  1. context + memory support

attempt 级重放能不能继续任务,不取决于“断点恢复”,而取决于上下文和记忆是否把任务状态保留下来了。


一定要分清两种“多轮”

这是理解 OpenClaw 时最容易出错的地方。

第一种:任务求解多轮

这是 agent 真正“做事”的轮次。

例如:

读文件-> 发现还不够-> 再搜一处-> 调命令验证-> 修改文件-> 再跑测试-> 最终回答

这种多轮发生在一次 attempt 背后的内部 session runtime 中。

第二种:运行恢复多轮

这是外层 run.ts 在做的事。

例如:

这次 attempt 因上下文溢出失败-> 先 compact-> 再发起一个新的 attempt

或者:

这次 attempt 用的账号失效-> 换 profile-> 再发起一个新的 attempt

这两种“轮次”在源码里都表现为“会再次调用模型”,但它们根本不是一回事。

前者是任务推进,后者是运行修复。


OpenClaw 为什么更像 ReAct,而不是 Planner-Executor

OpenClaw 当前主链没有一个清晰独立的“先做完整计划,再逐步执行”的硬边界。

它更接近:

看当前上下文-> 先决定下一步动作-> 执行动作-> 把结果写回上下文-> 再决定下一步

这就是 ReAct 范式的的核心。

具体体现

  1. 不预先生成完整执行图

没有显式 DAG 或多阶段 workflow 先展开再执行。

  1. 工具结果直接进入同一条 transcript

下一轮模型读取的是“自己刚刚行动后的最新状态”。

  1. 是否继续调工具由模型即时决定

不是外层流程引擎硬编码“必须先 search 再 read 再 edit”。

  1. 停止条件通常由内部 loop 自然收敛

当模型判断信息足够或任务完成,它就停止继续调用工具并输出最终答复。

因此从方法论上说:

OpenClaw 的主 agent 不是“先规划后执行”,而是“边观察边行动边更新工作记忆”。


为什么说 attempt.ts 是“执行容器”而不是“推理器”

attempt.ts 做了很多事,但它本身不扮演“决策者”。

它更像一个容器层,负责:

  • 准备工作记忆
  • 准备工具空间
  • 准备系统约束
  • 准备 hooks / skills / bootstrap
  • 接住底层事件
  • 在结束后把结果整理出来

真正“下一步该做什么”的决策,仍然由底层模型在 activeSession.prompt(…) 驱动的内部循环中完成。

所以你可以把三层关系记成:

run.ts      = 运行恢复控制器attempt.ts  = 单次执行容器session runtime = 真正的模型-工具求解循环

这套范式为什么天然依赖 transcript

如果一个系统采用的是“每一步都重新算完整计划”,它对 transcript 的依赖反而可以弱一点。

但 OpenClaw 不是。

它依赖的是:

上一步做了什么+ 得到了什么观察+ 现在还缺什么-> 决定下一步

这意味着 transcript 在这里不是“聊天记录”,而是:

当前任务的在线工作记忆。

里面承载的不是只有 user / assistant 文本,还有:

  • tool call
  • tool result
  • reasoning 相关块
  • 图片
  • 自定义条目
  • compaction summary

一旦 transcript 被裁坏、配对关系坏掉、tool result 太长、历史结构非法,任务推进能力会直接下降。


为什么这套范式还需要外层恢复 loop

如果只有内部 ReAct-like loop,没有外层恢复层,这套系统会非常脆弱。

原因很简单:agent 的失败不止是“想错了”,还有大量基础设施失败:

  • provider 超载
  • timeout
  • auth/profile 失效
  • 模型能力不兼容
  • context overflow
  • 工具结果把上下文顶爆

这些问题单靠“模型再想一轮”没有意义。

所以 OpenClaw 把恢复权收回到 run.ts

  • 内层 loop 负责求解任务
  • 外层 loop 负责修复运行环境

这其实是一种非常典型的 agent runtime 分层。


“为什么外层不直接接管任务推进”

因为如果外层也去管任务步骤,就会把系统变成另一种形态:

  • 需要显式的 planner
  • 需要显式的 task state machine
  • 需要定义每种工具的编排规则
  • 需要更多框架层调度逻辑

OpenClaw 当前显然没有选择这条路线。

它选择的是:

把任务推进留给模型,把运行恢复留给 runtime,把工作记忆维护交给 context/memory。

这条路线的优点是灵活,代价是对上下文质量要求非常高。


一次 attempt 内,什么在变,什么相对稳定

理解这一点很关键。

相对稳定的东西

  • 当前 attempt 的基本执行容器
  • 当前 attempt 内构建出来的 system prompt 主体
  • 当前 attempt 可用的工具集合
  • 当前 attempt 绑定的 provider / model / profile

持续变化的东西

  • transcript 内容
  • tool result 数量
  • usage 累积
  • compaction 状态
  • 当前任务所处阶段

外层重试时,什么会被保留,什么会被重建

这也是理解“attempt 级重放”必须知道的。

会被保留的

  • session 中已经写入并保留下来的 transcript
  • 上下文压缩后的结果
  • 某些 prompt-error 自定义条目
  • memory flush 后落入长期记忆的内容

会被重建的

  • 本次 attempt 的 session runtime 容器
  • system prompt 的完整装配
  • hook 运行结果
  • history sanitize / validate / limit / repair 的过程
  • 订阅器和流式状态

所以新的 attempt 不是“完全从零”,也不是“沿用上一个 attempt 的内存现场”。

它是一种中间态:

保留工作结果,重建执行容器。


一个复杂任务在这套范式下是怎么完成的

拿一个代码修复任务举例:

用户:修复 webhook 重复发送

真实推进方式更接近:

  1. attempt 启动,组装 prompt、tools、context。
  2. 内部 agent loop 先搜索和读文件。
  3. transcript 写入搜索结果和文件内容摘要。
  4. 模型根据新观察形成假设。
  5. 调命令验证假设。
  6. 修改代码。
  7. 运行测试。
  8. 如果通过,输出最终答复。
  9. 如果中途 context overflow,外层 run.ts 才介入做恢复。

注意:第 2 到第 8 步通常都在同一个 attempt 内发生。

这说明 OpenClaw 的主能力不是“把任务拆成很多外层流程节点”,而是:

给同一个 agent 一个足够好的连续工作空间,让它自己把链条走完。


这套范式最值得学习的设计点

1. 将“求解失败”和“运行失败”分层

模型不会因为 auth 失效这种基础设施问题直接承担恢复责任。

2. 将 transcript 当作在线工作记忆,而不是聊天日志

这让工具密集型任务能在一个长链里持续推进。

3. 允许 attempt 级重放,而不是依赖 fragile 的中间断点恢复

这提高了跨 provider、跨 compaction、跨 profile 恢复的健壮性。

4. 通过 context/memory 系统给重放提供“状态连续性”

否则 attempt 级重放会变成低质量重复劳动。

5. 把 system prompt 当成控制平面,而不是人格设定

这使得每次 attempt 都能重新绑定运行约束,而不是纯粹继承旧现场。


这一篇的最终结论

  1. OpenClaw 当前最接近“单智能体 ReAct-like 执行 + 外层运行恢复”的范式。
  1. 两层 loop 不是一个层级的问题。

内层 loop 解决任务,外层 loop 修运行环境。

  1. attempt 级重试是这套设计的关键。

它不恢复中间断点,而是依赖 transcript、context 和 memory 让新的 attempt 继续接近原任务状态。


如果您觉得有帮助,感谢您的关注和转发。

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » OpenClaw源码解析(八):OpenClaw 的 Agent 范式:内部求解循环、外层恢复循环

猜你喜欢

  • 暂无文章