把漂浮在空中的 loop engineering 概念落地成一个 skill

📋 全文路线图
01
落地面临的第一道选择题
为什么不做独立调度器,而是让模型自己对自己负责
02
核心结构:Phase → Gate → Loop
三个核心概念 + 六组件框架完整对应表
03
三种执行模式
串行 / 并行 / 混合,以及跨组回退的隐形成本
04
门禁:Sub-agents 的落地
Maker-Checker 分离、自检 vs 门禁、double_check 的谎言
05
循环:核心争议,我的答案
retry 不是 loop、best-so-far 指针、终止优先级
06
诚实面对局限
三条关键设计边界
07
Notes 与 Instructions 的分工
一个被低估的设计细节
08
回到 loop engineering 本身
模板大于产品,框架不限制你

如果你关注 AI 编程领域的动态,你大概率在最近一个月里反复看到同一个词——Loop Engineering

一切始于 Boris Cherny 的一条推文。这位 Claude Code 的创造者说:"我早就不手动给 Claude 写 prompt 了。我用 loop 来驱动 Claude,由 loop 来决定接下来做什么。我的工作就是写 loop。"紧接着,龙虾(OpenClaw)创始人 Peter Steinberger 跟了一条:"别再给编程 agent 写 prompt 了。你应该设计驱动 agent 的 loop。"两条推文加起来近千万阅读。Addy Osmani(Google Cloud AI 总监)随后发了一篇系统性的长文,正式命名了这个概念,拆解出它的六个核心组件。

整个圈子像被点了一把火——"提示词工程已死""从 Prompt Engineer 到 Meta-Prompt Engineer""Loop Engineering 是下一个必须掌握的技能"——铺天盖地。

Loop Engineering 的定义(据 Addy Osmani): 不再是"你去 prompt agent",而是"你设计一个系统,由这个系统来 prompt agent"。

六个核心组件:Automations(调度)→ Worktrees(隔离)→ Skills(知识封装)→ Plugins(工具连接)→ Sub-agents(制作者与检验者分离)→ Memory(状态持久化)。

概念很性感。但当你真正想用的时候,会发现自己面对的是一个真空——这些文章告诉你 loop engineering 是什么、为什么重要、长什么样,但你找不到一个可以拿过来就用的东西。你能找到的,是散落在 GitHub 上的实验性脚本、个人博客里的思路分享、以及各家公司的内部实践。它们像乐高零件——你知道应该能拼起来,但不知道标准接口在哪。

这篇文章,就是我的拼装尝试。我把 loop engineering 的核心概念落地成了一个可复用的 Skill。

落地面临的第一道选择题

把概念做成 Skill,第一个要面对的问题不是"要不要实现六组件",而是:谁来替你计时计数?

在传统软件工程里,编排多步骤流程需要独立的调度器——一个不受执行体影响的控制器,来计时、计数、判断是否重试。但在 LLM 的世界里,这个调度器不存在。没有 cron 守护进程替你盯着,没有健康检查替你判断,没有 scheduler 替你记次数。Skill 的执行发生在对话上下文中,所有"外部机制"最终都会被 bypass——因为用户和模型之间的交互不可截获。

所以第一个选择题的答案是:不替代模型做决定,而是要求模型在每一次决定中留下可核查的痕迹。

不设外部计时器、不写强制拦截代码、不做独立的调度引擎。

而是:告诉模型"由你亲自执行,没有人在背后替你计时计数,你必须自己记录每一轮的时间、次数、结果,并在每次决策前检查这些记录。"

这套设计取向最终凝结成了 四条"防执行幻觉纪律"——它不是对模型行为的某种哲学反思,而是直接写在执行流程里的元认知要求:

第一条:你来做策略判断,但"做了没有"要靠你留下可核查的痕迹 第二条:门禁判断不能自己对自己说"过了" 第三条:目标达成要靠你能拿出来的证据,不能靠你自己说"做到了" 第四条:你的执行轨迹要让别人能看懂你做了什么

