把一次执行表示为图
可以把一次已经展开的执行写成有向图 G = (V, E)。节点是有输入、输出和状态的执行步骤,可以是模型调用、工具操作、程序检查或产物提交;边表示步骤之间的依赖。一个长期存在的 Agent 往往对应许多节点,因此 Agent 数量并不等于计算图的宽度。
还需要区分边的含义。数据依赖说明某步需要另一份产物;控制依赖说明谁有权启动、取消或选择后续步骤;消息关系说明谁能看到哪些内容。中央调度器可以安排互不通信的任务,参与者也可以交换消息而不获得调度权。把这些关系都画成一种箭头,会掩盖实际约束。
模型看到的上下文是执行状态的一种投影。完整状态还包括任务队列、工具返回、产物版本、预算和外部副作用。把所有聊天记录放进同一个窗口,并不能让这些状态自动一致;把记录拆到多个窗口,也不意味着任务已经可以独立完成。
Pipeline:把稳定依赖编进运行时
当步骤及其依赖可以预先描述时,流水线可以用静态 DAG 表达。它允许分支、条件门和 fan-out/fan-in:一个输入展开成多个可并行分支,再在满足约定后合并。阶段不必对应不同 Agent,同一个模型也可以被调用多次,程序检查则可以完全不用模型。
流水线的价值在于把正确性条件写到边界。结构化提取必须带来源位置,校验必须说明哪些字段通过,汇总只能消费明确允许使用的版本。格式验证只能检查结构;语义是否成立,还需要相应的证据、测试或人工判断。一个节点返回成功,不等于它产生的所有结论都可信。
固定阶段的流程也可以返工。DAG 描述一次尝试的依赖,重试由外层控制器创建新尝试,或由预设的有界循环管理。将每次尝试展开成独立版本后,仍可以追踪执行的先后关系。关键在于保留稳定的阶段契约,并只重跑输入或前提已经改变的后继步骤,而不是每次失败都从头开始。
Orchestrator:在运行中扩展任务图
更困难的情况是,子问题本身需要通过探索才能发现。Orchestrator-workers 在运行时读取当前状态,提出新任务、选择执行者,再根据返回结果调整计划。预先枚举十个固定任务并发运行,已经有调度,却还没有这种动态任务生成。
协调者可以是程序,也可以包含模型决策。新任务先检查重复、写入冲突与预算;只有所需输入版本已提交且仍有效,才从 WAITING 进入 READY。就绪后还要等待执行槽和限流配额,不能把依赖已满足与现在可以派发混为一谈。
委派需要固定问题、输入版本、预期产物、读写范围和结束条件。新发现若改变任务范围,还应记录改变了哪项前提。一套保守的状态协议可以是:
WAITING → READY → RUNNING → VALIDATED → COMMITTED
RUNNING → FAILED
VALIDATED → STALE调用返回只产生候选。验证通过后进入 VALIDATED,依赖版本匹配且提交成功后才进入 COMMITTED,后继才能将它作为已确认输入消费。必需子任务失败时,父任务仍被阻塞,由协议选择重试、重规划或失败;若允许部分 fan-in,就把缺项写进条件产物。
独立上下文有利于隔离探索过程,也会让协调者承担压缩与整合工作。若各分支必须不断共享同一组隐含决策,拆分后的通信可能超过并行收益。我会优先把边界清楚的调查交出去,将必须共同修改的决策集中处理。
状态归属决定结果怎样提交
多窗口最容易出问题的地方,是参与者对“当前状态”各有理解。为可变产物指定写入者,其他任务基于固定快照提出候选,可以减少相互覆盖。写入者可以随阶段转移,但这种转移应由运行时记录和约束,不能只靠角色提示词。
每份结果应附带输入产物及版本、执行配置、检查状态和产物版本。若两个任务都从版本 v 读取,其中一个先提交了 v+1,另一个结果是否仍可用,需要检查它实际依赖的内容。它可能需要重算,也可能在核对后继续使用;不应直接覆盖较新的状态。
上下文压缩也应服从依赖边界。摘要保留了什么、丢掉什么,会改变下游能作出的判断。与其把完整日志反复塞进窗口,我会保留可回查的原始轨迹,另传任务需要的决定、约束和依据位置。短摘要不是信息完整性的保证;如果接收者无法据此发现关键前提缺失,就需要调整交接格式或收回这次拆分。
inputs = store.read_pinned(task.dependencies)
proposal = run(task, inputs)
if not validate(proposal, inputs):
return FAILED
return store.commit_if_dependencies_match(
proposal,
expected_versions=inputs.versions,
writer=task.owner
)这里假设存储层把依赖版本检查与提交做成原子操作,否则检查之后仍可能发生竞争。伪代码只处理受该存储层管理的产物,不能保证远端工具副作用也具有原子性。一次代码修改还可能隐含接口、路径或数据格式决策;这些约束需要进入共享产物,不能只留在某个 Agent 的对话里。
并行度受关键路径和同步边界限制
对已经展开的固定 DAG,设节点 v 占用执行资源的时长为 tv,总工作量 W = Σv tv,最多有 P 个同类执行槽。忽略调度开销,任务完成时间 L 至少受两项约束:
CP 是关键路径长度。这个下界假设节点时长已知、槽位可互换,依赖和通信耗时已被图正确表示。真实系统还需另行考虑 LLM API 限流、服务端排队和异构资源;动态任务生成时,完整图事先也未知。公式用于辨认瓶颈,不能直接预测一次 LLM 工作流的耗时。
Fan-out 后若必须等待全部结果,慢分支会推迟 fan-in。允许部分结果先驱动后续工作,可以缩短某些等待,但必须说明哪些缺项可以接受、后来结果如何合并,以及是否要修订已经输出的判断。超时不能被解释为否定证据。
同步更新让参与者读取同一轮快照,全部完成后再提交;顺序更新让后发者看到前面的修订;异步更新则可能读到不同年龄的状态。异步可以提前使用结果,也增加版本核对和取消工作的复杂度。并行调用不自动意味着异步协议,增加 Agent 也不能缩短不可并行的关键路径。
Debate:让候选相互影响的局部协议
Debate 可以放进图中的一个局部子流程:先保留互相不可见的初答,再把具体主张及依据送给其他参与者,记录质疑、回应和修订。相比独立采样后投票,它增加的是候选之间的信息依赖,而不是简单增加一次采样。
记录应指向可检查对象,例如某个推导步骤、测试结果或来源片段。参与者可以补充反例,也可以返回没有新增依据。固定支持与反对角色,或者要求每轮必须产生新证据,都可能把讨论推向为角色交差。初答盲态只能减少直接跟随,不能消除同模型、同来源造成的相关错误。
交流拓扑、轮次更新、裁决和停止是不同选择。消息可以经主持者转发,也可以只在邻居间交换;裁判可以输出条件结论或弃权。达成共识不能替代测试和证据检查。若增加交流后正确候选被覆盖,系统需要能从保存的版本中看出这次退化。
通信拓扑和历史保留共同决定输入量
先建立一个只计算跨参与者消息输入的简化模型。N ≥ 2 个参与者使用固定拓扑,每条新消息长度为 ℓ 个 token,不计算自发自收。全连接每批有 N(N−1) 次定向交付;单向环每人只发给下一个节点,共 N 次。相同文本进入多个接收者的上下文,需要按接收次数累计。
设每批交付数为 m。把初始候选作为第一批,在 R 次更新中,第 r 次更新之前已经有 r 批可读消息。若每次只读最新一批,或者每次重读全部已接收历史,通信输入量分别为:
Cfull = mℓ Σr=1R r = mℓR(R+1)/2
| 拓扑 | 每批交付数 m | 只读上一批 | 重读全部历史 |
|---|---|---|---|
| 全连接 | N(N−1) | N(N−1)ℓR | N(N−1)ℓR(R+1)/2 |
| 单向环 | N | NℓR | NℓR(R+1)/2 |
这些量只统计消息作为模型输入被读了多少次。基础提示、本地历史、工具结果、输出生成与消息封装都未计入,也忽略缓存、截断和压缩。发送给多个接收者可以复用同一份已生成文本,因此输入复制不能直接当作输出生成量。输入 token 总量也不等于账单或实际算力。
减少边数会改变可见信息。单向环上,一条信息到最远节点可能需要 N−1 跳;固定轮数下,不能假设它与全连接看到了同样的候选。定长消息也可能在转述时丢失细节。图中的输入量比较并没有给出效果排序,轮数和拓扑需要连同任务结果一起评估。
中央汇总还引入另一种取舍。若另设一个中心连接这 N 个参与者,一轮有 N 次上行与 N 次下行,只有把每次下行压成固定长度时,才可把消息体都按 ℓ 计算;这已经改变了信息内容。中央还要读取和生成摘要。若每人仍要获得其他人的全部原始消息,仅仅改成两跳转发并不能消除需要读取的内容。
恢复沿依赖传播,权限在执行点检查
检查点需要保存已提交产物、输入版本、队列与在途任务、预算消耗和副作用状态。恢复时先区分已完成、失败、超时和结果未知。读取失败通常可以重试;一次外部写入超时,却可能已经成功,需要查询操作状态或使用幂等键,不能直接再执行一次。
新输入或配置变化时,沿记录下来的依赖使受影响结果失效,而不是清空整个任务。对于可缓存步骤,缓存键还应覆盖会影响结果的模型、提示、生成配置、工具和输入版本,并核对工具结果是否仍有效。恢复能够继续工作,不代表逐 token 重放会得到同一个答案;需要保留的是足以检查和接续执行的状态。
权限仍在执行点检查:委派只传递已获准的读写能力,检索材料和其他 Agent 的消息不能自行变成指令。派工权不等于扩张工具权限。状态归属解决产物竞争,授权决定动作能否执行,两者不能互相替代。
把三种机制组合在不同层次
一个可控的组合是:外层用静态阶段组织输入获取、候选生成、校验和提交;只在某个阶段发现未知子问题时,由协调者展开局部任务图;只有存在会影响结果的具体分歧时,再启动一段有轮数限制的 Debate。每个局部过程返回明确状态,随后回到外层依赖。
组合是否成立,取决于返回语义。协调者新增任务后,谁负责等待和取消?辩论推翻前提后,哪些校验需要重跑?未解决的分歧能否作为条件产物提交?这些规则决定图如何变化。给每个阶段都增加一个经理与评审,反而可能让稳定依赖变成多次重复解释。
验证本身也会消耗关键路径上的资源。如果汇总者必须重新读取每个分支的全部材料、重走所有工具调用才能判断结果是否可用,候选虽然并行生成,验收仍可能接近串行重做。返回格式应让关键前提和检查结果可以局部核对;这部分节省需要在完整任务里测量,不能仅凭分支更快结束就认定获得了加速。
我会把并行优先放在只读探索和候选生成,把共享状态的合并集中到明确的提交点。若分支必须持续交换大量细节,或每次提交都会使其他分支失效,就先收回拆分,检查是否应由同一条执行轨迹维护这些决策。
从框架组件反推执行语义
框架名称不足以说明上述选择。2026 年 10 月核查的 CrewAI 文档中,Crew 默认 sequential;hierarchical 需要显式选择,并提供 manager_llm 或 manager_agent。sequential 表达预定顺序,hierarchical 引入经理分派与检查。它们都没有替应用定义产物版本和验收条件。
Microsoft Agent Framework 提供 sequential、concurrent、handoff、group chat 和 Magentic。其 group chat 也可以由中央协调者选择发言人;Magentic 使用经理动态协调。共享对话、集中控制和动态任务可以同时出现,不能从“群聊”推断没有中心。
AutoGen 当前已归档,可用作机制参考。它的经典 Debate 示例把稀疏连接的求解者与聚合者组合起来。选组件时,我会继续追问:返回是否阻塞、消息怎样进入上下文、失败怎样持久化、共享状态由谁提交。这些行为比模式名称更能决定系统是否符合设计。
用任务结果判断新增结构是否值得
比较前先固定任务集、输入快照、模型版本、工具范围和验收方式,保留未参与调优的任务。至少有一条单 Agent 基线,再比较独立候选聚合、静态流水线、动态委派和局部讨论。若要判断交流是否有用,应尽量复用同一批初答,减少候选质量差异造成的干扰。
相同 Agent 数量不是相同预算。计入输入与输出 token、工具调用、协调和摘要、失败重试,并同时报告实际费用和耗时。固定总预算时可以比较完成质量;固定质量目标时可以比较成本与延迟。两种问题不能混成一个没有约束的“更好”。
过程记录要能解释结果:关键路径上等了什么,有多少任务重复或失效,局部恢复节省了多少重算,交流让哪些正确候选改错。超时、弃权和预算耗尽也属于全体任务,不能只统计顺利完成的运行。多次重复有助于看清方差,但还需要检查失败类型与受影响范围。
我会先让较短的执行图可靠地完成任务,再针对一个已经观察到的瓶颈增加结构:探索覆盖不足就试并行,未知子问题反复漏掉就试动态委派,具体判断无法通过现有检查解决再试交流。一次改动需要一个能被记录和验证的目标。这样,保留或移除某个 Agent 都有依据。