想象你是一家餐厅的老板,开业第一天,客人陆续坐满,菜单上有八十道菜。如果你一个人既洗菜、又切菜、又炒菜、又端盘,不出十分钟后厨就会乱成一锅粥。聪明的做法,是把“做出一桌菜”这个大目标,拆成“洗菜组”“切菜组”“炒菜组”“传菜组”各自的活,再按每个人的手艺和忙碌程度分派下去——这就是后厨的分工艺术。 多Agent协作系统,本质上就是一间“数字后厨”。当你给AI系统一个宏大目标(比如“写一份行业研究报告”),单个AI模型往往力不从心。真正的解法是:把大目标拆解成一个个可独立执行的小任务,分配给多个各有所长的Agent,让它们各司其职、彼此配合,最后再汇总成完整成果。任务分解,就是这间数字后厨里最关键的“开工仪式”——它决定了整个协作系统的效率、稳定性和最终质量。

岗位关联

掌握任务分解与分配,是构建复杂AI Agent系统的核心能力。无论你是设计自动化工作流、搭建多Agent平台,还是优化团队协作效率,这门“分活的艺术”都是你从单兵作战走向系统指挥的必修课。

目录
  1. 可视化演示
  2. 任务分解为何必要
  3. 分解策略模型
  4. 任务分配机制
  5. Agent间协调
  6. 依赖与调度
  7. 结果汇总
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示多Agent系统任务分解(根任务→子任务→Agent分配→结果汇总)及协调器双向通信协作架构。

本节配有交互动效(进入视口后自动加载,约 3KB)。

任务分解与分配 根任务→T1/T2/T3/T4子任务→A1/A2/A3/A4 Agent分配→结果汇总,层次化分解 T = Σ(sub_i), sub_i → Agent_i 任务分解是多Agent协作的前提,粒度控制决定执行效率

任务分解为何必要

设想后厨里只有一位全能厨师。客人点了一桌十道菜,他既要去仓库领食材,又要洗、切、炒、摆盘,每一道工序都亲力亲为。结果呢?客人等了四十分钟,第一道菜才上桌,后面的菜全都卡在“等锅”上。这就是单Agent系统的真实写照:模型上下文有限、计算资源固定、一次只能做一件事。面对庞大复杂的任务,单个Agent要么顾此失彼,要么直接“超时崩溃”。

任务分解(Task Decomposition)的核心,就是把一个宏大目标拆成若干可独立执行的小任务。它之所以是多Agent协作的前提,是因为只有拆开了,才能让多个Agent并行处理,才谈得上“分配”二字。拆解带来的收益非常直观:并行加速、单点复杂度下降、出错时可局部重试,甚至可以让不同Agent用各自擅长的工具处理最适合自己的子任务。

用一个量化视角来看,假设总任务为 T,拆成 n 个子任务,原本单人完成总耗时是各任务耗时之和;而并行执行时,理想总耗时就变为最长子任务的耗时。数学上可以这样表达:

回到餐厅比喻:拆解任务就像把“一桌菜”拆成“洗菜、切菜、炒菜、装盘”四道工序。洗菜和切菜可以同时由两个人做,但炒菜必须等切完才能开始——这个“等”就是依赖关系,也是后面要讲的重点。

T=∑i=1ntiT = \sum_{i=1}^{n} t_i
T并行=max⁡1≤i≤ntiT_{\text{并行}} = \max_{1 \leq i \leq n} t_i
公式解读:第一个式子说明“大任务 T 可以被拆成 n 个小任务,每个小任务耗时 t_i”;第二个式子说明“并行时,整体耗时只取决于最慢的那个子任务”。这就是“拆开来跑得更快”的数学依据。
  1. 总任务量化总任务 T 被拆成 n 个子任务,每个子任务 i 的耗时为 t_i。
    T=∑i=1nti\displaystyle T = \sum_{i=1}^{n} t_i
  2. 并行耗时上界当多个Agent并行执行时,整体所需时间等于所有子任务耗时的最大值,即最慢的环节决定总时长。
    T并行=max⁡1≤i≤nti\displaystyle T_{\text{并行}} = \max_{1 \leq i \leq n} t_i

