Skip to content
预计 1 分钟右侧目录可快速定位

常见编排模式怎么选:Router、Fan-out、Manager 与 Handoff ​

前置:Plan 如何进入 Runtime:Graph Compilation 与 Code / LLM Orchestration
核心问题:同一个任务该用 Router、Fan-out、Manager 还是 Handoff,选择它们时真正变化的是并发、控制权还是 Context ownership?

代码问题→coding agent,账户问题→workflow;低置信分类可走 generalist,而不是强制错误分支。同时让三个检索器查不同数据源,返回后去重/排序再生成答案;某一路超时是否允许用另外两路继续由 policy 决定。

Router Pattern ​

Router 适合“候选路径有限、先分类再执行”的场景。输出最好是结构化枚举,例如:

text
CODING | ACCOUNT | GENERAL

低置信时走 fallback,比强制进入一个错误专家更安全。如果为了决定路由本身就要搜索十几个来源、反复推理,说明问题已经超出 Router,应该升级为 Planner/Agent。

🔍 源码对照:真实 Router 同时处理 provider 差异和 Turn 顺序 ​

精确定位

ts
function dispatchSendPrompt(agentId, request) {
  const previous = queues.get(agentId) ?? Promise.resolve()
  const next = previous
    .catch(() => undefined)
    .then(() => execute(currentProvider(), request))

  queues.set(agentId, next.finally(() => clearIfCurrent(agentId, next)))
}

async function execute(provider, request) {
  const bridge = provider === "claude-code" ? await createMcpBridge() : null
  return runRoutedProviderText(provider, messages, bridge ? { mcpServerUrl: bridge.url } : { tools })
}

对照理解

  • Router 先读取当前 provider,再把同一 agent 的请求串进 per-agent Promise queue,避免 Turn 顺序被并发打乱。
  • Claude Code 走本地 MCP bridge,而其他 provider 可以直接获得 Tool definitions;这是 provider capability adaptation,不是通用 fallback 算法。
  • Routing 是调用前选择路径;队列、transcript 持久化、stream update 则属于 coordinator/runtime 责任。

源码说明

inference-router.ts 把 provider selection、transcript、streaming 和 tools 组合在同一路由边界;仓库同时又有 subagent-runtime.ts 与 multitask 入口。这是一个提醒:Router、Fan-out、Handoff 经常横跨 model capability、state ownership 和 execution lifecycle,而不是只在 Prompt 里写“请分给三个专家”。

工程边界

该项目的 provider router 与 Agent orchestration 不是同一概念。阅读时要主动分离“选择哪个模型/Provider”和“把哪个工作单元交给哪个 Agent/Node”。

Shadow Harness 对照

  • Router 输出结构化 routing decision,Runtime 才创建/调度执行单元。
  • fan-out 必须定义 join condition、failure policy 与 context ownership。

验证

同一个任务分别走 deterministic router、LLM router、parallel fan-out,记录路由准确率、额外 token、latency 和失败传播差异。

Fan-out / Fan-in ​

Fan-out 适合独立子任务并行,Fan-in 负责聚合并处理 partial failure、排序和冲突。不要并行有隐含写依赖的任务。关键是定义子任务是否真正独立、并发上限、partial failure policy 和聚合 contract;如果子任务有隐藏共享状态或顺序依赖,盲目并行会产生 race 或重复副作用。

Planning-side Manager vs Handoff ​

两者最容易混淆,但核心区别是 谁继续拥有控制权和上下文:

  • Manager 调专家后,专家结果回到 Manager,由 Manager 决定下一步并最终回复;
  • Handoff 把后续交互 owner 转给 specialist,新 Agent 获得约定的上下文和能力边界。

因此它们会直接影响 context ownership、Tool capability、Trace parentage,以及失败后“返回谁继续处理”。

四种模式真正不同的是控制权和合并点 ​

可以把常见编排模式放在两条轴上理解:谁决定下一步,以及结果在哪里合并。

text
Router      → 选择一个分支
Fan-out     → 同时启动多个独立分支,之后 Fan-in
Manager     → 中央 Agent 持续分配/检查子任务
Handoff     → 控制权转给另一个 Agent,后者继续推进

例如“判断问题属于 billing 还是 technical support”更像 Router;“同时分析 10 个互不依赖文件”适合 Fan-out;如果子任务需要中央协调共享目标,则 Manager 更自然。

不要因为“多 Agent”听起来高级就使用 Handoff/Manager。若控制路径本来是确定的,代码 Router/Fan-out 通常更便宜、更容易测试。

Fan-out 之前先证明子任务真的独立 ​

三个搜索数据源可以并行,因为彼此没有写依赖;“修改代码 → 运行测试 → 部署”不能为了速度做 fan-out。Planner/Compiler 应把 dependency 显式化,Runtime 只并行 READY 节点。

Fan-in 还要定义 partial failure:三个来源坏一个,是继续用两路结果、重试失败分支,还是整体失败。这个决定属于 plan/domain policy,而不是 asyncio.gather() 的异常参数。

关联源码 ​

自测 ​

  1. 一个请求只是按类别选择单个专家,另一个请求需要并行收集三类证据。Router 和 Fan-out 分别更合适哪一个?
  2. Manager 与 Handoff 的核心区别是“Agent 数量”还是 control ownership?给一个不该 Handoff 的例子。

Sources ​

AI Engineering · Agent · Harness · Backend Systems