
拆解 Workflow Runtime 如何用代码接管 Agent Loop让长任务更稳定、可复盘、可复用。原文链接AI 小老六导语过去一两年很多人都在想同一个问题Agent 为什么一到长任务就开始飘单轮问答里模型很聪明。给它一个目标、几条约束、几个工具它经常能给出不错的结果。可一旦任务变长事情就没那么体面了。它要记住阶段要判断下一步要用工具要验收结果还要在失败时绕回来。所有这些动作如果都压在一次对话里的instruction following上流程迟早会松。这就是Loop Engineering值得被认真讨论的原因。它并不是再发明一种更会写 prompt 的方法而是把一类任务的执行方式重新摆放流程不再藏在模型临场推理里而是被编译成一段可以执行、可以观察、可以复用的 Workflow Script。代码负责走路模型负责在几个需要判断力的位置上出手。Boris Cherny 那句 “I don’t prompt Claude anymore. I have loops running that prompt Claude” 之所以有分量就在这里。重点已经从“我怎么提示模型”转到“什么样的 loop 在替我提示模型”。ReAct 的软肋流程全靠模型临场维持ReAct 的设计很漂亮模型先 reason再 act再 observe然后继续 reason。它自己就是那个 loop。图ReAct 将推理、行动和观察都交给模型临场维持这套范式适合探索。任务边界模糊、用户随时改主意、路径无法提前确定时让模型自己在循环里调整确实省事。Skill 也正是服务这类模式的它给模型一份说明书告诉模型遇到某类任务大概怎么走。问题出在稳定交付。在ReAct里阶段顺序、工具选择、错误恢复、是否遗漏检查项都要靠模型当场理解并坚持执行。模型每一步都在读说明、做判断、更新路线。一次跑通不难跑十次还保持同样的结构就难了。更麻烦的是复盘结果错了你很难准确指出是哪一步偏了因为执行路径本身就在模型的上下文里漂。所以 ReAct 的成本不只是 token 或模型价格。真正贵的是把整个流程交给模型的运行时自觉。Dynamic Workflow先生成脚本再让脚本调模型Dynamic Workflow换了一种摆法。它先用强模型把任务拆成一段 Workflow Script脚本里写清楚阶段、并行、循环、分支、验收和日志。等真正执行时流程控制由代码完成模型只在被显式调用的位置出现。图Dynamic Workflow 用脚本接管流程控制只在关键节点调用模型这里的Dynamic很关键。脚本不是工程师提前手写死的 pipeline而是模型按当前任务现场生成的。生成之后它又不再是飘在对话里的自然语言而是一段普通代码能改、能存、能重跑。这带来一个直接收益强模型只需要在“生成脚本”时出场一次。后续执行时orchestration agent和sub-agent可以使用更便宜、够用的模型因为它们不再需要靠超强 instruction following 维持整条流程。结构已经在代码里了。换句话说Workflow 不是用代码取代模型。它只是把谁负责结构这件事说清楚确定的骨架归代码不确定的判断归模型。图Workflow Runtime 用确定性结构承载 Agent 的开放判断Skill 和 Workflow 的分界谁来保管结构Skill 与 Workflow 看起来都在指导 Agent 做事但它们的工程含义完全不同。维度SkillDynamic Workflow结构位置写在自然语言说明里运行时由模型理解写在脚本控制流里运行时按代码执行执行路径每次可能不同模型临场决定阶段、分支、循环显式固定对模型要求高需要持续遵守说明低模型只处理被调用的子任务复盘方式难以还原完整路径日志、状态和阶段都可追踪适合任务探索性强、边界模糊、临时性任务阶段清楚、有验收标准、会反复执行成本结构往往依赖强模型全程维持强模型生成一次普通模型执行多次我更愿意把两者看成两种不同的手感。Skill像是给一个聪明同事的任务说明。你相信他能看懂也允许他临场调整。Workflow像是把一条工作流写进调度系统。它少一点即兴多一点可控。真实场景里两者会一起出现先用 Skill 生成 Workflow再用 Workflow 编排多个 agent。一个研究型任务怎么被编译成 loop以深度研究为例。用户给一个复杂问题系统先快速扫一遍背景再规划子课题并行研究合并成稿审稿必要时回炉最后做终验。如果把它写成 prompt模型需要自己记住所有阶段。如果把它写成 Workflow骨架就变成了这样图研究任务被拆成扫描、规划、并行研究、审稿和终验阶段对应到脚本大概会长成下面这种形态。这里保留的是机制不照搬任何具体实现。exportconstmeta{name:research-workflow,phases:[scan,plan,research,draft,review,finalize],}constqueryargs.queryphase(scan,先把问题和背景摸清楚)constscanawaitagent(读用户问题找出核心对象、争议点和需要进一步查证的方向。 问题${query})phase(plan,拆出能并行推进的研究块)constplanawaitagent(基于问题和初步背景设计若干个互不重复的子课题。 每个子课题需要有目标、搜索线索和交付标准。 背景${scan},子课题之间应当边界清楚合起来能回答原问题。)phase(research,并行处理子课题)constfindingsawaitPromise.all(plan.map(itemagent(围绕这个子课题做研究输出结论、事实依据、不同观点和不确定性。 子课题${JSON.stringify(item)},结果必须能支撑最终报告不能只给泛泛摘要。)))phase(draft,把分散材料合成一篇报告)letreportawaitagent(把这些研究结果整合成完整报告。先给结论再展开证据和限制。 材料${JSON.stringify(findings)})phase(review,审稿和回炉)for(leti0;i3;i){constreviewawaitagent(检查报告是否回答问题、证据是否够、结构是否顺。 报告${report})constneedRewriteawaitassert(审稿意见里是否有必须修改的问题 意见${review})if(!needRewrite)breakreportawaitagent(根据审稿意见输出完整新版报告。 旧稿${report}意见${review})}phase(finalize,最终验收)constokawaitassert(判断这份报告是否可以交付。要求回答原问题有证据限制讲清楚。 报告${report})if(!ok)thrownewError(final report failed validation)returnreport这段伪代码里真正有意思的不是语法而是边界。Promise.all决定并行for决定最多回炉三次if决定何时跳出throw决定失败不静默吞掉。这些都是代码控制流。模型不需要记住研究完要审稿、审稿不过要重写、最多三轮脚本会逼着它走。模型出现的地方只有两类agent()干活assert()判断。它们被代码点名调用而不是在流程里自由漂移。agent()不是一次调用而是一道质量门很多人第一次看 Workflow会把agent()理解成调一次模型。这个理解太薄了。更准确地说agent(taskPrompt, verificationPrompt?)是一个带验收标准的 worker。第一个参数告诉它做什么第二个参数告诉它什么叫合格。实现上它可以搜索、反思、重试、修正直到通过内部的 verification才把结果吐给外层脚本。这有个很实用的效果重试逻辑不需要到处写。外层 Workflow 不必写一堆retry、score、fix的样板代码。它只需要声明每个 worker 的准出门。worker 自己负责把事情做到能交差。这就把脚本层和工作层拆开了脚本层管路线worker 层管产出质量。图agent()更像带验收标准的质量门而不是一次裸模型调用assert()则站在更高一级。它不处理某个 worker 的内部质量而是决定阶段是否能往下走。比如审稿意见是否需要回炉终稿是否能交付。这里的判断仍然可能由 LLM 完成但它被包成了一个清晰的布尔信号能驱动代码分支。一条可复用 loop 需要哪些部件把研究任务拆完之后可以得到一套更通用的检查表。设计 Workflow 时我会先问这些问题部件设计时要回答的问题Trigger这条 loop 被什么启动用户手动触发、定时任务还是某个外部事件Planner大任务是否需要先拆解拆解出来的子任务能不能并行State中间结果放在哪里变量、文件、数据库还是外部任务系统Workers哪些部分交给 agent 做每个 worker 的输入输出是什么Evaluator每个阶段怎么判定过关用规则、测试还是 LLM-as-a-JudgeLoop / Branch哪些地方允许回炉最多回几次失败后是否降级处理Stop / Resume中途断掉怎么办从哪一步恢复状态如何校验Repeatability同一脚本重复执行时哪些差异是允许的哪些差异必须被记录可以把它画成一个更抽象的状态机图长任务 Workflow 的状态、回炉、暂停和失败路径这张表的价值不在于每条 Workflow 都要凑齐八个部件。简单任务用不上完整的 Stop / Resume也未必需要复杂 Planner。但只要是长任务Trigger、Workers、Evaluator、State 这几样绕不过去。少想一个后面就会多一个黑箱。可观测性不是装饰是长任务的安全带一个 loop 跑十几分钟用户看不到进度会天然不信任它。更糟的是用户不知道它正在错。phase()和log()看起来只是 UI 细节其实是Workflow 可观测性能投入使用的底层条件。phase()告诉用户当前在哪个阶段log()记录细粒度动作。它们不参与业务逻辑却让系统从黑箱变成可以旁观的机器。图长任务自动化越强越需要进度、状态和人工接管接口还需要两类人机接口。第一类是 Workflow 主动停下来问人。比如规划阶段出现两个方向一个偏技术实现一个偏市场分析。脚本不应该假装自己知道用户要哪个而是通过askUserQuestion()暂停把选择权交回去。第二类是用户主动打断。长 loop 正在跑用户突然发现方向不对不能等最后交付才纠偏。脚本可以在循环检查点调用drainInbox()把用户中途发来的 steering 消息并进当前状态。图Workflow 通过进度上报、主动询问和中途纠偏保留人的控制权loop 越自动越要给人留接口。否则它只是更有条理地犯错。什么时候不该写 WorkflowLoop Engineering 容易被讲成万能方案但它不是。如果任务只做一次边界还很模糊先开一段对话更便宜。如果任务依赖大量临场判断过早把流程钉死反而会限制模型发挥。如果验收标准写不清楚assert()也救不了你宽松的裁判会让错误安静地通过。Workflow 适合的是另一类场景任务会反复出现阶段相对稳定产出需要验收过程需要复盘成本还需要压下来。比如研究报告、内容生产、批量代码迁移、资料整理、周期性监控、复杂工单处理。这些任务不一定每一步都确定但“该有哪些步骤”通常是确定的。这时把流程编译成脚本就划算了。它给你的不是绝对正确而是工程上的抓手阶段可见、状态可存、错误可定位、结果可比较。模型仍然会犯错但错会发生在几个明确的调用点而不是散落在整段对话的雾里。结语Agent 的下一步不只是更聪明的模型也包括更可靠的运行方式。ReAct 把 loop 放在模型脑子里灵活但不稳。Dynamic Workflow 把 loop 放进脚本里少一点即兴多一点可复盘。两者没有谁取代谁的问题关键是看任务要什么探索要弹性交付要结构。我觉得 Loop Engineering 真正改变的是工程师和 Agent 的关系。你不再只是在写 prompt而是在设计一个会不断提示模型、调用模型、验收模型的运行时。Prompt 仍然重要但它退到更小的边界里。外层的 loop才是长任务能不能稳定跑完的关键。当这些 loop 未来能被 Agent 自己读懂、修改、组合Workflow 就不只是执行脚本了。它会变成 Agent Harness 的一部分既能调用模型也能约束模型既让模型发挥也让系统留下证据。这可能才是最值得投入的地方。不是让模型一次表现得像天才而是让一套系统在第十次、第一百次执行时仍然知道自己正在做什么。推荐阅读Google AX 控制面拆解分布式 Agent 如何把断点恢复、审计策略和执行调度收进同一条链路AI Native 竞争力真正稀缺的不是会用 AI而是把事往前推的人Harness EngineeringAgent 真正能交付靠的不是更强模型而是上下文、执行协议和验收闸门Agent 工具链工程化 Skill 负责编排判断CLI 稳定交付的执行边界AI Coding 如何影响交付链路重构写代码更快了为什么人反而觉得更累了