分解策略模型

拿到一个复杂目标,怎么拆才合理?后厨的经验是:没有统一的切法。有的菜按流程拆,有的菜按品类拆。同样,任务分解有几种常见策略。

目标分解是最上层的策略:把大目标逐层细化成子目标。比如 “写行业报告” → “收集数据、分析数据、撰写正文、制作图表”。流程阶段拆分强调按先后顺序切分,适合流水线型任务,如 “数据采集 → 数据清洗 → 特征工程 → 建模 → 评估”。领域类型拆分则按专业知识分块,比如一份法律咨询报告可以拆成“合同法部分”“公司法部分”“知识产权部分”,各交给不同领域的Agent。

拆解粒度的把控是分解策略中最微妙的艺术。切得太粗,子任务仍然太大,单个Agent依然扛不动;切得太细,任务之间通信和汇总的协调成本反而超过并行收益。后厨里有个经验法则:一道菜如果十秒就能炒完,就不值得单独安排一个厨师。同样,一个子任务如果几秒钟就能完成,就不值得单独交给一个Agent。

数学上常把拆解粒度问题描述为一个优化问题:设协调开销为 C(n),它是子任务数量 n 的增函数;并行收益随 n 增大而增大,但边际递减。理想的 n\* 应使总成本最小:

回到后厨:如果客人只点了一盘拍黄瓜,你非要动用三个厨师、拆成五个工序,光传话的时间黄瓜就蔫了。拆解的智慧,在于“够用就好”——先按流程拆,遇到跨领域知识再按领域拆,最终让每个子任务的规模匹配单个Agent的能力边界。

n{\*} = \arg\min_{n} \left( \max_{1 \leq i \leq n} t_i + C(n) \right)
公式解读:这里的 n\* 是“最优子任务数量”。如果 n 太小,max(t_i) 很大;如果 n 太大,协调开销 C(n) 飙升。平衡点就是最优拆解粒度。
  1. 成本函数总成本 = 并行耗时中的最大值 + 协调开销 C(n),二者都是子任务数量 n 的函数。
    f(n)=max⁡1≤i≤nti+C(n)\displaystyle f(n) = \max_{1 \leq i \leq n} t_i + C(n)
  2. 取最小值最优子任务数 n\* 是使总成本 f(n) 最小的那个 n 值。
    \displaystyle n{\*} = \arg\min_{n} f(n)

任务分配机制

任务拆好了,下一步是“派活”。后厨里,主厨不会把切葱花的活交给大厨,也不会让一个已经炒着三个菜的厨师再去蒸鱼——这就是任务分配要考虑的两个核心维度:能力匹配和负载均衡。

能力匹配要求把任务分给最擅长它的Agent。文本总结交给语言模型Agent,精确计算交给代码解释器Agent,图片生成交给绘画Agent。负载均衡则关注每个Agent当前的工作量:一个Agent任务队列已经排了十项,就不要再给它派新活,否则它成为瓶颈会拖累整个系统。动态领取是另一种常见机制——把任务池开放,Agent完成当前任务后主动认领下一个任务,像外卖骑手抢单一样自然。

还有一个容易被忽视的点:避免重复。如果两个Agent同时处理同一个子任务,不仅浪费算力,还会在汇总时产生冲突。好比两个厨师同时做同一道菜,出来的口味可能完全不同。分配时需要通过“任务认领登记”机制确保每个任务有且仅有一个执行者。

一个简单的分配策略可以用“能力-负载”评分函数来描述:设 Agent j 对任务 i 的适合度为 s_ij,当前负载为 l_j,分配器选择得分最高的Agent:

回到餐厅:主厨派活时心里有本账——小张刀工好所以负责切菜,小李颠勺稳所以负责炒菜,同时谁手里菜少谁就多接一道。这样的后厨,每个人都在忙,但没有人忙到崩溃,也没有人闲到发呆。