这四条纪律贯穿整条流水线的全部生命周期,任何一条被违反,执行报告的可靠性就归零。

这和 Addy Osmani 提出的"Maker-Checker Separation(制作者与检验者分离)"原则一脉相承——写代码的 agent 绝不能给自己打分。但我的处理方式走得更远:不是换一个 sub-agent 来检查就算完,而是在每一层执行中都要求"你既是执行者也是记录者",把自我监督从外部规范变成内部纪律。

Skill 的核心结构:Phase → Gate → Loop

整个 Skill 围绕三个核心概念展开:Phase(阶段)、Gate(门禁)、Loop(循环)。它们组合成一个完整的执行闭环:

① 正常流向(流水线主线): step-1 ──→ [gate] ──→ step-2 ──→ generate ② 内循环 local_retry(当前阶段内部重试,输入不变): step-1 ──→ [gate] ──→ step-2 ──→ ✓成功 ──→ generate ↑ │ └── retry ──┘ ×N,输入不变 ③ 外循环 loop(gate不通过,携带反馈回到前置阶段): 正常通过:step-1 ──→ [gate] ──→ step-2 ──→ generate 不通过循环:step-1 ←──────────────── [gate] ↑ │ │ │ ✗不通过 │ │ 携带未通过项 + 已尝试调整 └───────────────────────┘ (回到 step-1 重新执行)
🔁 内循环 · local_retry
当前阶段原地重试,输入不变。适用于网络波动、超时等临时错误。先耗尽 local_retry,再触发外循环。
🔁 外循环 · loop
回到前置阶段重新执行,必须携带上一轮的具体失败点和已尝试的调整方式——不带反馈的循环只是重复犯错。
🚪 门禁 · gate
质量校验点。必须用独立 subagent 执行,不得由主流程自判。校验通过是进入下一阶段的唯一许可。
📊 输出 · generate
基于所有前置输出生成最终产物(html/markdown/json)。循环场景中通过 data_mode 策略决定各轮产出的交付方式。

回到 Addy Osmani 的六组件框架——这个 Skill 与它的对应关系如下:

六组件Skill 中的落地说明
Automations
调度与触发
Loop 配置
(from / back_to / trigger / break)
YAML 中的 loop 字段完整定义了"什么条件下触发→回到哪个阶段→如何跳出"
Worktrees
工作隔离
未内置,外部接入 Skill 不强制绑定——由调用方在使用时按需接入 git worktree 或隔离目录
Skills
知识封装
type: skill + SKILL.md 每个 phase 可以声明调用哪个 skill,指令和避坑分离写入 instructions / notes
Plugins
工具连接
未内置,外部接入 Skill 依赖对话上下文中已有的 MCP 连接或工具权限,不自行管理插件生命周期
Sub-agents
制作者与检验者分离
Gate 的独立 subagent 校验 Maker-Checker 分离的最严格执行——gate 不得由主流程自判,double_check 防噪声
Memory
状态持久化
审计日志 + JSON 文件传递 audit_log.md 记录执行轨迹,JSON 文件在 phase 之间传递数据,best_of 保留各轮记录

六个组件中,四个(Automations / Skills / Sub-agents / Memory)直接落地,两个(Worktrees / Plugins)作为外部基础设施留给了调用方。这不是能力不足,是设计选择——不应该把隔离策略和工具连接绑死在框架里。这个 Skill 不试图完美实现每一个组件,而是做一个最小可用的、完整闭环的框架。

三种执行模式:直接对应真实工作流中的不同 loop 形态

🔵 串行 sequential: step-1 ──→ [gate] ──→ step-2 ──→ generate 🟢 并行 parallel: task-A ──┐ task-B ──┤──→ merge ──→ generate task-C ──┘ 🟠 混合 mixed: g1(并行)──→ [gate] ──→ g2(串行)──→ generate

串行适合有明显依赖链路的场景,并行适合多维度独立分析,混合则是现实世界最常见的形态——第一步并行采集多源数据,第二步串行做依赖分析。三种模式通过一个 YAML 字段切换,底层共用同一套 gate + loop 机制。

