主题 14 · 多 Agent 与编排模式#
定位:从 Anthropic 五模式到实际选型——为什么 DocMind 选 Orchestrator-Worker + 单 Agent 循环而不是 Multi-Agent,以及评估多 Agent 框架后放弃的经验
一、通用知识#
1.1 核心概念与原理#
多 Agent 架构四种拓扑
面试怎么讲:“多 Agent 不是一个东西,是一类设计模式。按 Agent 间的关系可以分四种拓扑。“
| 拓扑 | 机制 | 典型场景 | 优劣 |
|---|---|---|---|
| 层级(Supervisor→Workers) | 中心调度器分派任务,Worker 执行后汇报结果 | RAG 检索编排、客服系统 | 可控性强、调试清晰;瓶颈在 Supervisor |
| 扁平/对等 | Agent 间直接通信,辩论/投票/共识 | 代码审查、事实核验 | 去中心化、鲁棒性好;协调成本随 Agent 数量指数增长 |
| 市场/竞价 | Agent 竞标任务,调度器按”报价”分配 | 资源调度、多模型择优 | 天然负载均衡;实现复杂、bid 策略难调 |
| 流水线 | 串行传递,前一个输出是后一个输入 | 文档处理(提取→分类→生成) | 最简单、延迟可预测;无法并行、一步卡全链卡 |
Anthropic 五模式回顾
Anthropic 在 “Building Effective Agents”(2024)中提出五种从简到繁的构建块:
| 模式 | 机制 | 适用场景 |
|---|---|---|
| Prompt Chaining | 串行 LLM 调用,前一步输出是后一步输入 | 固定序列任务 |
| Routing | 分类后路由到不同子流程 | 输入类型差异大 |
| Parallelization | 多路并行后合并 | 多视角投票、分段处理 |
| Orchestrator-Workers | 中心调度器动态分派 Worker | 子任务动态不可预枚举 |
| Evaluator-Optimizer | 生成后评估、不达标重来 | 有明确量化评测标准 |
面试怎么讲:“Anthropic 的核心建议是从增强型 LLM 起步,只在需要时加复杂度。五种模式不是阶梯要一级级爬,而是工具箱——需要哪个拿哪个。大多数场景一个 LLM + 好工具 + 好 prompt 就够了。加 Agent 是加复杂度,复杂度要有明确收益才值得。”
单 Agent + 工具 vs 多 Agent 选型标准
核心判断问题:“子任务之间需要 Agent 间’对话’吗?”
- 如果 Worker 只需要”执行指令 + 返回结果”(像函数调用),用 Orchestrator-Worker 模式——Worker 不需要理解上下文,只需要执行一个明确的 API 调用
- 如果 Agent 间需要协商 / 辩论 / 迭代反馈(比如一个 Agent 写代码,另一个 Agent review 后要求改),才需要多 Agent
- 面试怎么讲:“区分标准很简单——Worker 是’函数’还是’对话者’。函数只需要参数和返回值,对话者需要理解上下文和意图。RAG 的检索 Worker 100% 是函数——给它 query 和 kbIds,它返回 chunks,完事。”
Agent 通信模式
| 模式 | 机制 | 耦合度 | 适用场景 |
|---|---|---|---|
| 共享状态(黑板模式) | 所有 Agent 读写同一状态对象 | 高 | Agent 数量少、需要实时同步 |
| 消息传递 | Agent 间发消息,松耦合 | 低 | Agent 可独立部署、数量可伸缩 |
| 函数调用 | Orchestrator 直接调 Worker | 最简 | Worker 是无状态函数 |
面试怎么讲:“DocMind 用的是函数调用模式——SupervisorAgent 直接 CompletableFuture.supplyAsync 调 Worker,Worker 返回 WorkerResult,没有消息队列、没有状态共享。最简单的就是最好的。”
多 Agent 的隐性成本
面试官经常问”为什么不用多 Agent”,核心答案是成本不止 token 费用,还有三层隐性成本:
- 延迟税:Agent 间每轮消息传递需要一次 LLM 调用来”理解”对方输出并产生下一步行动——3 个 Agent 串行协作最少 2 轮额外推理,按 qwen-plus 平均 0.8s/调用算就是 +1.6s 起步
- 调试税:Agent A 输出的自然语言被 Agent B “误解”导致下游错误——这种 bug 无法用断点调试,只能看日志推理,排查时间是确定性代码的 3-5 倍
- 一致性税:多 Agent 的最终输出依赖所有 Agent 的”共识”——任何一个 Agent 的输出波动都会传播到最终结果,系统整体的可复现性下降
面试怎么讲:“多 Agent 最大的问题不是贵,而是不可控。每多一个 Agent 就多一层 LLM 的不确定性。两个 Agent 各有 5% 的’跑偏率’,串联起来就是 ~10%——越多越不稳。”
Agent 状态管理
AgentState 承载整个执行过程的上下文:已尝试策略、累积证据、置信度轨迹、剩余预算。设计原则是最小化——只存决策必需的信息,不存中间过程的全文。具体来说:accumulatedEvidence 里只存 chunk 引用和分数,不存原始文档全文;confidenceTrajectory 只记分数不记全文。
为什么最小化很重要?两个原因:
- 性能:AgentState 在 agentic 循环的每次迭代中都要传给 LLM 做决策参考——状态越大,prompt token 越多,延迟越高
- 可调试性:状态小意味着日志可读——出了问题看 AgentState 的 JSON dump 就能定位是哪一步出错,不需要翻几十 KB 的中间结果
面试怎么讲:“状态管理的关键是只存决策需要的信息。比如 triedStrategies 是个 Set——Supervisor 看一眼就知道哪些 Worker 已经调过了不用重复。confidenceTrajectory 是个 List
1.2 业界主流方案对比(表格形式)#
表 1:多 Agent 框架对比#
| 框架 | 架构模式 | 语言 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|---|---|
| CrewAI | 角色分配 + 任务链 | Python | 角色定义直观、文档友好 | 角色间通信依赖 LLM 理解,延迟高;生产调试黑盒 | 快速原型、自动化工作流 |
| AutoGen | 对话式多 Agent | Python | 支持人机协作、Agent 间自由对话 | 对话轮次不可控、token 成本爆炸 | 研究探索、需要人工介入 |
| Swarm | 轻量 Agent 切换 | Python | 极简 API、Agent 间 handoff 自然 | 无持久化、无并行能力 | 客服路由、简单分流 |
| LangGraph | 状态图 + 条件边 | Python | 可视化强、状态转移可调试 | Python only;图定义 vs prompt 调试割裂 | 复杂 workflow、需要可视化 |
| 自研编排(DocMind) | Supervisor + Worker | Java | 与主栈统一、Worker 粒度可控、无框架黑盒 | 需要自己实现超时/降级/可观测 | Java 生态、RAG 场景 |
表 2:编排模式选型矩阵#
| 场景特征 | 推荐模式 | 理由 |
|---|---|---|
| 简单查询,一次检索够用 | 单次检索(RULE_PLANNER) | 最低延迟,规则确定性 100% |
| 多源并行(KB + Web + 记忆) | Orchestrator-Workers | fan-out 并行,Worker 间无依赖 |
| 需要 Agent 间辩论/交叉验证 | Multi-Agent | Agent 需理解对方输出、迭代反馈 |
| 固定流程(提取→分类→生成) | Prompt Chaining | 每步输出确定性高,串行最简 |
| 需要迭代改进(写作、代码) | Evaluator-Optimizer | 有明确的质量度量,改到达标 |
| 复杂/多焦点/多跳查询 | 单 Agent 工具循环 | 模型自驱拆解+多跳,省去多 Agent 协调 |
1.3 关键论文与技术要点#
| 论文 | 核心贡献 | 面试怎么用 |
|---|---|---|
| Anthropic “Building Effective Agents” (2024) | 五模式分类 + “从简单开始”原则 | ”我们的架构选型直接参考这篇” |
| AgentBench (Liu et al. 2023) | 8 个环境的 Agent 基准测试 | ”Agent 能力差异巨大——不是所有 LLM 都适合做 Agent” |
| Generative Agents (Park et al. 2023) | 25 个 Agent 社会模拟,记忆 + 反思 + 规划 | ”展示了多 Agent 交互的上限——但延迟和成本也是上限” |
| CAMEL (Li et al. 2023) | 角色扮演框架,Agent 间通过”inception prompting”对话 | ”证明了 Agent 间通信需要额外 LLM 调用——这正是我们放弃的原因” |
| Agentic RAG Survey (arXiv 2501.09136) | 系统综述 Agentic RAG 模式 | ”Survey 确认了 single-agent + tools 对 RAG 足够” |
编排三原则:
- 最简架构够用就不加 Agent——每加一个 Agent 就多一轮 LLM 调用、多一层调试黑盒。DocMind 从 5 种路径收敛到 3 种就是这个原则的实践
- Worker 独立超时 + 独立降级——一个 Worker 挂了不影响其他 Worker 的结果。
withWorkerTimeout用orTimeout + exceptionally返回空 Evidence,不抛异常不阻塞 - 状态最小化——AgentState 只存决策必需信息,中间过程的全文不存。
confidenceTrajectory只记分数(每个 Double 8 字节),不记每轮的完整 chunks
面试怎么讲:“这三条原则不是从论文抄的,是踩坑总结的。第一条是做了 CrewAI PoC 后的结论,第二条是线上 WebWorker 偶发超时倒逼出来的,第三条是 AgentState 序列化到 Redis 超 1MB 报警后加的。“
1.4 常见面试问答#
Q1:什么时候用多 Agent,什么时候用单 Agent?
关键区分:“子任务之间需要 Agent 间对话吗?“RAG 场景的 Worker 只需要”给 query 返 chunks”——这是函数调用,不是对话。单 Agent + 多工具就够了。多 Agent 的场景是:一个 Agent 写代码、另一个 review、第三个写测试——它们之间需要理解对方的输出并迭代。
Q2:Worker 之间需要共享状态吗?
DocMind 的 Worker 完全无状态——状态全在 AgentState 里。Worker 执行完把 Evidence 返回给 SupervisorAgent,由 Supervisor 统一融合。Worker 间不通信、不共享——所以可以 CompletableFuture 并行。
Q3:为什么不用 CrewAI / LangGraph?
三个原因:(1) Python only,和 Java 主栈集成需要 REST bridge,运维复杂度翻倍 (2) 框架的抽象层掩盖了真正的问题——出 bug 不知道是 prompt 错了还是框架的状态转移错了 (3) RAG 场景的 Worker 是函数不是对话者,不需要框架提供的”Agent 间通信”能力。
Q4:Agent 状态管理怎么设计?
最小化原则。AgentState 有 20+ 字段但每个都有明确用途:triedStrategies 避免重复调度、confidenceTrajectory 判断置信度是否收敛、remainingBudget 控制 token 上限。不存中间全文——accumulatedEvidence 只存 chunk 引用和分数。
Q5:多 Agent 调试为什么难?
三重黑盒叠加:(1) 每个 Agent 内部的 LLM 推理不可预测 (2) Agent 间消息传递的语义理解不确定 (3) 全局状态的最终一致性难保证。单 Agent + 多工具只有第 (1) 层,其他都是确定性代码。
Q6:编排框架 vs 自己写代码?
看你的编排逻辑复杂不复杂。如果是 DAG(有向无环图)——LangGraph 的可视化确实有价值。但如果是 fan-out + 合并这种简单模式——Java 的 CompletableFuture.allOf 三行代码搞定,不需要框架。框架有价值的地方是状态持久化和重试——但 DocMind 的检索是秒级操作,不需要持久化中间状态。
二、DocMind 实践#
30 秒口述版#
“DocMind 的编排层有三个核心设计。第一是 PathDecision 三模式路由——SELECTED_DOC 直读零检索、RULE_PLANNER 走规则引擎加多 Worker 并行一次性检索、AGENTIC 走 LLM 工具调用循环,85% 简单查询走快速路径不进 Agent。第二是 SupervisorAgent 的 Orchestrator-Worker 并行——RetrievalWorker、WebWorker、MemoryWorker 用 CompletableFuture 并行派发,每个 Worker 独立 orTimeout 15s 加 fallback,一个挂了其他正常用。第三是评估多 Agent 框架后选择自研——用 CrewAI 做了’检索加验证加生成’三角色 prototype,发现 Agent 间消息传递引入 2-3 轮额外 LLM 调用、延迟增加 3-5 秒,且验证 Agent 的 CRAG 判断不如硬编码阈值稳定。结论是 RAG 场景的 Worker 只需要’执行加返回’,不需要’理解对话加自主决策’。“
详细展开#
PathDecision 三模式路由
DocMind 的路径决策收敛为三种 Mode:
- SELECTED_DOC:用户选中了特定文档且意图是”读这份文档”——直接 DocumentDirectReader 按 chunk 均匀采样,零检索零 LLM
- RULE_PLANNER:SIMPLE 且非歧义查询——RetrievalPlanner 规则引擎选定工具集(doc_search + keyword_search + 可选 web_search/recall_memory),SupervisorAgent 一次性编排
- AGENTIC:所有中等/复杂/歧义查询——AgenticSearchOrchestrator 用真 LLM 工具调用循环,模型自驱拆解/多跳/补 Web/决定停止
面试怎么讲:“85% 的查询是简单问题——走 RULE_PLANNER 用规则引擎确定工具集,一次性检索,延迟 < 2s。只有 15% 的复杂查询才进 AGENTIC 循环——让 LLM 自己决定拆不拆、跳不跳、搜什么、何时停。这个比例不是拍脑袋——SIMPLE && !ambiguous 的判定是 QueryClassification 的 complexity 和 isAmbiguous 两个字段,分类器准确率在 90%+ 以上。”
SupervisorAgent 的 Orchestrator-Worker 并行
dispatchWorkers() 的实现非常直接:
- 根据 RetrievalPlan 确定需要哪些 Worker(
determineTools) - 每个 Worker 用
CompletableFuture.supplyAsync提交到线程池 - 每个 Future 用
withWorkerTimeout包装——orTimeout(15s)+exceptionally(fallback)返回空 Evidence CompletableFuture.allOf().join()等全部完成- 收集结果,按 Worker 类型分桶(vectorPart / bm25Part / webPart / memoryContext)
关键设计:部分降级而非整体失败——某个 Worker 超时,其他 Worker 的结果正常使用。CRAG 评分基于实际拿到的 chunks,不会因为 WebWorker 超时就整体报错。
withWorkerTimeout 的实现只有 4 行,但体现了 Orchestrator-Worker 模式最重要的工程约束——Worker 失败不应传播:
private <T> CompletableFuture<T> withWorkerTimeout(CompletableFuture<T> f, Function<Throwable, T> fallback) {
int timeoutMs = safeGetInt("retrieval.worker_timeout_ms", 15000);
return f.orTimeout(timeoutMs, TimeUnit.MILLISECONDS).exceptionally(fallback);
}java注意 fallback 返回的是 WorkerResult.failure(workerName, msg, 0),不是 null 也不是异常——下游代码用 wr.success() 过滤失败结果,成功的正常融合。
评估多 Agent 框架的过程
CrewAI PoC——实现了”检索 Agent + 验证 Agent + 生成 Agent”三角色 prototype:
- 检索 Agent 调 searchDocs 拿到候选 chunks
- 验证 Agent 对 chunks 做 CRAG 质量评估,决定是否需要补检索
- 生成 Agent 根据验证后的 chunks 生成最终回答
结果暴露三个问题:
- 延迟不可接受:Agent 间消息传递需要 LLM 理解对方输出,引入 2-3 轮额外 LLM 调用,端到端延迟从 ~2s 增加到 ~5-7s
- 验证不如硬编码稳定:验证 Agent 用小模型做 CRAG 判断,对 topScore 阈值的判断偏差 ±0.15——而 RetrievalGrader 直接比较
topScore >= threshold,精度 100% - 跨语言集成成本:Python CrewAI 和 Java 主栈之间需要 REST bridge,部署从一个 JAR 变成两个服务,运维复杂度翻倍
结论:“RAG Worker 是’执行指令 + 返回结果’的函数式角色——给 query 返 chunks,不需要理解上下文。函数式角色用函数调用模式(CompletableFuture)就够了,不需要 Agent 间通信框架。”
辩论式验证 prototype
还尝试了另一个方向:两个 LLM 实例对同一检索结果做”辩论式验证”——一个主张引用充分(advocate),一个专门挑刺(critic)。
结果:
- 确实多发现了 2/52 条不忠实回答——critic 指出了 advocate 忽略的细微矛盾
- 但每条回答多 2 次 LLM 调用,成本从 ¥0.012 涨到 ¥0.036(×3)
- 对比 CitationParser 的覆盖率检查——纯 Java 正则解析
[n]标记,0 成本 0 延迟,也能发现大部分未引用的幻觉
决策:2/52 ≈ 3.8% 的增量收益 vs ×3 的成本——投入产出比不如 CitationParser,放弃。但保留了一个备选方案:如果以后幻觉率上升,可以只对 CRAG-LOW 的回答触发辩论——选择性触发而非全量触发,成本可接受。
为什么最终选择自研而非框架
总结下来就是一句话:DocMind 的编排逻辑不复杂,不需要框架来管理复杂度。具体来说:
- 编排拓扑是 fan-out + 合并——
CompletableFuture.allOf三行代码搞定 - Worker 是无状态函数——不需要框架提供的”Agent 生命周期管理”
- 失败恢复是返回空结果——不需要框架提供的”重试/检查点/回滚”
- 可观测性用 OpenTelemetry span——不需要框架提供的”LangSmith/LangFuse 集成”(我们已经自己接了)
面试怎么讲:“自研的好处是每行代码都是自己写的,出 bug 5 分钟能定位。用框架的话,框架内部的状态转移、回调注册、生命周期钩子加起来几千行——出 bug 你先花 30 分钟读框架源码。“
代码锚点#
| 类/方法 | 路径 | 职责 |
|---|---|---|
PathDecision | agent/PathDecision.java | 三模式路由 record(SELECTED_DOC / AGENTIC / RULE_PLANNER) |
SupervisorAgent.oneShotRetrieval() | agent/supervisor/SupervisorAgent.java | 一次性检索编排入口:调度→融合→重排→压缩→CRAG |
SupervisorAgent.dispatchWorkers() | 同上 | CompletableFuture 并行 Worker 派发 |
SupervisorAgent.withWorkerTimeout() | 同上 | Worker 独立 15s 超时 + fallback 返回空 Evidence |
RetrievalWorker.execute() | agent/worker/RetrievalWorker.java | Vector + BM25 → RRF → Cross-Encoder → MMR → CRAG |
WebWorker.execute() | agent/worker/WebWorker.java | Tavily 联网检索 → RetrievedChunk(Source.WEB) |
MemoryWorker.execute() | agent/worker/MemoryWorker.java | Redis 语义记忆召回 → memoryContext |
AgentState | agent/state/AgentState.java | 完整状态载体:20+ 字段、triedStrategies/confidenceTrajectory/remainingBudget |
量化数据#
| 指标 | 数值 | 基线/对比 | 来源 |
|---|---|---|---|
| PathDecision 模式数 | 3 种 | 5 种(含已删的 MULTI_HOP / DECOMPOSED) | PathDecision.Mode |
| Worker 并行度 | 3 个(Retrieval + Web + Memory) | — | dispatchWorkers() |
| Worker 超时 | 15s(可配置) | — | withWorkerTimeout |
| 规则路径覆盖率 | ~85% 查询 | — | SIMPLE && !ambiguous |
| CrewAI prototype 延迟增加 | +3-5s | 原链路 ~2s | Agent 间消息传递 2-3 轮额外 LLM 调用 |
| 辩论 prototype 成本增加 | ×3(¥0.012 → ¥0.036/条) | — | 2 次额外 LLM 调用 |
| 辩论 prototype 额外发现 | 2/52 条不忠实 | ~3.8% 增量 | critic 角色 |
| AgentState 字段数 | 20+ | — | AgentState.java |
| Agentic 循环最大迭代 | 4 轮(默认) | — | agentic.max_iterations |
| 验证 Agent CRAG 判断偏差 | ±0.15 | 代码阈值精度 100% | CrewAI PoC |
| 辩论触发后端到端延迟 | ~6s | 原链路 ~2s | 2 次额外 LLM 推理 |
三、追问应对#
面试官想听到的信号#
- 架构选型有评估有数据:不是”凭感觉选的 Orchestrator-Worker”,而是”做了 CrewAI 三角色 PoC 和辩论式验证 prototype,对比延迟/质量/成本后决定的”
- 理解多 Agent 的真实代价:延迟(Agent 间消息传递需要额外 LLM 调用)、成本(每多一个 Agent 多一次推理)、调试复杂度(三重黑盒叠加)
- 知道何时够用就停:Worker 模式够用就不升级到多 Agent——“加 Agent 是加复杂度,复杂度要有明确收益才值得”
- 对框架有自己的判断:不是”不会用 CrewAI/LangGraph”,而是”评估后这个场景不需要”
追问预判与应答#
Q1:CrewAI 评估具体怎么做的?
实现了三个角色:检索 Agent 调 searchDocs、验证 Agent 做 CRAG 评分、生成 Agent 产出回答。跑了 50 条测试 query 对比两条路径。核心发现是 Agent 间消息传递需要 LLM “理解”对方的输出——这个”理解”就是额外的推理调用,直接多了 2-3 轮,延迟从 2 秒到 5-7 秒。验证 Agent 用小模型做 CRAG 判断偏差 ±0.15,而代码里直接
topScore >= 0.55精度 100%。结论是:CRAG 是阈值比较,不是需要”理解”的任务——用代码比用 Agent 更合适。
Q2:辩论式验证为什么放弃?
2/52 条额外发现(3.8%)vs ×3 的成本——算账算不过来。更关键的是 CitationParser 的覆盖率检查是纯 Java 正则,0 成本 0 延迟也能发现大部分”引用了但没根据”的幻觉。辩论 prototype 的 2 条额外发现是”细微语义矛盾”——确实更深入,但这 3.8% 的增量不值 ×3 的成本。如果以后幻觉率上升到需要更强验证,可以只对 CRAG-LOW 的回答触发辩论——选择性的成本可接受。
Q3:Worker 超时后怎么处理?会丢失结果吗?
withWorkerTimeout用orTimeout(15s)让 Future 异常完成,exceptionally(fallback)返回空 Evidence。其他 Worker 的结果正常使用——部分降级而非全挂。比如 WebWorker 超时了,RetrievalWorker 的 chunks 照常进 RRF 融合和 Cross-Encoder 重排。CRAG 评分基于实际拿到的 chunks——少了 Web 的 chunks 可能分数略低,但不会报错。
Q4:如果以后确实要加多 Agent 怎么扩展?
PathDecision 加第四种 Mode(比如 MULTI_AGENT),新的编排层和现有 Worker 正交——Worker 接口不变,编排逻辑可替换。Worker 的
execute(WorkerRequest): WorkerResult接口足够通用,不管是 SupervisorAgent 调还是某个 Agent 框架调,Worker 不用改。这也是 Orchestrator-Worker 模式的好处——编排层和执行层解耦。
Q5:LangGraph 考虑过吗?
考虑过。LangGraph 的状态图可视化确实很好——能看到每个节点的输入输出。但三个问题:(1) Python only,Java 生态没有对应物 (2) 图定义 vs prompt 调试割裂——出 bug 不知道是状态转移条件写错了还是节点里的 prompt 写错了 (3) DocMind 的编排逻辑就是 fan-out + 合并,Java 的 CompletableFuture 三行代码搞定,不需要图引擎。如果编排逻辑以后变成复杂 DAG,会考虑 Java 生态的 Temporal 或 Cadence——但那是 workflow engine,不是 Agent framework。
Q6:Agent 状态(AgentState)膨胀怎么管理?
最小化原则,三层控制:(1) 字段层——只存决策必需信息,
accumulatedEvidence存 chunk 引用和分数不存全文 (2) 预算层——remainingBudget控制上下文 token 总量,超预算时CrossEncoderReranker.compress(原 ContextCompressor 已下沉)做 query-aware 截断 (3) 生命周期层——extraParams每轮迭代后清空;hopQaPairs是早期自研串行多跳的遗留字段(多跳已收敛进 agentic 循环、该编排已删,字段现恒空,属待清理的死字段)。20+ 个字段里大多数在当前路径下是空的。
Q7:Worker 之间为什么不需要通信?
因为每个 Worker 做的事情是独立的——RetrievalWorker 搜知识库、WebWorker 搜互联网、MemoryWorker 查记忆,它们之间没有数据依赖。结果的”交叉验证”在融合层做——Cross-Encoder rerank 在同一标尺下给 KB chunks 和 Web chunks 打分,自然做了跨源排序。这正是 Anthropic Orchestrator-Workers 模式的标准实现:Worker 独立执行,Orchestrator(SupervisorAgent)负责合并。
Q8:Agentic 循环和 Worker 并行是什么关系?
两条路径、同一套工具。RULE_PLANNER 走 SupervisorAgent.oneShotRetrieval()——Worker 并行一次性检索,确定性编排。AGENTIC 走 AgenticSearchOrchestrator——LLM 工具调用循环,每次工具调用实际上也是调同一组检索工具(searchDocs/keywordSearch/webSearch/recall_memory),agentic 还额外挂 executeCode 沙箱计算工具(one-shot 不挂),但由 LLM 决定调什么、调几次、什么时候停。两条路径共享检索工具定义和融合管道(Cross-Encoder rerank → MMR → 压缩 → CRAG)。Agentic 异常或空结果时 fallback 到 oneShotRetrieval——这个 fallback 机制本身就是”最简架构够用就不加复杂度”的体现。
Q9:如果 Worker 数量增多(比如加了数据库查询 Worker),编排层需要改什么?
Worker 接口是
execute(WorkerRequest): WorkerResult——新 Worker 实现这个接口就行。dispatchWorkers()里加一个if (tools.contains(newToolName))分支提交到线程池。融合层不用改——RRF 对任意数量的 chunk 列表都能融合。唯一要注意的是withWorkerTimeout的超时值可能需要按 Worker 类型差异化——比如数据库查询可能只需要 3 秒,Web 检索需要 15 秒。
反击引导#
- “编排模式和工具设计是一体的——工具越简单,编排越灵活。Worker 只要调工具就行,不需要理解工具。”(→ Story 09 工具设计与 Function-Calling)
- “三模式路由的收敛过程其实就是架构收敛的故事——从 5 种路径到 3 种,每删一种都有具体原因。”(→ Story 07 架构收敛)
- “Worker 独立超时是全链路降级 10 层之一——每层独立兜底,不级联失败。”(→ Story 08 全链路降级)
- “Agentic 循环的 LLM 工具调用其实就是 Function Calling 的最佳实践——system prompt 里写清策略、白名单硬排除写工具、手动控环限迭代。”(→ Story 09 工具设计与 Function-Calling)
- “PathDecision 的三模式分流也是一种 Routing 模式——Anthropic 五模式里最基础的那个,但我们是用代码规则而非 LLM 做分流。”(→ Story 11 Prompt Engineering 实践)