assign(i)=arg⁡max⁡j(sij−λlj)\text{assign}(i) = \arg\max_{j} \left( s_{ij} - \lambda l_j \right)
公式解读:分配器给“能力分”加分,给“当前负载”减分(λ 是负载惩罚系数),最终把任务派给综合得分最高的Agent。这就像后厨派活时,既看谁最会做这道菜,又看谁现在最闲。
  1. 适合度与负载s_ij 表示 Agent j 做任务 i 的擅长程度,l_j 表示 Agent j 当前的忙碌程度,λ 是一个调节系数。
    score(i,j)=sij−λlj\displaystyle \text{score}(i, j) = s_{ij} - \lambda l_j
  2. 选最优Agent对同一个任务 i,计算所有Agent的 score,把任务分配给得分最高(argmax)的那一个。
    assign(i)=arg⁡max⁡jscore(i,j)\displaystyle \text{assign}(i) = \arg\max_{j} \text{score}(i, j)

Agent间协调

活分下去了,但Agent之间不是各干各的就能完成一桌菜。后厨里,传菜窗、叫菜声、黑板上的快捷菜单,都是协调工具。多Agent系统同样需要协调机制,否则就会出现两个Agent抢同一个数据库、或者前一个任务没完成后面已经开始空转的局面。

共享黑板(Blackboard) 是最经典的协调模式:所有Agent在一个公共区域读写状态信息,就像后厨墙上挂的小白板,写着“3号桌已上齐”“5号桌催菜”。每个Agent干完活,往黑板更新一笔;需要别人配合时,也先在黑板上看一眼最新状态。消息传递则是点对点的通信,一个Agent直接给另一个Agent发消息:“你切的土豆丝我这边要用了”或“我蒸的鱼好了,叫你那边上菜”。

协商机制解决的是冲突问题:两个Agent都需要同一个资源(比如同一个GPU、同一份文件)时,通过协商裁决给谁先用。后厨里,蒸锅只有一个,蒸鱼和蒸蛋撞车时,主厨拍板“先蒸鱼,客人在催”。协商可以是集中式裁决(有主控Agent),也可以是分布式协议(Agent间按优先级互让)。

数学上,协调协议通常用状态机来描述:每个Agent在“等待→就绪→执行→报告”之间转换,全局状态保持一致:

餐厅打烊前的真实场景:蒸锅只有一个,但需要蒸的菜有三桌。传菜窗的小黑板写着每桌的上菜进度,两位厨师互相喊一嗓子“你的鱼我先用锅了”,冲突就消解了。协调不是额外的工作量,而是让分工真正无缝咬合的润滑剂。

Sj:idle→receive_taskbusy→notify_doneidleS_j: \text{idle} \xrightarrow{\text{receive\_task}} \text{busy} \xrightarrow{\text{notify\_done}} \text{idle}
公式解读:每个Agent是一个简单的状态机,接收任务进入忙碌,完成任务通知外界后回到空闲。这条循环就是协调机制的最小单元——而黑板和消息传递让这些状态对全局可见。
  1. 状态转移Agent j 的状态从空闲(idle)开始,收到任务后转为忙碌(busy)。
    Sj:idle→receive_taskbusy\displaystyle S_j: \text{idle} \xrightarrow{\text{receive\_task}} \text{busy}
  2. 完成回闲任务完成后,Agent 发出通知(notify\_done),状态回到空闲,准备接下一个任务。
    busy→notify_doneidle\displaystyle \text{busy} \xrightarrow{\text{notify\_done}} \text{idle}

依赖与调度

任务之间往往不是完全独立的。后厨里,炒菜必须等切好的食材;切菜必须等洗好的菜。这种“必须先做A才能做B”的关系,就是任务依赖。盲目并行会让Agent在等待中空转,甚至形成死锁——A等B完成,B等A完成,谁也不动。

建模任务依赖最自然的工具是有向无环图(DAG),叫依赖图:每个节点是一个子任务,每条边 A→B 表示“B 依赖 A”。判断哪些任务可以并行、哪些任务必须先等,就转化为在DAG上做拓扑排序:只要一条边 A→B 存在,A 就必须排在 B 前面执行。

拓扑排序保证所有任务按依赖顺序执行。设任务 i 的最早开始时间为 ES_i,它由所有前置任务的最早完成时间决定:

