从循环到图:Agent 系统的编排工程 · 第 1 / 6 节

第 1 课:一个循环什么时候不够用

学习目标:

  • 用一个真实压垮单循环的任务,说清「换个更大的窗口」为什么解决不了形状问题
  • 说出 workflow 与 agent 的架构区分,并用「谁持有计划」判断手上的系统落在哪一端
  • 逐条列出该往上走的触发信号与该按住不动的反向条件,并先把延迟与 token 的代价亮在桌面上

前置要求:完成本系列前 11 门课,能手写以 stop_reason 驱动的 harness 循环(本系列第 7 门课) | 下一课 第 2 课 >>

跑到第 30 个模块,事情开始不对劲

你们要把一个后端仓库从内部 RPC 框架 v1 迁到 v2,动手之前得先摸底:仓库里有 40 个模块,每个模块要出一份迁移评估——列出风险点、估一个改动量、附一张依赖清单。这活不难,就是多。你手上正好有本系列第 7 门课写的那个 harness:

(harness 就是包着模型调用的那层宿主代码:发请求、执行模型要用的工具、把结果塞回去、判断该不该继续。)

你把 40 个模块的清单一次性交给它,写一句「逐个评估,每个模块一份报告」,然后去泡咖啡。

前 5 个模块很漂亮:它 grep 出调用点、读了配置、翻了测试文件,报告比你想象中细。

第 15 个模块的时候,你回来看了一眼日志。messages 数组已经很壮观了:前 14 个模块的 grep 输出、读进来的整段配置文件、写文件的成功回执、几次走错方向又退回来的痕迹,全都还躺在那条时间线上。这些内容一条都没错——它们当时确实必要。可它们现在的作用只剩一件事:占地方。

第 30 个模块开始,质量塌了。它把第 27 个模块的结论原样搬到第 30 个上,因为两个模块名字有点像;它悄悄省掉了前面每次都做的「检查是否有自定义拦截器」;到第 34 个,连输出格式都开始飘。

你的第一反应大概率是:换个上下文窗口更大的模型。

这个反应只起一半作用。窗口翻一倍,崩塌点大概从第 30 个挪到第 55 个。而你手上的下一个仓库有 120 个模块。你没有解决问题,只是买了一段缓刑。

真正到头的不是窗口,是**「一个循环」这个形状**:40 个互不相干的条目被迫共用一条时间线、一份注意力预算。第 30 个模块的评估质量,取决于前 29 个模块留下了多少残渣——而这两件事本来一点关系都没有。

这门课要做的事,就是把这个形状换掉。

先把官方词汇摆正

Agent 的实现通常很直接——通常就只是在循环里根据环境反馈使用工具的 LLM1。你在本系列第 7 门课写的那段 while 就是它,一行不差。所以先给自己一个定位:你已经造过一个 agent 了,这门课不是从零开始。

再往上一层。Anthropic 把这些变体统称为 agentic systems(白话说就是:由模型、工具和某种控制流拼起来、能自己走多步的系统),但在这个大类里划了一条重要的架构分界1

  • workflow 是 LLM 与工具被预定义代码路径编排的系统1。「预定义代码路径」这五个字是关键——下一步做什么,写死在代码里。
  • agent 是 LLM 动态指挥自己的流程与工具使用、自己掌控完成方式的系统1。下一步做什么,模型当场决定。

顺手再补一个更底层的词,后面几课会反复用到。在计算机里,确定性系统给定相同输入每次都产生相同输出,而非确定性系统——比如 agent——即使起始条件相同也可能给出不同回应2

把这个定义按到你那段 while 上,会发现它是两种东西缝在一起的:怎么发请求、怎么执行工具调用、什么时候停——这些是确定性的,是你写的代码;而「下一步该 grep 什么、这份报告写完了没有」——这些是非确定性的,是模型当场决定的。你要动的手术,就是把决策权在这两半之间挪一挪。

「谁持有计划」这根轴

Claude Code 的文档把这件事问得更直接:子代理、技能、代理团队、工作流都能跑多步任务,差别是谁持有计划3

(「子代理」= 在自己的上下文窗口里独立干活、只把摘要交回来的助手;「扇出」= 一次派出多个子代理同时开工。这两个词本系列第 6 门课讲过。)

