Agent Workflow Runtime 架构拆解:把 Agent Loop 从提示词搬进代码,长任务才真正稳了

拆解 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 agentsub-agent 可以使用更便宜、够用的模型,因为它们不再需要靠超强 instruction following 维持整条流程。结构已经在代码里了。

换句话说,Workflow 不是用代码取代模型。它只是把"谁负责结构"这件事说清楚:确定的骨架归代码,不确定的判断归模型。

图:Workflow Runtime 用确定性结构承载 Agent 的开放判断

Skill 和 Workflow 的分界:谁来保管结构

Skill 与 Workflow 看起来都在指导 Agent 做事,但它们的工程含义完全不同。

维度 Skill Dynamic Workflow
结构位置 写在自然语言说明里,运行时由模型理解 写在脚本控制流里,运行时按代码执行
执行路径 每次可能不同,模型临场决定 阶段、分支、循环显式固定
对模型要求 高,需要持续遵守说明 低,模型只处理被调用的子任务
复盘方式 难以还原完整路径 日志、状态和阶段都可追踪
适合任务 探索性强、边界模糊、临时性任务 阶段清楚、有验收标准、会反复执行
成本结构 往往依赖强模型全程维持 强模型生成一次,普通模型执行多次

我更愿意把两者看成两种不同的手感。

Skill 像是给一个聪明同事的任务说明。你相信他能看懂,也允许他临场调整。Workflow 像是把一条工作流写进调度系统。它少一点即兴,多一点可控。真实场景里两者会一起出现:先用 Skill 生成 Workflow,再用 Workflow 编排多个 agent。

一个研究型任务怎么被编译成 loop

以"深度研究"为例。用户给一个复杂问题,系统先快速扫一遍背景,再规划子课题,并行研究,合并成稿,审稿,必要时回炉,最后做终验。

如果把它写成 prompt,模型需要自己记住所有阶段。如果把它写成 Workflow,骨架就变成了这样:

图:研究任务被拆成扫描、规划、并行研究、审稿和终验阶段

对应到脚本,大概会长成下面这种形态。这里保留的是机制,不照搬任何具体实现。

javascript 复制代码
export const meta = {
  name: "research-workflow",
  phases: ["scan", "plan", "research", "draft", "review", "finalize"],
}

const query = args.query

phase("scan", "先把问题和背景摸清楚")
const scan = await agent(`
读用户问题,找出核心对象、争议点和需要进一步查证的方向。
问题:${query}
`)

phase("plan", "拆出能并行推进的研究块")
const plan = await agent(`
基于问题和初步背景,设计若干个互不重复的子课题。
每个子课题需要有目标、搜索线索和交付标准。
背景:${scan}
`, `
子课题之间应当边界清楚,合起来能回答原问题。
`)

phase("research", "并行处理子课题")
const findings = await Promise.all(
  plan.map(item => agent(`
围绕这个子课题做研究,输出结论、事实依据、不同观点和不确定性。
子课题:${JSON.stringify(item)}
  `, `
结果必须能支撑最终报告,不能只给泛泛摘要。
  `))
)

phase("draft", "把分散材料合成一篇报告")
let report = await agent(`
把这些研究结果整合成完整报告。先给结论,再展开证据和限制。
材料:${JSON.stringify(findings)}
`)

phase("review", "审稿和回炉")
for (let i = 0; i < 3; i++) {
  const review = await agent(`
检查报告是否回答问题、证据是否够、结构是否顺。
报告:${report}
  `)

  const needRewrite = await assert(`
审稿意见里是否有必须修改的问题?
意见:${review}
  `)

  if (!needRewrite) break

  report = await agent(`
根据审稿意见输出完整新版报告。
旧稿:${report}
意见:${review}
  `)
}

phase("finalize", "最终验收")
const ok = await assert(`
判断这份报告是否可以交付。要求:回答原问题,有证据,限制讲清楚。
报告:${report}
`)

if (!ok) throw new Error("final report failed validation")
return report

这段伪代码里,真正有意思的不是语法,而是边界。

Promise.all 决定并行,for 决定最多回炉三次,if 决定何时跳出,throw 决定失败不静默吞掉。这些都是代码控制流。模型不需要记住"研究完要审稿、审稿不过要重写、最多三轮",脚本会逼着它走。

模型出现的地方只有两类:agent() 干活,assert() 判断。它们被代码点名调用,而不是在流程里自由漂移。

agent() 不是一次调用,而是一道质量门

很多人第一次看 Workflow,会把 agent() 理解成"调一次模型"。这个理解太薄了。

更准确地说,agent(taskPrompt, verificationPrompt?) 是一个带验收标准的 ​worker ​。第一个参数告诉它做什么,第二个参数告诉它什么叫合格。实现上,它可以搜索、反思、重试、修正,直到通过内部的 ​verification​,才把结果吐给外层脚本。

这有个很实用的效果:重试逻辑不需要到处写。

外层 Workflow 不必写一堆 retryscorefix 的样板代码。它只需要声明每个 worker 的准出门。worker 自己负责把事情做到能交差。这就把脚本层和工作层拆开了:脚本层管路线,worker 层管产出质量。

图:agent() ​更像带验收标准的质量门,而不是一次裸模型调用

assert() 则站在更高一级。它不处理某个 worker 的内部质量,而是决定阶段是否能往下走。比如审稿意见是否需要回炉,终稿是否能交付。这里的判断仍然可能由 LLM 完成,但它被包成了一个清晰的布尔信号,能驱动代码分支。

一条可复用 loop 需要哪些部件

把研究任务拆完之后,可以得到一套更通用的检查表。设计 Workflow 时,我会先问这些问题:

部件 设计时要回答的问题
Trigger 这条 loop 被什么启动?用户手动触发、定时任务,还是某个外部事件?
Planner 大任务是否需要先拆解?拆解出来的子任务能不能并行?
State 中间结果放在哪里?变量、文件、数据库,还是外部任务系统?
Workers 哪些部分交给 agent 做?每个 worker 的输入输出是什么?
Evaluator 每个阶段怎么判定过关?用规则、测试,还是 LLM-as-a-Judge?
Loop / 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 越自动,越要给人留接口。否则它只是更有条理地犯错。

什么时候不该写 Workflow

Loop 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 Engineering:Agent 真正能交付,靠的不是更强模型,而是上下文、执行协议和验收闸门

Agent 工具链工程化: Skill 负责编排判断,CLI 稳定交付的执行边界

AI Coding 如何影响交付链路重构:写代码更快了,为什么人反而觉得更累了?