关键路径是依赖图中最长的路径,它决定了整个项目的最短完成时间。识别出关键路径上的任务,调度器就知道哪些任务千万不能延误。死锁预防则要求:分配任务时确保依赖图无环,同时设置超时机制——一个Agent等待太久就主动上报,让调度器介入。

后厨的经验是“切配先行”:洗好的菜要提前备好放在案板上,炒菜师傅来了直接下锅。依赖调度本质上是“把等待变成计划”——提前识别谁等谁,再把等待时间压缩到最短。

ESj=max⁡i∈pred(j)(ESi+ti)ES_j = \max_{i \in \text{pred}(j)} (ES_i + t_i)
公式解读:一个任务的最早开始时间,等于它所有前置任务中“最晚完成”的那个时间。这就像等菜:一桌菜里最后一道备齐了,这桌才能开炒。
  1. 前置任务集pred(j) 表示任务 j 所依赖的全部前置任务集合。
    pred(j)={i∣i→j}\displaystyle \text{pred}(j) = \{ i \mid i \to j \}
  2. 最早开始时间任务 j 的最早开始时间 ES_j,是 max 在所有前置任务 i 的“开始时间+耗时”上取最大值。
    ESj=max⁡i∈pred(j)(ESi+ti)\displaystyle ES_j = \max_{i \in \text{pred}(j)} (ES_i + t_i)

结果汇总

所有子任务完成后,还差最后一步:把各Agent的成果拼成一桌完整的菜。如果每个Agent做完直接撒手不管,系统得到的就是一堆碎片。

结果收拢是第一步:统一收集所有Agent的输出,按任务编号或依赖关系整理。去重合并解决重复问题:如果两个Agent基于同一份数据各自得出了结论,需要判断是取其一、取并集、还是融合成更全面的观点。后厨里,两道菜用了同一锅高汤,那高汤只需要熬一次。质量校验则是检查每个子任务的产出是否符合标准,不合格的要打回重做——相当于主厨在出菜前尝一口,淡了就加盐。最后是统一输出:把零散结果按统一格式拼装成最终交付物,保证接口一致。

结果汇总可以用一个整合函数来描述:设各Agent的产出为 r_1, r_2, ……, r_n,最终结果 R 是对它们的整合:

回到餐厅,最后的摆盘检查就是汇总:传菜员核对每桌菜品是否齐了,颜色搭配是否好看,凉菜热菜顺序对不对。多Agent系统的结果汇总也一样——不是简单拼凑,而是让每个Agent的产出在整体中找到恰当的位置,最终交付一个完整、一致、高质量的结果。

R=Φ(r1,r2,…,rn)R = \Phi(r_1, r_2, \dots, r_n)
公式解读:Φ 是汇总函数,它把多个Agent的输出做合并、去重、校验、格式化,最终生成统一成果。这个函数可以是简单的拼接,也可以是复杂的归纳推理。
  1. 子结果集合每个Agent i 提交自己的产出 r_i,汇总器收到 n 份结果。
    {r1,r2,…,rn}\displaystyle \{ r_1, r_2, \dots, r_n \}
  2. 整合函数汇总器通过函数 Φ 对所有 r_i 做处理,输出最终结果 R。
    R=Φ(r1,r2,…,rn)\displaystyle R = \Phi(r_1, r_2, \dots, r_n)

AI 应用场景

智能报告生成系统

阶段:任务分解 → 任务分配 → 结果汇总

解决的问题:传统上,生成一份行业研究报告需要分析师手动收集数据、整理资料、撰写分析、排版校对,单人完成需要数天。单Agent大模型直接生成时,受上下文长度限制,容易遗漏关键数据或前后矛盾。

具体案例:某咨询公司搭建了一个多Agent报告系统。调度Agent先把“生成新能源汽车行业报告”这个大目标分解为“数据采集、行业分析、竞品对比、趋势预测、排版校对”五个子任务。随后按能力匹配分配:数据采集Agent调用爬虫工具抓取最新数据;分析Agent使用大模型进行结构化解读;排版Agent专门负责格式统一。各Agent通过共享数据库交换中间结果,最后汇总Agent合并所有章节,自动生成一份带图表、引注的完整报告。整个过程从三天缩短到三小时。

软件开发的Agent协作流水线