这句话把一堆看起来差不多的做法一刀切开了。同样是「跑 40 个模块的评估」:

  • 你在一条对话里让模型自己顺着做完 40 个——计划在模型手里,而且是隐式的,藏在对话历史里,你翻日志才能猜出它打算怎么走。
  • 你让模型当编排者,它每轮决定下一个派哪个子代理去做——计划还是在模型手里,只是显式了一点。
  • 你写一段脚本,脚本自己 for 循环这 40 个模块——计划在代码手里,你打开文件就能读完,明天能一字不改地再跑一遍。

第三种做法有个精确的描述:工作流把计划搬进代码——脚本自己持有循环、分支与中间结果,模型的上下文只装最终答案3。而中间结果留在脚本变量里,不落进模型的上下文3。第 27 个模块的 grep 输出留在一个 JavaScript 数组里,第 30 个模块的评估自然就看不见它——不是模型学会了忽略,是它压根没机会看见。

这根轴的两端,官方各给了一句适用面:需要更多复杂度时,workflow 为定义清晰的任务提供可预测性与一致性,agent 在需要灵活性与模型驱动决策的规模化场景更合适1

这里要说清一件事:本课把这根轴叫「确定性光谱」,把第 5 课那套组合画法叫「图」「节点」「边」。这些叫法都是本课自己的工程隐喻,一手材料里一次都没出现过——一手给的只有两端的定义(预定义代码路径 vs 模型自主决定)1和「谁持有计划」这个提问方式3。借用光谱和图是因为它们方便把真实存在的模式排在一起;你在任何官方文档里都读不到这两个词,别把它们当官方概念说出去。

什么时候该往上走

「一个循环不够用了」听着像感觉,其实有几个说得出口的触发信号。

信号一:需要的代理多到一场对话协调不动,或者你想把编排固化成能读、能重跑的脚本3。前半句是能力问题,后半句是工程问题——哪怕一场对话勉强协调得动,「明天能不能原样再跑一遍」也够格当理由。

信号二:任务大过一个代理能装进上下文的量,或者同一步要在很多条目上跑3。这两句合起来正好把开头那个 40 模块的场景说完了。注意第二句:条目数多本身就是理由,跟每个条目难不难无关。

信号三:旁支任务会淹掉主对话。子代理文档的场景描述是:当一个旁支任务会用搜索结果、日志或你不会再看第二眼的文件内容淹没主对话时,就派个子代理——它在自己的上下文里干这活,只把摘要交回来4把探索和实现挡在主对话之外,以此保住上下文4。注意这个信号给的药方是「派个子代理」——计划仍在模型手里;它和「把计划搬进代码」是两码事,Level 2 练习的 B、C 两列会把这层差别摆开。

先看下面这段代码,感受一下形状换掉之后长什么样:

循环还是那个循环——runHarnessLoop 里面就是你本系列第 7 门课写的那段 while。变的只有一件事:谁来数到 40。以前是模型在数,现在是 for 在数。

什么时候按住不动

触发信号背面有一份同样长的清单,这份更容易被跳过。

先找最简单的方案,必要时才加复杂度——这可能意味着压根不建 agentic 系统1对很多应用来说,优化单次 LLM 调用、配上检索和上下文示例,通常就够了1。那 12 处函数改名的活,不需要 harness、不需要编排,一次调用加一遍 grep 就结束了。

有些领域今天不适合多 Agent:需要所有代理共享同一份上下文的、或者代理之间依赖很多的。原文点名了一个例子——多数编码任务里真正可并行的部分比研究少,而且 LLM 代理目前还不太擅长实时协调与委派5。你要重构一个高耦合的订单模块,改动会连锁波及一串调用方——这活扇出成五个子代理只会更慢更乱,因为它们要看的是同一份东西,谁先动都会让别人手上的信息作废。

反过来,正向的适配条件也说得很干脆:他们发现多 Agent 擅长这类任务:重并行、信息量装不下一个上下文窗口、要对接一大堆复杂工具,而且任务本身值钱5。三个条件命中得越多,往上走越划算。

还有一类任务是该留给自主循环的,不该硬拗成编排:开放式问题、难以甚至不可能预测所需步数、没法硬编码一条固定路径——这种可以交给 agent,它可能要跑很多轮,你得对它的决策有一定信任1。Anthropic 自己的研究系统就是这类:研究工作是开放式问题,事先很难预测需要哪些步骤,你没法为探索复杂主题硬编码一条固定路径,因为这个过程内在就是动态的、路径依赖的5

所以「该不该上编排」不是一根单向的进度条。40 模块评估该往编排走,是因为步骤固定、只是条目多;「该不该把消息队列从 A 换成 B」不该往编排走,是因为你连要读几篇东西都不知道。