有一个设计细节在 loop engineering 的讨论中很少被提及,但在实践里非常关键:在混合模式下,如果外循环回到的是一个并行组内的某个 phase,整个并行组都会被重跑。这不是设计失误——并行组内的各 phase 共享下游依赖,只重跑其中一个会造成版本不一致,比多花一次资源更危险。这个取舍在社区讨论中几乎找不到,只有在实际拼装时才会撞上。

门禁:六组件中 Sub-agents 的落地

Loop engineering 的一个核心理念是 Maker-Checker 分离——做的人和检查的人不能是同一个人。这个理念在这个 Skill 中落地为 Gate 机制。也是整个框架里执行误差最大、最容易流于形式的地方。

Gate 必须以独立 subagent 执行校验,不得由主流程自判。这条规则看起来简单,但它违反直觉——你会有冲动说"我既然在执行,顺手检查一下不就行了吗?"

答案是:不行。同一个推理链条中的自判存在系统性偏差。模型完成一项任务后,紧接着在同一段推理中给它打分,它倾向于认为自己做得不错。这不是恶意,这是认知连贯性的自然结果——就像你让人写一篇文章然后自己审稿,他总能找到理由说自己写得还行。

为了把这个问题说清楚,有必要区分一下"step 内部自检"和"gate 门禁"——很多人把这两个搞混,以为 step 里加一段 self-validation 就算有了质量保障。实际上它们是完全不同的两种机制:

维度Step 内部自检Gate 门禁
执行者step 自己在执行过程中顺手检查独立 subagent,与执行 step 的不是同一个体
检查时机step 内部,失败时触发 local_retrystep 完成后,作为独立 phase 执行
失败后果原地重试(local_retry),输入不变触发外循环(loop),回到前置阶段,携带反馈
检查范围格式校验、字段完整性等 self-validation按 check_list 逐项验真——数据是否准确、逻辑是否自洽、结论是否合理
独立性❌ 同一推理链条✅ Maker-Checker 分离

两者在流水线中各司其职:step 内部自检负责"这件事我做完了没有",gate 负责"这件事做得对不对"——前者是执行完备性的检查,后者是交付质量的裁判。step 自检的结果只影响自己要不要重试一次,而 gate 的判断会决定整条流水线要不要回退重来。

但即使做到了独立 subagent,还有一个更隐蔽的坑——它只防噪声,不防偏差。这是我在文档中反复强调的一点:

⚡ double_check 的双刃剑: 同一个 check skill 跑两次,结果一致——看起来很好,但这只能说明这次没"手滑"。不能说明标准本身没问题。如果一个 check 标准天生偏松(比如只检查文件是否存在而不检查内容是否正确),跑两次一致只是两次都漏了同样的问题。两次一致反而可能被误读成"更可信",掩盖标准本身的缺陷。

真正的解决方案不是跑更多次同样的检查,而是换一个不同的检查方法做交叉验证。

这个认知在社区讨论中几乎不存在。大部分人看到"double check"就天然觉得更可信了——但在我这套框架里,double_check 只防随机噪声,不防系统性偏差。你真正需要的是不同 check skill 之间的交叉验证,而不是同一个 check 的多次重复。

循环:loop engineering 的核心争议,我的明确答案

Loop engineering 讨论最混乱的地方就是循环本身——while 还是 for?无限迭代还是设上限?每次重试时输入变不变?这些不是概念问题,是设计决策。我的答案是明确的。

很多人第一次接触这个 Skill 时,会把 loop 理解成"失败了就重来一次"。这是误解。重试(retry)是输入不变再试一次,只应对临时问题。但 loop 是带着上一轮的失败反馈回去重新执行。输入变了——因为你知道上次哪里没做好。这个区别至关重要。没有反馈的循环只是在消耗预算,不是在收敛。