阶段:流程阶段拆分 → 依赖调度 → 质量校验

解决的问题:现代软件开发中,需求分析、代码编写、测试、文档编写是强依赖流程,传统方式下各环节由不同角色串行交接,等待时间长、信息传递失真。单Agent编程时,既写代码又写测试又写文档,上下文很快溢出。

具体案例:一个开发团队使用多Agent流水线:产品Agent将需求拆成用户故事并生成本体,编码Agent根据依赖图按模块开发,测试Agent同时为已完成的模块编写并执行测试,文档Agent在代码稳定后自动生成API文档。通过DAG调度,多个模块的开发可以并行,只有存在依赖的模块才排队等待。测试失败时自动触发“返工”信号,编码Agent收到后修复再提测。最终版本的代码、测试报告和文档在同一时间点全部就绪,一次通过验收。

Python 演示

python101 行
import timefrom collections import deque # 定义任务: name(名称), dur(耗时), deps(依赖的任务名列表)TASK_DEFS = [    {"name": "洗菜", "dur": 2, "deps": []},    {"name": "切菜", "dur": 3, "deps": ["洗菜"]},    {"name": "备料", "dur": 2, "deps": ["洗菜"]},    {"name": "炒菜A", "dur": 3, "deps": ["切菜", "备料"]},    {"name": "炒菜B", "dur": 2, "deps": ["切菜"]},    {"name": "出锅", "dur": 2, "deps": ["炒菜A", "炒菜B"]},] # 三个Agent,各有擅长的任务类型和当前负载AGENTS = [    {"id": "Agent-1", "skills": ["洗菜", "切菜"], "load": 0},    {"id": "Agent-2", "skills": ["备料", "炒菜A"], "load": 0},    {"id": "Agent-3", "skills": ["炒菜B", "出锅"], "load": 0},] class AgentWorker:    def __init__(self, agent_info):        self.info = agent_info        self.current_task = None        self.remaining = 0        self.done_count = 0  # 该Agent完成的任务数     def can_do(self, task):        # 任务类型是否属于该Agent的技能        return task["name"] in self.info["skills"]     def start_task(self, task):        self.current_task = task        self.remaining = task["dur"]        self.info["load"] += 1     def tick(self):        # 模拟一个时间单位的工作        if self.current_task is None:            return None        self.remaining -= 1        if self.remaining <= 0:            done = self.current_task            self.current_task = None            self.info["load"] -= 1            self.done_count += 1            return done        return None class KitchenScheduler:    def __init__(self):        self.tasks = {t["name"]: dict(t) for t in TASK_DEFS}        self.completed = set()        self.workers = [AgentWorker(a) for a in AGENTS]        self.start_time = time.time()     def ready_tasks(self):        # 找出所有依赖已完成且未开始的任务        result = []        for name, task in self.tasks.items():            if name in self.completed or task["state"] == "running":                continue            if all(dep in self.completed for dep in task["deps"]):                result.append(name)        return result     def assign(self):        for worker in self.workers:            if worker.current_task is not None:                continue            ready = self.ready_tasks()            if not ready:                break            # 优先选自己擅长且当前负载最低的任务            for name in ready:                task = self.tasks[name]                if worker.can_do(task):                    worker.start_task(task)                    task["state"] = "running"                    break     def run(self, max_ticks=50):        tick_count = 0        while len(self.completed) < len(self.tasks) and tick_count < max_ticks:            tick_count += 1            self.assign()            for worker in self.workers:                done_task = worker.tick()                if done_task:                    self.completed.add(done_task["name"])                    self.tasks[done_task["name"]]["state"] = "done"        return tick_count if __name__ == "__main__":    scheduler = KitchenScheduler()    elapsed = scheduler.run()    print(f"总任务数: {len(TASK_DEFS)}")    for w in scheduler.workers:        print(f"{w.info['id']} 完成 {w.done_count} 个任务, 当前负载 {w.info['load']}")    print(f"全部完成!用时 {elapsed} 个时间单位")    print(f"完成顺序: {list(scheduler.completed)}")
目的:模拟多Agent系统中“任务分解→依赖检查→能力匹配分配→并行执行→结果收集”的完整流程,用后厨做菜的比喻直观展示调度逻辑。
  1. TASK_DEFS = [...]定义任务清单,每个任务带 deps 依赖字段,这就是“任务分解 + 依赖图”的代码化表达
  2. AGENTS = [...]定义三个Agent及其技能和负载,对应“能力匹配 + 负载均衡”的分配依据
  3. def can_do(self, task)判断某个Agent是否擅长该任务类型,相当于后厨里“小张负责切菜”
  4. def ready_tasks(self)找出所有前置依赖已完成的任务,是依赖调度的核心判断
  5. def assign(self)遍历空闲Agent,从就绪任务池中认领下一个任务,实现“动态领取”
  6. if all(dep in self.completed for dep in task["deps"])检查一个任务的所有前置任务是否都已完成
  7. while len(self.completed) < len(self.tasks)主循环,直到所有任务完成为止

