想象你是一家繁忙餐厅的总厨。客人点了一道“脆皮烤鸭配酸梅酱”,你不会自己一个人从头忙到尾——你会让帮厨去清洗鸭子、让烧烤师傅掌控火候、让酱料师调制蘸酱、让传菜员在最佳时机上桌。每个环节都有专人(工具)负责,而你作为总厨(Agent),心里装着整张菜单和流程,知道谁先谁后、什么条件该叫谁上、哪一步需要确认。如果烤鸭糊了,你会立刻叫烧烤师傅重烤;如果客人多,你会让多个灶台同时开工。这就是“工具编排”——让AI Agent像总厨调度后厨一样,按照预定计划有序地组合多个工具,完成复杂任务。 本文将用“餐厅后厨”这个比喻贯穿始终,带你理解工具编排的核心模式(顺序、条件、循环、并行)、状态如何传递、依赖如何处理、异常如何恢复,以及实战设计原则。学完你会明白:为什么说“工具编排是Agent从'能说话'到'能办事'的关键一跃”。
对于AI从业者:工具编排是构建多工具协作Agent的核心能力,掌握它意味着你能把零散的API调用变成可靠的业务自动化流程,这是成为高级AI应用工程师的关键技能。
可视化演示
动态演示工具编排的核心机制,通过全局/局部/动态/静态四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
工具编排:工具编排 工具编排总览与核心编排模式 顺序执行与条件分支编排实践 核心机制可视化 工具编排整体架构与关键组件
工具编排基础
作为总厨,你手里有一份“后厨协作手册”——它规定了什么菜该经过哪些厨师的手、每道工序负责什么、出现问题找谁。这份手册就是“编排”。如果只有一位厨师,一手包办洗切炒,那就不需要手册;但现实是,一个复杂任务(做一桌宴席)必然涉及多个专长(食材采购、清洗、刀工、火候、摆盘),必须有人统筹规划。AI Agent 也是如此:单个工具能力再强也有边界,工具编排的价值在于把“单点能力”变成“流程能力”。
技术视角来看,工具编排(Tool Orchestration)是指 Agent 依照预设流程或动态规划,依次或并行地调用多个工具(API、函数、服务),并协调它们之间的数据流与控制流。一个最简单的编排就是顺序调用:先调用工具A,把A的结果作为参数传给工具B。但真实场景中,编排要处理条件判断(库存不足怎么办)、循环(批量处理客户名单)、并行(同时查询多个供应商价格)、异常(API超时怎么办)等复杂逻辑。
从工程师的角度,编排层就像后厨的“传菜铃”和“看板”——它不关心每道菜怎么炒(工具内部实现),只关心工序之间的衔接、资源和结果的流动。成熟的 Agent 框架(如 LangChain、AutoGen)都内置了编排引擎,而理解编排的核心模式,是你自己设计复杂 Agent 的基础。
一场宴会如果只有一道菜,你不需要编排;但如果你要做一桌酒席,没有编排就会乱成一锅粥。工具编排就是 Agent 的“后厨手册”,让每个工具在最合适的时机、以正确的方式被调用。
- 顺序执行最简单的编排模式,按步骤先后逐个调用。
- 条件分支根据中间结果决定走哪条支路。
- 循环迭代对一批数据反复执行同一工具。
- 并行执行无依赖的多个工具同时运行。
顺序编排
后厨里做“佛跳墙”绝不能先上桌再炖汤——流程顺序错了,菜品就废了。顺序编排就是“认准步骤、一步一步来”。它的核心特征是:后一个工具的启动依赖前一个工具的输出,前一步失败则整个流程中止。这种模式适合那些客观上存在先后逻辑的任务——比如“查询商品库存”必须在“生成订单”之前,因为你先要知道有没有货,才能决定是否下单。
在技术落地时,顺序编排通常用一个“任务队列”来实现:Agent 维护一个工具调用列表,依序取出执行,并将每一步的返回值存入共享上下文(即“传递挡板”)。比如,工具1返回 {"库存": 5},工具2 就能从上下文中读取 库存 这个变量来决定自己的参数。实现上相当于一个不可跳过的步骤序列,任何一步抛出异常,队列即停止。
LangChain 等框架中,这种编排被封装成 Chain(链),开发者只需声明步骤序列。你还可以为每步配置 max_retries(最大重试次数),但顺序本身的严格性是硬约束——换顺序就可能产生错误结果。这里的关键词是“依赖”:顺序编排的价值就在于,它天然保证了上游结果对下游可见。
“先洗菜、再切菜、最后炒菜”——顺序是刻在流程里的。顺序编排的价值就是这种“天然的先后依赖”,对于必须按部就班的业务流程(如订单处理、审核流、计费流程),它是最稳妥的编排方式。
o_i 会成为下一步 T_{i+1} 的输入,这就是“结果传递”的流水线。任何一环中断,整条流水线停摆。- 步骤队列按预定义顺序排列工具,形成执行队列。
- 结果传递每步输出写入上下文,供后续步骤读取。
- 失败中止任一步抛错,队列停止向后推进。
条件分支
餐厅每天会收到两类订单:普通散客单和宴会大单。散客,服务员直接下单即可;宴会,则必须请经理确认菜单、审核报价。处理方式完全不同。这就是“条件分支”——Agent 根据当前上下文(订单金额、用户类型、库存状态)判断走哪条工具路径。它让编排从“僵化的直线”变成了“灵活的路网”。
技术实现上就是一个 if-else(或 switch)逻辑:Agent 执行一个判断工具(或根据上一步返回值),如果满足条件X,则走工具A路径;否则走工具B路径。这要求编排层能够读取上下文中已有变量的值,并据此改变控制流。多数框架对此原生支持,如 LangGraph 的 conditional edges。
条件分支的威力在于“适应性”:一个订单处理 Agent 面对低价商品自动发货、面对高价值商品触发人工审核、面对库存不足的商品自动推荐替代品。每个分支是一段独立的顺序编排子流程,从而组合出了复杂的决策结构。设计时要注意设置完备的“默认路径”——当所有条件都不满足时,走兜底逻辑,避免流程“死在了岔路口”。
“宴会大单走经理审核,散客直接下单”——同一件事,条件不同路径就不同。条件分支让 Agent 不再是“一条道走到黑”,而是在每个关键节点上都像经验丰富的总厨一样:看一眼食材(数据),决定下一步怎么处理。
- 条件评估读取上下文中关键变量的值。
- 阈值比较将评估值与预置阈值比较,决定走向。
- 默认兜底所有条件未覆盖时,走预置的默认流程。
循环与并行
高峰期,后厨同时来了十桌客人点同一道菜。总厨有两种做法:一是一桌一桌慢慢做(串行);二是让三位厨师同时开灶,一锅给一桌(并行)。或者,面对“给1000个客户发通知”的任务,你显然是循环调用“发送通知”工具1000次。循环与并行是编排中处理“批量和并发”的两大法器。
循环迭代(Loop)用于对列表中的每个元素重复执行同一工具。伪代码逻辑是:从上下文中读取一个列表,遍历每个元素作为参数调用工具,把每次结果收集起来。并行执行(Parallel)则用于多个无依赖的工具调用同时进行——例如,Agent 需要同时查询汇率、库存和物流价格,三个调用互不依赖,并行发出可以极大缩短总耗时。在实现层面,并行可以用 Promise.all 或 ThreadPool 完成,并等待所有结果聚合后继续后续流程。
实际编排中,两者常常组合使用:“循环内每轮任务可并行”或“并行批处理每批数据”。比如批量处理100个订单,每批10个并行执行;又比如一个大循环中,每次迭代内部有多个无依赖查询可以并发。这种“嵌套编排”模式极大地提高了吞吐量,但实现复杂度也相应上升——要注意并行数限制、接口限流、结果顺序与合并。
高峰期总厨让三个灶台同时开火,一桌的菜和其他桌的菜同时在做。循环与并行,就是 Agent 版本的“多灶台策略”——逐批处理数据、并发优化耗时。用好这两招,你的 Agent 才能在真实负载下扛住大量调用。
- 循环遍历从上下文读取列表数据。
- 并行分派无依赖的工具调用同时下发。
- 结果聚合收集所有并行任务的返回结果。
状态传递
传菜员端着一盘菜从厨房走到前厅,如果没人告诉他这是哪桌点的,菜就送错了。在编排流程中,“状态”就是传菜员手里的托盘——它装着从第一步到当前步的所有关键信息。状态传递机制,决定了下游工具能否拿到上游的正确结果。
技术层面上,编排引擎维护一个“共享上下文”(Shared Context / State Store),本质是一个结构化的键值容器或 Pydantic 模型。每执行完一个工具,就把该工具的返回值写入上下文某些字段;后续工具的参数不再写死,而是从上下文中动态读取。例如:
1. 工具A返回 {"customer_name": "张三", "order_amount": 999}
2. 编排引擎将这个结果写入上下文
3. 工具B的参数声明为 customer_name={context.customer_name}
这就是“参数转换”与“结果聚合”的雏形。更复杂的场景中,工具A的输出字段名和工具B的输入字段名不一致,就需要一个映射层(如 from context.a_id to input.b_id)。LangChain 的 TransformChain、AutoGen 的对话历史机制都属于状态传递的实现。设计状态模型时要保持字段命名清晰、避免过度嵌套,否则后面调试会非常痛苦。
托盘上的每道菜都写着桌号;上下文中的每个字段都标着来源。状态传递是编排的“记忆系统”——没有它,每个工具都是“失忆的厨师”,做完一道菜就忘了之前的所有事。
- 写入状态工具执行完毕后,返回值写入共享上下文。
- 参数映射把上下文字段映射为下一个工具的参数。
- 状态版本化部分框架保留每一步的快照,便于回溯调试。
依赖与调度
“先有鸡还是先有蛋?”在后厨里这不是哲学问题——你当然先得买到鸡(采购工具),才能杀鸡(处理工具);先有食材,才能做菜。工具之间天然存在“依赖关系”:B 依赖 A 的输出,C 依赖 A 和 B 的输出。编排引擎必须能识别这些依赖,决定先调谁、再调谁、哪些可以同时调。这就是依赖与调度。
技术上,常用“有向无环图”(DAG)来表示工具间的依赖关系。图中每个节点是一个工具调用,每条边表示“必须先执行完上游才能执行下游”。调度器遍历 DAG,找出“入度为0”的节点先执行,执行完毕后“解锁”其下游节点,循环往复。这个算法就是经典的“拓扑排序”。
举个例子:做“番茄炒蛋”需要三个工具——买番茄、买鸡蛋、炒菜。买番茄和买鸡蛋互不依赖,可以并行;炒菜依赖前两者的输出。DAG 结构为 [买番茄, 买鸡蛋] → 炒菜,调度器会先并行执行两个“买”工具,等结果齐了再执行“炒”。在 Agent 编排中,DAG 往往不是静态预定义,而是 Agent 根据用户 request 动态规划生成的(如 ReAct 模式就是推理一步、执行一步)。
后厨挂着一张“工序图”:哪个菜等哪个食材、哪道菜和哪道菜可以同时做。DAG 就是这张图的工程表达。理解了依赖与调度,你就明白了 Agent 怎样在“万事俱备”时才启动某个工具,又怎样让无依赖的活儿齐头并进。
- 构建DAG将工具及依赖关系建模为有向图。
- 入度为零当前无前置依赖的节点可立即执行。
- 逐层解锁执行完的节点释放其下游节点的依赖锁。
异常恢复
再好的总厨也会遇到“食材不新鲜”“灶台起火”“客人临时改口味”——后厨的应急预案决定了一家餐厅能否在意外中存活。工具编排同样如此:API 会超时、第三方服务会挂、数据格式会变。异常恢复机制,就是编排层的“消防预案”,它决定了 Agent 在生产环境中的可靠性。
常见的恢复手段有三板斧:
1. 重试(Retry):对一次性、临时性故障(网络抖动、超时),在等待一小段时间后重新调用同一工具。通常配合指数退避(backoff),避免重试风暴。
2. 降级(Fallback):当主工具不可用时,切换到备用实现(如同一功能的备用 API、缓存值、默认结果)。比如查询天气的主 API 挂了,切到备用的天气 API。
3. 熔断(Circuit Breaker):当某工具连续失败 N 次,标记其为“熔断开路”,短时间内不再调用它,直接走降级逻辑,让服务有时间恢复。
实现这些策略,关键点在于区分“可重试错误”(超时、5xx)与“不可重试错误”(参数错误、鉴权失败)。前者值得重试,后者重试多少次都没用。同时,日志追踪(Logging)贯穿整个异常处理——每步调用的入参、出参、耗时、错误信息都应记录,否则异常发生后你根本无法定位是哪个环节出了岔子。
应急预案的核心不是“避免所有意外”,而是“意外发生后知道做什么”。异常恢复机制让 Agent 从“一摔就碎的花瓶”变成“推不倒的不倒翁”。在生产环境中,这三个字(重试、降级、熔断)能决定你的 Agent 是“能用”还是“好用”。
- 错误分类判断错误类型是否可重试。
- 计数与退避控制重试次数,并逐步增加等待间隔。
- 降级切换到备用重试耗尽后选择备用工具路径。
设计原则
最后,站在总厨的高度,总结一套“后厨管理哲学”。无论编排多复杂,几个设计原则能帮你保持系统健壮、可扩展、可维护:
1. 高内聚、松耦合:每个工具只做一件事、做好一件事;工具之间不直接依赖,只通过上下文通信。这就像切菜的只管切菜,炒菜的只管炒菜,两者通过“切好的菜盘”传递,而不是切菜的跑过去帮炒菜。
2. 幂等设计:同一工具用相同入参调用多次,结果一致(如 cancelOrder 重复执行不会重复扣款)。幂等是安全重试的前提——如果你不确定重复执行会出什么问题,就别轻易重试。
3. 快速失败(Fail Fast):如果前置条件不满足(如缺失关键上下文字段),第一时间抛出异常,而不是带着脏数据往下走。宁可早崩,不崩错地方。
4. 可观测性(Observability):每个工具调用的入参、出参、耗时、错误码全量打日志 + 链路追踪。分布式系统中,没有日志=没有眼睛。
这些原则不是写在 PPT 上的口号,而是每个做 Agent 编排的工程师每天都会踩的坑:不幂等的重试导致客户被扣两次款;隐式上下文耦合导致改了A工具破坏了B工具;不设快速失败导致脏数据一路污染到最终结果。反过来,遵循原则的系统,出问题时你能迅速定位、恢复,而且新工具接入只需实现一个接口,不需要改动整个流程。
总厨的管理哲学浓缩成一句话:每件事有人负责、每份材料有来源、每次意外有预案、每个环节有记录。工具编排的设计原则也是这样——它不会让你的流程“永远不坏”,但能保证你的流程“坏了也能快速修好,而且知道为什么坏”。
- 幂等校验重复执行不产生额外副作用。
- 上下文约束工具只能读取自己声明需要的字段。
- 全量日志每一步落日志,含入参出参与耗时。
AI 应用场景
供应链订单自动化
阶段:工具编排 → 顺序 + 条件分支
解决的问题:传统电商订单处理需要人工在多个系统中切换——ERP 查库存、财务算价格、物流下单,每单耗时 3-5 分钟。AI Agent 通过工具编排把这些系统 API 串成一条流水线:自动查库存 → 算价格 → 走审批(大单人工、小单自动)→ 下物流单,单均耗时降到 20 秒。
具体案例:某 B2B 电商平台接入编排 Agent 后,采购订单从进系统到发货全自动完成。库存不足时自动触发“找替代供应商”工具;金额超阈值自动转人工审批节点(条件分支)。整体订单处理效率提升了 12 倍,差错率降为原来的 1/5。
智能会议纪要自动执行
阶段:工具编排 → 顺序 + 循环 + 并行
解决的问题:传统会议后需要人工整理纪要、分发任务、设置提醒,耗时 1 小时/场。编排 Agent 自动串联语音转文字 → 摘要生成 → 任务提取(循环遍历每条 action item)→ 更新项目看板(并行调用 Jira、飞书、日历 API)。
具体案例:某互联网公司产品团队每周使用该 Agent 处理 40+ 场会议。Agent 识别出“张三负责跟进 PD 对接”,自动在 Jira 创建任务、给张三发飞书通知、在他日历上添加提醒。人工只需在最后确认一次“任务分配无误”,整个会后流程基本不需要人参与。
异常恢复驱动的数据同步服务
阶段:工具编排 → 异常恢复 + 重试/降级
解决的问题:多系统数据同步过程中,第三方 API 不稳定是常态。传统方案中断后需要人工介入恢复。编排 Agent 在同步链路上内置重试(指数退避)、降级(切备库)、熔断(隔离故障数据源)策略,并全程记录同步日志。
具体案例:某金融科技公司的清算系统每天凌晨从交易所拉取行情数据。某天交易所 API 连续超时,Agent 自动重试 3 次不成功后,切换至备用数据源完成拉取,并发送告警通知值班工程师。整个过程无人干预,账务处理准时完成。事后日志完整还原了故障链路,定位到是交易所网关配置变更所致。
Python 演示
class Context: """共享上下文对象,模拟后厨的'传菜托盘'。""" def __init__(self): self.store = {} def set(self, key, value): self.store[key] = value def get(self, key, default=None): return self.store.get(key, default) def check_stock(ctx): """工具: 查库存(模拟请求库存服务)""" stock = 15 ctx.set("stock", stock) print(f"[库存] 当前库存: {stock}") return stock def calc_amount(ctx): """工具: 计算订单金额(依赖库存步骤写入的上下文)""" qty = ctx.get("qty", 3) price = 50 amount = qty * price ctx.set("amount", amount) print(f"[价格] 数量={qty} 单价={price} 金额={amount}") return amount def place_order(ctx): """工具: 提交订单(依赖金额字段)""" amount = ctx.get("amount") if amount is None: raise RuntimeError("缺少金额字段,无法下单") print(f"[订单] 已提交, 金额={amount}") return "done" def request_approval(ctx): """工具: 大单走人工审批""" amount = ctx.get("amount") print(f"[审批] 金额={amount} 超阈值,转人工审批") def orchestrate(ctx, qty): """编排主控: 顺序执行 + 条件分支""" ctx.set("qty", qty) check_stock(ctx) stock = ctx.get("stock") if stock < qty: print("[编排] 库存不足,终止流程") return calc_amount(ctx) amount = ctx.get("amount") if amount > 500: request_approval(ctx) # 条件分支 else: place_order(ctx) # 默认路径 if __name__ == "__main__": demo_ctx = Context() orchestrate(demo_ctx, qty=3) print("--- 第二单(大额)---") demo_ctx2 = Context() orchestrate(demo_ctx2, qty=100)
class Context:共享上下文对象,是所有工具之间传递数据的“传菜托盘”。ctx.set / ctx.get工具通过这两个方法读写上下文,实现状态传递。def check_stock(ctx)第一个被调用的工具,把库存量写入上下文。stock = ctx.get("stock")后续逻辑从上下文读取上一步的结果。if stock < qty:条件分支:库存不足时终止流程,不执行后续步骤。if amount > 500:条件分支:按金额阈值走审批或自动下单路径。def orchestrate(ctx, qty)编排主控函数,决定了工具的执行顺序与分支逻辑。if __name__ == "__main__":可执行入口,分别演示小单自动下单与大单转审批。
常见误区
误区我以为工具编排就是把几个 API 按顺序一个个调用,写个 for 循环挨个执行就完事了,跟写普通脚本没什么区别。
正解顺序调用只是编排最基础的形态。真实编排包含条件分支(异常时走降级路径)、循环(批量处理)、并行(无依赖的调用同时发)、状态管理(上下文传递)和异常恢复(重试与熔断)。就像后厨不是“挨个上菜”,而是要根据订单情况灵活调度多个灶台、多个厨师,还要处理食材短缺等突发状况。
为何常见:因为入门教程演示的第一个例子往往是最简单的顺序调用,新手很容易把“最简单形态”误当成“全部内涵”,忽略了编排作为一个独立领域的能力边界。
误区既然 Agent 有智能,我告诉它“帮我把订单处理了”,它应该自己知道先查库存、再算价格、最后下单,不需要我写流程。
正解完全自由的工具调用(ReAct 模式)确实存在,但不可控——Agent 可能跳过关键步骤、调错参数、不处理错误。工程上的最佳实践是“预定流程 + 局部自主”:用编排定义好骨架(顺序、分支、异常处理),让 Agent 在骨架内做选择(如选择哪个分支),而不是把整个流程都交给自由发挥。就像总厨会把大框架定好,但允许烧烤师傅在烧烤细节上有自己的经验发挥。
为何常见:大模型表现出足够强的“推理能力”,让人误以为它可以像人一样“随机应变”完成所有事。但实际上模型输出的稳定性不足以支撑关键业务流程的可靠性要求。
误区我写编排时把所有中间结果都塞进一个全局字典里,谁需要谁就去取,反正能跑起来。
正解无节制的全局状态是灾难源头——字段命名冲突、版本混乱、并发写入丢数据、排查困难。正确做法是设计结构化上下文(如 Pydantic 模型),明确每个字段的写入方和读取方;并行任务各自维护局部状态,最后再聚合。就像传菜托盘上每道菜都标好了桌号,而不是所有菜混在一个大锅里随便盛。
为何常见:早期脚本编程养成的“全局变量爷”习惯被带到了 Agent 编排中。加上业务流程一急,先跑通再重构的心态让状态管理变成后期最大的技术债。
误区Agents 调用工具报错了就循环重试,重试 10 次总有成功的吧?实在不行再说。
正解盲目重试至少有三个坑:一是对不可重试错误(如参数格式错)重试多少次都是浪费;二是重试可能放大系统压力,让已经过载的服务雪上加霜;三是不幂等的工具被重复执行会产生脏数据(如重复下单扣款)。正确做法是对错误分类,超时、5xx 可重试,且用指数退避;参数错误直接失败返回;同时确保工具幂等。
为何常见:直觉上“错了就再来一次”是人之常情,就像菜没熟再回锅炒一下。但工程上没有“回锅”这么简单——每次重试都要考虑资源消耗、副作用和服务端压力。
误区既然 DAG 能表达依赖关系,我就把所有编排都建模成 DAG,搞张图全搞定。
正解DAG 适合表达“静态依赖 + 并行调度”,但很多场景并不适合:比如需要循环直到满足条件的流程(DAG 没有循环)、需要人机交互暂停审批的流程(图编译后难以挂起恢复)、动态分叉数不确定的流程。实际工程中,顺序、状态机、DAG、甚至事件驱动都是可选范式,要按流程特征选择。就像后厨的运作既有流水线(顺序)、也有看板(状态机)、还有会议调度(事件),不只有一张图。
为何常见:DAG 听起来“高级”且可视化效果也好,容易让工程师过度设计。但正如“手里拿着锤子,看什么都是钉子”,工具的流行遮蔽了需求本来的多样性。
面试题
Q1. 工具编排最基础、最核心的编排模式是哪种?
- A.条件分支
- B.顺序执行← 正确答案
- C.循环迭代
- D.并行执行
答案:B。顺序执行是所有编排的基础形态,它保证了上游结果对下游可见,是其他所有模式(条件、循环、并行)的骨架。就像做菜必须先切后炒,顺序是流程的底线。条件/循环/并行都是在顺序骨架上添加的控制流变体。
Q2. 在编排流程中,“共享上下文”的主要作用是什么?
- A.存储所有工具的源代码
- B.在不同工具步骤间传递状态与结果← 正确答案
- C.控制工具的并发数量上限
- D.存储用户的历史聊天记录
答案:B。共享上下文相当于后厨的传菜托盘,每完成一步就把结果放上去,下游工具从上面取自己需要的输入。它解决的是“步骤间数据如何流动”的问题(状态传递),与源代码管理、并发控制、聊天记录无关。
Q3. 当工具调用抛出“参数格式错误”异常时,正确的处理策略是?
- A.立即重试 5 次直到成功
- B.指数退避重试 3 次
- C.直接失败并返回错误信息← 正确答案
- D.切换到备用 API 再试一次
答案:C。参数错误属于不可重试错误——入参本身有问题,重试不可能成功,就像食材已经坏了,回锅多少次都是坏的。正确做法是快速失败并暴露清晰的错误信息。只有超时、5xx 这类临时性错误才值得重试或降级。
Q4. 两个工具之间没有数据依赖关系,以下哪种编排方式最合理?
- A.强制按顺序执行
- B.并行执行两个工具← 正确答案
- C.仅执行其中一个工具
- D.将两个工具合并为一个工具
答案:B。无依赖则并行是编排优化的基本策略,就像两个互不干扰的灶台可以同时开火。并行能把总耗时从 t1+t2 降为 max(t1,t2)。强制顺序浪费资源,只执行一个或强行合并则丢失了业务正确性或模块清晰度。
Q5. 下面哪种情况最适合使用“条件分支”编排模式?
- A.批量给 1000 个用户发通知
- B.大额订单转人工审批、小额订单自动通过← 正确答案
- C.同时查询汇率、库存和物流价格
- D.先查询库存再生成订单
答案:B。条件分支的核心是“根据上下文状态选择不同路径”。大额/小额走不同处理路径是典型场景。批量发通知属于循环迭代,同时查询多个价格属于并行执行,查库存再下单属于顺序执行。
Q6. 在工具编排中,依赖管理需要解决哪些问题?
- A.判断哪些工具可以并行执行← 正确答案
- B.确保上游工具执行完毕再执行下游← 正确答案
- C.避免循环依赖导致死锁← 正确答案
- D.提升单个工具的内部执行速度
答案:ABC。依赖管理的核心是“谁先谁后、谁可并行、不能有环”三个问题。DAG + 拓扑排序正是为了回答这三个问题。但单个工具本身的性能优化不在编排层的职责范围内,那是工具内部实现该考虑的。
Q7. 关于“幂等设计”在工具编排中的作用,以下说法正确的有?
- A.幂等是安全重试的前提条件← 正确答案
- B.幂等工具重复执行不会产生额外副作用← 正确答案
- C.所有工具都必须设计成幂等的
- D.幂等设计可以完全替代异常处理机制
答案:AB。只有幂等的工具,才能在失败后放心重试(执行两次等于执行一次),否则重试可能重复扣款/重复下单。但并非所有工具都天然幂等(如“发送验证码”重复发送有额外副作用),需要根据业务设计。且幂等只是可靠性的一环,异常处理还包括重试策略、降级、熔断等。
Q8. DAG 拓扑排序的意义在于?
- A.找出执行时间最长的工具
- B.为所有节点排出一个满足依赖顺序的执行序列← 正确答案
- C.计算工具调用的总成本
- D.决定每个工具的重试次数
答案:B。拓扑排序的结果是一个线性序列,满足“每条依赖边的起点都在终点之前”。调度器按这个序列执行,就能保证所有工具都在依赖就绪后才被调用。它不关心耗时、成本或重试,只关心“先后合法性”。
Q9. 设计 Agent 工具编排系统时,正确的设计原则包括?
- A.工具间高内聚、松耦合,只通过上下文通信← 正确答案
- B.上下文可被任意工具自由读写,保持灵活性
- C.关键工具调用全量记录日志与耗时,便于追踪← 正确答案
- D.前置条件不满足时,尽量用默认值继续执行
答案:AC。松耦合 + 可观测性是工程共识。A 对:工具只通过上下文打交道,避免隐式依赖。B 错:自由读写会导致状态混乱与技术债。C 对:全量日志是排查问题的眼睛。D 错:前置条件不满足应该快速失败,而不是带脏数据硬跑,否则错误会被放大到下游。