这也是为什么 loop 配置中强制要求 strategy 字段必须写明"携带上一轮的未通过项证据和已尝试的修正方式"——这不是一个建议,是一个约束。

同时,循环的终止策略也有一条容易被忽略的设计:不默认"最后一轮最好"。实际执行中,第三轮的结果可能比第二轮差——模型越迭代越疲劳、上下文越长注意力越分散。所以引入了 best-so-far 指针:每轮完成后与历史最优比较,更优才更新指针。循环强制终止时,交付的永远是最优的那一轮,而不是最后一轮。

这正好回应了 loop engineering 社区中的"while loops vs for loops"争论——我的答案是:设上限、加门禁、维护最优指针。让循环收敛,而不是让它跑死。loop 不等于无限循环,这个 Skill 里的每一个 loop 都有明确的终止优先级:目标达成 > 次数耗尽 > 超时 > 成本耗尽 > 用户打断。

诚实面对局限:设计选择的几何边界

这个 Skill 在文档中列出了 7 条已知局限,这里说最关键的几条:

  • 没有外部强制机制。所有"硬上限"最终都靠模型自觉兑现。不存在一个独立于模型之外的调度器在替你计数。这是设计选择——但你必须知道这一点。
  • double_check 不防偏差。同一个 check 跑两次一致,不能说明标准本身没问题。怀疑标准有问题时,应该换一个不同的检查方法,而不是把同一个 check 再跑一次。
  • best_of 依赖 gate 的评分粒度。如果 gate 只输出二元通过/不通过,未通过的各轮之间无法区分优劣,退化为"最近一次未通过的结果"。
  • 这些局限不是 bug。它们是 Prompt 模板的宿命,也是它诚实的地方——它不假装自己做不到的事情。

    意外的细节收获:Notes 与 Instructions 的分工

    在收尾之前,还有一个细节值得单独拿出来说——虽然它在整个框架里最不起眼,但实际影响出乎意料的大。

    在这个 Skill 的 YAML schema 中,每一个阶段都有两个文本字段:instructions 和 notes。分工很明确:instructions 答"做什么",notes 答"做的时候要避免什么"。

    这个分工最初看起来像是文档洁癖,但实际使用中,它被证明是关键设计。原因是模型读 instructions 时的心态是"我要按步骤来",读 notes 时的心态是"有什么坑需要注意"——同一个问题在两个字段中触发的是不同的认知处理模式。

    我把 notes 分为三个层级:Pipeline 级的 notes 管全局约束,Phase 级的 notes 管这一步专属的避坑,Gate 级的 notes 管 check_list 之外的隐性标准。简单来说:instructions 回答"怎么做好",notes 回答"怎么做坏"。

    这个设计在 loop engineering 的社区讨论中几乎从没被提过。六组件框架里有 Skills(知识封装),但没有深入到"Skills 内部的 instructions 和 notes 怎么分工"这个粒度。这是我拼装过程中自己发现的重要细节。

    回到 loop engineering 本身

    回头看第二节那张对应表就知道了——四个组件直接落地,两个留作外部。这个 Skill 的选择一直很明确:不试图完美实现每一个组件,而是做一个最小可用的、完整闭环的拼装版本。

    所以它不是一个开箱即用的产品,它是一份模板——你拿走它,根据自己的场景去填充、去扩展、去改造。你可以给它加上工作树隔离,你可以给它接上 Slack 通知,你可以把它的 gate 从单次 subagent 升级为双 Agent 对抗验证。框架不限制你,它只确保你在这个框架里做的每一件事都是可追溯的。

    Addy Osmani 在那篇广为流传的文章结尾写道:"Build the loop. But build it like someone who intends to stay the engineer, not just the person who presses go."

    构建你的 loop。但在构建它的时候,要像你打算长期维护它的人那样去构建——而不是那个按了按钮就走开的人。

    如果你也想试试这套框架,它在 GitHub 上开源了。它不会让你的模型变聪明,但它会让聪明的模型不再做出不可追溯的蠢事。

    ★ GitHub:github.com/renqun/loop-engine