常见误区

误区我以为任务分解就是把大任务尽量切碎,切得越细并行度越高,系统就跑得越快。上次我把一个报告任务拆成了两百多个子任务,结果Agent之间光传消息就花了大量时间,最后比不拆还慢。

正解拆解粒度存在最优区间,不是越细越好。每个子任务拆分后都会引入协调开销——任务分派、状态同步、结果合并。粒度太细时,协调开销会吞噬并行收益。后厨里不会把“洗菜”再拆成“洗菜叶”和“洗菜根”,因为传话的成本比省下的时间还高。实践中,子任务规模应匹配单个Agent的能力边界,做到“一口能吃下但需要嚼几下”。

为何常见:“并行=更快”的直觉让人误以为任务越多并行度越高,忽略了通信和汇总这些隐藏成本。我们天然喜欢“切碎”这个动作带来的掌控感,但系统设计看的是端到端的整体耗时。

误区我觉得多Agent系统的优势就是并行,所以把所有任务一次性分给所有Agent,谁也别等谁。结果有个Agent拿到的是“需要等另一个Agent结果才能算”的任务,反复重试也出不来结果。

正解任务之间存在真实的依赖关系,必须先建模依赖图,再做拓扑排序,让“无依赖的任务并行、有依赖的任务排队”。像后厨,切菜必须等洗菜完成,这是物理顺序,不可能靠并行来跳过。把假并行强加给真依赖的任务,只会产生大量空转和重试。正确的做法是先识别依赖,再调度——依赖图至少能确定哪些任务是真独立。

为何常见:我们容易把“多个Agent”直接等同于“多线程”,忽略了任务本身的内在顺序约束。依赖分析听起来抽象,直觉上不如“分下去就完事”来得轻松。

误区我认为任务分配完,各Agent各干各的,最后把结果拼起来就行。结果某个Agent卡在了一个资源竞争问题上,另一个Agent重复做了别人已经完成的事,整个系统没有机制发现这些问题。

正解分配只是协作的开始,还需要持续协调:共享黑板让全局状态对所有人可见,消息传递让任务间主动同步,协商机制解决资源竞争,超时检测兜底异常卡死。后厨里不可能主厨派完活就回办公室喝茶,他得盯着传菜窗、听着叫菜声,随时调度。多Agent系统的价值正在于这种“动态协调”,而不是一次性的静态分派。

为何常见:管理者习惯“布置完任务就等汇报”的思维惯性,加上多Agent系统看起来“自动运行”,让人低估了运行时协调的复杂性。

面试题

Q1. 在多Agent系统中,“任务分解”的首要价值是什么?

单选题 · easy

  • A.增加代码行数
  • B.让多个Agent并行工作← 正确答案
  • C.减少Agent数量
  • D.让系统更复杂

答案:B。任务分解的核心是把大目标拆成小任务,从而让多个Agent可以并行执行各自负责的部分,缩短整体耗时。增加代码量、减少Agent数量或让系统复杂化都不是目的,而是手段甚至副作用。

Q2. 任务分解后,理想并行情况下的整体耗时约等于什么?

单选题 · easy

  • A.所有子任务耗时之和
  • B.最慢子任务的耗时← 正确答案
  • C.最快子任务的耗时
  • D.平均子任务耗时