成本先亮在桌面上

在开始学五个模式之前,先把账本翻开。

agentic 系统常常是用延迟和成本换来更好的任务表现,你应该想清楚这笔交易什么时候划算1。这里没有一个字是修辞:它说的就是一笔交换

有多贵?Anthropic 给了一组他们自己数据里的观察:代理通常比聊天式交互多用约 4 倍 token,多 Agent 系统比聊天多用约 15 倍5。所以他们的结论是——要在经济上说得通,多 Agent 系统需要任务本身的价值高到足以支付这份性能提升5

注意这个数字的语境:它来自他们自己的数据,不是普适基准,也不是「所有编排方案都贵 15 倍」。但方向明确:你每往「更多代理、更多并行」挪一步,账单就往上跳一档。顺带划清:这个乘数量的是多代理系统相对聊天的用量,不是「把计划搬进代码」这个动作本身的价签——一手材料没给过编排脚本自身的开销数字。这也是为什么开头那 40 个模块值得往上走、而 12 处改名不值得——不是因为一个「复杂」一个「简单」,是因为一份能救下两周返工的迁移评估付得起这笔钱。

接下来五课怎么走

这门课剩下的部分从最轻的形状开始,一路加到能组合:

  • 第 2 课 链式与路由:把任务拆成固定的几步、每步之间加一道程序化关卡;分类之后分发到专门化的提示词。最轻量的「计划在代码里」。
  • 第 3 课 并行化:分段(切成互不依赖的子任务同时跑)与投票(同一任务跑多次拿多样化输出),以及怎么在代码里聚合结果。
  • 第 4 课 编排者-工人:中心模型动态拆解任务、派给工人模型、再综合结果。关键差异是子任务不预先定好。
  • 第 5 课 评审回路,以及把模式组合成图:查-修-再查直到通过或不再有进展,然后把前面几样拼起来。那一课会再明说一次:「图」是本课自己的画法。
  • 第 6 课 实战:把你本系列第 7 门课那个单循环 harness 升级成一段确定性编排脚本。

这套模式分类不是 2024 年的老黄历:现行的 Claude 平台多代理编排文档里仍然独立点名了 Parallelization(并行扇出独立子任务、由协调者综合结果)、Specialization(路由到有领域提示词和工具的代理)、Escalation(就一部分复杂子任务去请更强的代理或模型)6。名字换了皮,骨头是同一副。

再说清这门课跟前面两门的分工:本系列第 2 门课教工作流的概念——步骤、状态、分支,画图级别的认识;本系列第 6 门课教多 Agent 协作的分工与沟通——扇出、派活提示词自包含、生产者-评审者。这门课两样都不重讲,它管的是控制流本身:谁数数、谁分支、中间结果放哪、挂了怎么办。顺带一句词汇搭桥:本系列第 6 门课里叫「生产者-评审者」的那套,一手材料里叫 evaluator-optimizer1,Claude Code 的工作流文档里则叫让独立的代理对抗式地互审彼此的发现3

分寸:每一样都得过「可测量的改进」这一关

这门课接下来会教你五个模式、一堆组合方式。它们共用同一条准入线,原文说得毫不含糊:这些构件不是处方,是常见模式,成功的关键跟任何 LLM 功能一样——测量表现、迭代实现。再重复一遍:只有当复杂度能被证明改善了结果时,才考虑加它1

「被证明改善了结果」要落到实处,靠的是本系列第 10 门课的评测和本系列第 11 门课的观测:没有评测集,你说不清「加了路由之后到底好了没有」。原典的结尾就是这个顺序:从简单提示词开始,用充分的评测把它优化好,只有当简单方案确实不够用时,才加多步的 agentic 系统1

所以每学完一个模式,请对自己问一遍:我能不能拿出一个数,说明加了它之后结果更好了? 拿不出来,就先别加。

💻 练习