答案:B。并行执行时,多个Agent同时开工,整体耗时取决于最慢的那个环节——类似后厨里炒菜师傅还在忙,切配师傅早已完工在等。数学上即 T_并行 = max(t_i)。

Q3. 关于任务分解的粒度,以下哪项说法正确?

单选题 · mid

  • A.分解越细越好
  • B.分解越粗越好
  • C.存在最优粒度,需权衡并行收益与协调成本← 正确答案
  • D.粒度和性能无关

答案:C。分解太细,协调开销(通信、同步、汇总)会超过并行收益;分解太粗,单个Agent仍负担过重。最优粒度是使“最大子任务耗时+协调开销”最小化的平衡点。

Q4. 分配任务时,同时考虑“能力匹配”和“负载均衡”的目的是什么?

单选题 · mid

  • A.让每个Agent任务数量一样多
  • B.让最擅长的Agent做最合适的任务,同时避免单个Agent过载← 正确答案
  • C.让所有Agent做同样的事
  • D.不做任何区分,随机分配

答案:B。能力匹配保证任务质量——切菜找刀工好的师傅;负载均衡保证不出现瓶颈——已经炒着三个菜的师傅不再派新活。两者结合,既高效又稳定。

Q5. 以下哪些属于多Agent系统的协调机制?

多选题 · mid

  • A.共享黑板← 正确答案
  • B.消息传递← 正确答案
  • C.协商机制← 正确答案
  • D.随机数生成

答案:ABC。共享黑板提供全局状态同步,消息传递支持点对点通信,协商机制解决资源冲突——三者都是经典协调手段。随机数生成与协调无关,不能帮助Agent达成一致。

Q6. 任务依赖图通常是哪种类型的图?

单选题 · mid

  • A.有向无环图(DAG)← 正确答案
  • B.无向图
  • C.循环图
  • D.星型图

答案:A。任务依赖是单向的“先A后B”关系,且必须无环——否则会出现A等B、B等A的死锁。有向无环图既能表达先后约束,又能保证拓扑排序存在。

Q7. 某个任务的最早开始时间等于什么?

单选题 · hard

  • A.所有前置任务中最早完成时间
  • B.所有前置任务中最晚完成时间← 正确答案
  • C.前置任务平均完成时间
  • D.第一个前置任务的开始时间

答案:B。任务必须等所有前置任务全部完成才能开工,所以最早开始时间取决于“最慢的那个前置任务”何时完成。就像一桌菜的食材必须全部备齐才能开炒。

Q8. 避免多Agent系统死锁的常见手段有哪些?

多选题 · hard

  • A.保证依赖图无环← 正确答案
  • B.设置超时重试机制← 正确答案
  • C.调度器主动介入← 正确答案
  • D.增加更多Agent

答案:ABC。无环依赖从根源上避免循环等待;超时机制让卡死的Agent主动上报;调度器介入可以重新分派或回滚。单纯增加Agent数量不会解决死锁,反而可能加剧资源竞争。

Q9. 结果汇总中“去重合并”解决的问题是?

单选题 · easy

  • A.减少代码量
  • B.多个Agent产出冗余结论时统一成一份← 正确答案
  • C.让所有Agent输出相同格式
  • D.删除所有中间结果

答案:B。多个Agent可能基于同一份数据各自得出结论,汇总时需要判断保留哪份、如何融合。格式统一属于“统一输出”,删除中间结果属于“清理”,都不是去重合并的核心。

Q10. 以下关于“关键路径”的说法哪些正确?

多选题 · hard

  • A.是依赖图中最长的路径← 正确答案
  • B.决定了整个任务集合的最短完成时间← 正确答案
  • C.关键路径上的任务延误会直接影响整体进度← 正确答案
  • D.关键路径上的任务数量一定是最多的

答案:ABC。关键路径是最长路径,它决定了整体耗时;这条路径上任何任务延误都会直接推迟项目交付。但“最长”不等于“任务数最多”——可能某条路径只有两个任务但每步都很慢,而另一条路径有五个任务却每步很快。后厨里,等一份需要四十分钟的炖汤,比等十个只需一分钟的小菜更关键。