小结

  • 你在本系列第 7 门课写的那段 while 就是一个 agent——Agent 的实现通常很直接,通常就只是在循环里根据环境反馈使用工具的 LLM1
  • 这些变体统称 agentic systems,其中划了一条架构分界:workflow 是 LLM 与工具被预定义代码路径编排的系统,agent 是 LLM 动态指挥自己的流程与工具使用、自己掌控完成方式的系统1
  • 分辨它们的那根轴是「谁持有计划」:工作流把计划搬进代码,脚本自己持有循环、分支与中间结果,模型的上下文只装最终答案3。本课把这根轴叫「确定性光谱」、把第 5 课的组合画法叫「图」,两个词都是本课自创的隐喻,一手材料里没有。
  • 该往上走的信号:代理多到一场对话协调不动、或想把编排固化成能读能重跑的脚本3;任务大过一个代理能装进上下文的量、或同一步要在很多条目上跑3;旁支任务会用你不会再看第二眼的内容淹掉主对话4
  • 该按住不动的条件:先找最简单的方案,必要时才加复杂度,这可能意味着压根不建 agentic 系统1;很多应用优化单次调用加检索和示例就够1;需要共享同一份上下文、或代理间依赖很多的领域今天不适合多 Agent,多数编码任务真正可并行的部分比研究少5
  • 该留给自主循环的:开放式、步数难以预测、没法硬编码固定路径的问题1——研究类工作就是典型,过程内在动态、路径依赖5
  • 账要先算:agentic 系统常常用延迟和成本换任务表现1;他们自己的数据里,代理约比聊天多用 4 倍 token、多 Agent 约 15 倍,经济上要求任务价值配得上这份提升5
  • 这门课教的每一样都要过同一关:只有当复杂度能被证明改善了结果时才加它1;从简单提示词开始,用充分的评测优化它,简单方案确实不够时才加多步的 agentic 系统1

>> 第 2 课:串起来、分下去:链式与路由

Footnotes

  1. Building Effective AI Agents — Anthropic Engineering — https://www.anthropic.com/engineering/building-effective-agents 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

  2. Writing effective tools for agents — with agents — Anthropic Engineering — https://www.anthropic.com/engineering/writing-tools-for-agents

  3. Orchestrate subagents at scale with dynamic workflows — Claude Code 官方文档 — https://code.claude.com/docs/en/workflows 2 3 4 5 6 7 8 9 10

  4. Create custom subagents — Claude Code 官方文档 — https://code.claude.com/docs/en/sub-agents 2 3

  5. How we built our multi-agent research system — Anthropic Engineering — https://www.anthropic.com/engineering/multi-agent-research-system 2 3 4 5 6 7 8

  6. Multiagent orchestration — Claude API 文档(Managed Agents) — https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration

练习

01

不用写代码。下面 5 个任务,逐个判断它落在哪一档:

Level 1:把五个任务放进三档
  • 单循环够(甚至一次调用就够,别加复杂度)
  • 该上编排(把计划搬进代码)
  • 该留给自主循环(让模型自己决定步数)

第一档和第三档跑起来都是一个循环,分开列是因为不上编排的理由不同——一个是活太简单不值得,一个是活太开放拆不动;判档判的就是理由。每个判断配一句理由,理由必须指名本课列过的某一条具体条件(同一步要跑很多条目 / 大过一个上下文 / 多到一场对话协调不动 / 步数不可预测没法硬编码固定路径 / 简单任务别加复杂度 / 共享同一份上下文与依赖多的领域不适合多 Agent),不能只说「任务大」「任务复杂」。

  1. 给仓库里 40 个模块各写一份迁移评估,每份包含风险点、改动量估计、依赖清单。
  2. getUserProfile 改名为 fetchUserProfile,全仓 12 处引用一起改。
  3. 调研「我们该不该把消息队列从 A 换成 B」,没有既定的信息源清单,读到哪算哪。
  4. 给积压的 200 张客服工单各打一个分类标签(共 8 类),标签规则写死在一份文档里。
  5. 重构一个高耦合的订单模块:拆 3 个类、挪 2 个接口,改动会连锁波及一串调用方。
完成标准 · 本地勾选
02

不用写代码。还是那 40 个模块的迁移评估,三种做法:

Level 2:同一个任务,三种「谁持有计划」
  • A:一个大循环 —— 把 40 个模块的清单一次性交给一个 harness 循环,让它自己顺着做完。
  • B:模型当编排者逐个派子代理 —— 模型在主对话里每轮决定下一个派谁去评估哪个模块,子代理做完把结果交回主对话。
  • C:计划写进脚本 —— 一段脚本 for 循环这 40 个模块,每个模块起一个干净的 harness 循环。

补全下面这张表(问号是你要填的)。第三行是重点:跑到第 25 个模块时进程被杀了 / 会话断了,三种做法各自丢掉什么?

A:一个大循环B:模型当编排者C:计划写进脚本
谁持有计划???
中间结果落在哪???
挂在第 25 个模块时丢什么???
完成标准 · 本地勾选

我的笔记

记下想法、痛点、没懂的地方。只写进这门课的附录,正课文件不动。