
目录一、问题根源你根本没说清楚谁该干什么二、Agent角色设计的四条铁律铁律1单一职责原则SRP铁律2明确的能力边界铁律3标准化的协作接口铁律4可观测性三、四大核心角色模板角色1规划者Planner角色2执行者Executor角色3审查者Reviewer角色4协调者Coordinator四、任务分解大活拆小活的学问分解策略递归拆解法五、任务分配算法不是什么活都随便派策略1基于能力的分配最常用策略2基于负载的分配高并发场景策略3优先级调度关键任务优先六、角色交互协议Agent之间怎么说话统一消息格式错误处理与超时重试七、动态角色调整动态扩缩Agent Pool模式八、完整实战软件开发多Agent团队九、避坑指南 效率技巧三个避坑点回顾三个效率技巧回顾开篇一个让你血压飙升的场景你兴奋地配好了3个Agent扔进去一个需求等着看它们自动协作。 30秒后架构Agent在画UI前端Agent在写SQL后端Agent在发呆。 你这不是段子。我亲眼见过至少5个团队在这个坑里翻车。问题出在哪你配了多个Agent但没给它们分配好角色。就像你招了三个程序员没有一个明确的Title——没人知道该干什么有人干重复的活有人闲着还有人越界干涉别人的工作。这不是团队这是大型事故现场。今天这篇文章我们把多Agent角色设计与任务分配这个命题彻底拆透从设计原则到角色模板从任务分解到分配算法从交互协议到动态调整。全文4000字含3张Mermaid架构图、多段完整可运行代码、3个避坑点和3个效率技巧。读完这篇文章你的多Agent系统成功率起码翻一倍。一、问题根源你根本没说清楚谁该干什么很多人以为多Agent就是多搞几个LLM调用来回传。大错特错。真实情况graph TD A[用户需求] -- B{谁来处理?} B --|没约束| C[Agent1: 我也能做] B --|没约束| D[Agent2: 我也能做] B --|没约束| E[Agent3: 我也能做] C -- F[三个Agent各干各的] D -- F E -- F F -- G[ 结果: 冲突/重复/遗漏]加上角色约束后graph TD A[用户需求] -- B[Coordinator: 协调器] B -- C[Planner: 拆解任务] C -- D{角色匹配} D --|前端| E[Frontend Agent] D --|后端| F[Backend Agent] D --|测试| G[Tester Agent] E -- H[Reviewer: 审查结果] F -- H G -- H H -- I[✅ 结果: 有序/高效/无遗漏]一眼就看出差别对吧核心问题就三个角色不清晰Agent不知道自己的边界在哪任务分配混乱没有分配机制全靠Agent自觉协作协议缺失Agent之间没有统一的通话语言下面逐个击破。二、Agent角色设计的四条铁律别急着写代码先把这四条刻在DNA里。铁律1单一职责原则SRP⚠️避坑1一个Agent承担太多职责 比单Agent还差每个Agent只做一件事而且把这件事做到极致。这跟微服务的设计哲学一脉相承。# ❌ 反面教材一个Agent包揽所有 class SuperAgent: def handle(self, task): # 需求分析 analysis self.analyze(task) # 写代码 code self.write_code(analysis) # 测试 test_result self.test(code) # 部署 self.deploy(code) return test_result# ✅ 正确做法职责分离 from abc import ABC, abstractmethod from typing import Dict, Any class BaseAgent(ABC): 所有Agent的基类定义角色契约 def __init__(self, name: str, role: str, capabilities: list[str]): self.name name self.role role self.capabilities capabilities self.workload 0 # 当前负载 abstractmethod def can_handle(self, task: Dict[str, Any]) - bool: 判断能否处理此任务 pass abstractmethod def execute(self, task: Dict[str, Any]) - Dict[str, Any]: 执行任务并返回结果 pass # 每个Agent只做自己能做的事 class RequirementAgent(BaseAgent): def can_handle(self, task): return task.get(type) requirement_analysis def execute(self, task): return {output: f需求分析完成: {task[content]}, status: done} class CodeAgent(BaseAgent): def can_handle(self, task): return task.get(type) code_generation def execute(self, task): return {output: f代码生成完成: {task[content]}, status: done}每个Agent只回答一个问题“这件事归不归我管”铁律2明确的能力边界光有职责还不够你得让Agent知道自己能做什么、不能做什么。明确能力边界有什么用比你想象的更有用——协调Agent拿着这个列表做任务匹配不需要每次都问你会不会这个铁律3标准化的协作接口⚠️避坑2每个Agent用不同的输入/输出格式 协调器崩溃所有Agent必须遵守统一的消息协议。就像HTTP协议一样——不管你是Nginx还是Apache请求格式都是GET /path HTTP/1.1。铁律4可观测性每个Agent的行为必须可追踪、可审计。你不能让Agent悄无声息地把活儿干错了还不知道。三、四大核心角色模板多Agent系统最常见的四种角色我称之为F4天团。角色1规划者Planner 大总管。拿到需求先拆成可执行的子任务。不干活只画图。角色2执行者Executor 苦力。给什么活干什么活不问为什么。但要汇报进度。角色3审查者Reviewer 质检员。代码合入前必须过我这关。像你前公司的Code Review老大爷。角色4协调者Coordinator 调度员。所有消息的中央交换局负责消息路由、任务分配、状态跟踪。完整角色架构图graph TB subgraph 用户层 U[用户输入] end subgraph 协调层 CO[Coordinator 协调者br/消息路由/任务分配/状态跟踪] end subgraph 规划层 PL[Planner 规划者br/需求拆解/子任务生成] end subgraph 执行层 E1[Executor: CodeAgentbr/代码生成] E2[Executor: TestAgentbr/测试验证] E3[Executor: DocAgentbr/文档生成] end subgraph 审查层 RV[Reviewer 审查者br/质量检查/结果审核] end U --|输入需求| CO CO --|转交需求| PL PL --|返回子任务列表| CO CO --|分配子任务| E1 CO --|分配子任务| E2 CO --|分配子任务| E3 E1 --|返回结果| CO E2 --|返回结果| CO E3 --|返回结果| CO CO --|提交审查| RV RV --|审查结果| CO CO --|最终输出| U style CO fill:#4A90D9,color:#fff style PL fill:#F5A623,color:#fff style RV fill:#7ED321,color:#fff style E1 fill:#9B59B6,color:#fff style E2 fill:#9B59B6,color:#fff style E3 fill:#9B59B6,color:#fff四、任务分解大活拆小活的学问多Agent协作的第一步不是分配任务是分解任务。你连活儿都没拆清楚怎么分配分解策略递归拆解法把一个大任务不断拆成一个Agent能独立完成的最小单元。from typing import TypedDict class SubTask(TypedDict): id: str parent_id: str | None content: str task_type: str dependencies: list[str] # 依赖的子任务ID列表 assigned_to: str | None status: str class TaskDecomposer: 递归任务分解器 def __init__(self, llm_client): self.llm llm_client def decompose(self, task_content: str, max_depth: int 3) - list[SubTask]: 递归分解任务直到每个子任务可被单个Agent处理 subtasks [] task_id_counter [0] def _decompose(content: str, parent_id: str | None, depth: int): if depth max_depth: tid ftask_{task_id_counter[0]} task_id_counter[0] 1 subtasks.append(SubTask( idtid, parent_idparent_id, contentcontent, task_typeself._classify_task(content), dependencies[parent_id] if parent_id else [], assigned_toNone, statuspending )) return tid ftask_{task_id_counter[0]} task_id_counter[0] 1 subtasks.append(SubTask( idtid, parent_idparent_id, contentcontent, task_typecomposite, dependencies[parent_id] if parent_id else [], assigned_toNone, statuspending )) # 使用LLM拆解 sub_contents self._ask_llm_to_decompose(content) for sub_content in sub_contents: _decompose(sub_content, tid, depth 1) _decompose(task_content, None, 0) return subtasks def _classify_task(self, content: str) - str: 把子任务分类code/test/doc/review keywords_map { code: [实现, 编写, 开发, 写代码, coding], test: [测试, 验证, test, 单元测试, 集成测试], doc: [文档, 说明, readme, 注释], review: [审查, 检查, review, 审计], } for task_type, keywords in keywords_map.items(): if any(kw in content for kw in keywords): return task_type return general def _ask_llm_to_decompose(self, content: str) - list[str]: 调用LLM拆解任务这里用伪代码表示 prompt f将以下任务拆解为2-5个可独立执行的子任务。 每个子任务应该是一个Agent能独立完成的原子操作。 任务{content} 返回格式每行一个子任务描述。 response self.llm.generate(prompt) return [line.strip(- ) for line in response.split(\n) if line.strip()] # 使用示例 decomposer TaskDecomposer(llm_clientNone) # 实际使用时传入LLM客户端 subtasks decomposer.decompose(开发一个用户登录功能包括前端页面和后端API, max_depth2) for st in subtasks: print(f[{st[id]}] {st[task_type]}: {st[content][:50]}...)效率技巧1大任务拆解时加一个原子性检查——如果拆出来的子任务还能再拆就不能分配给Agent。任务流转图从需求到执行的全链路sequenceDiagram participant U as 用户 participant C as Coordinator participant P as Planner participant E1 as CodeAgent participant E2 as TestAgent participant R as Reviewer U-C: 提交需求用户登录功能 C-P: 转发需求请求拆解 P-P: 拆解任务 P--C: [子任务1: 前端页面, 子任务2: 后端API, 子任务3: 测试用例] C-C: 能力匹配 负载计算 C-E1: 分配前端页面任务 C-E1: 分配后端API任务 E1-E1: 执行代码生成 E1--C: 返回前端代码 后端代码 C-E2: 分配测试用例任务 E2-E2: 执行测试生成 E2--C: 返回测试代码 C-R: 提交全部结果审查 R-R: 质量检查 R--C: 审查通过 ✅ C--U: 交付完整结果五、任务分配算法不是什么活都随便派任务拆完了现在面临核心问题这个子任务到底该派给哪个Agent有三种经典策略根据你的场景选。策略1基于能力的分配最常用匹配Agent的能力标签和任务的类型标签最直接。class CapabilityBasedScheduler: 基于能力标签的任务分配器 def __init__(self, agents: list[BaseAgent]): self.agents agents def assign(self, task: SubTask) - BaseAgent | None: 根据能力标签找到最匹配的Agent candidates [] for agent in self.agents: # 检查Agent是否能处理此类任务 if agent.can_handle(task): candidates.append(agent) if not candidates: return None # 没有Agent能处理 if len(candidates) 1: return candidates[0] # 多个候选时选负载最低的 return min(candidates, keylambda a: a.workload) # 使用 agents [ CodeAgent(码农1号, code_agent, [python, javascript]), CodeAgent(码农2号, code_agent, [python, golang]), TestAgent(测试老王, test_agent, [unit_test, integration_test]), ] scheduler CapabilityBasedScheduler(agents)策略2基于负载的分配高并发场景⚠️避坑3请求全发给最快那个Agent它直接就挂了而另外两个在摸鱼import heapq from dataclasses import dataclass, field dataclass class LoadBalancedScheduler: 负载均衡分配器——基于最小堆 agents: list[BaseAgent] _min_heap: list field(initFalse) def __post_init__(self): self._min_heap [] for agent in self.agents: heapq.heappush(self._min_heap, (agent.workload, id(agent), agent)) def assign(self, task: SubTask) - BaseAgent: 始终分给当前负载最小的Agent workload, _, agent heapq.heappop(self._min_heap) agent.workload 1 heapq.heappush(self._min_heap, (agent.workload, id(agent), agent)) return agent def complete_task(self, agent: BaseAgent): 任务完成后降低Agent的负载计数 agent.workload max(0, agent.workload - 1) # 重建堆Python堆无法原地更新元素 heapq.heapify(self._min_heap)效率技巧2能力匹配负载均衡组合拳——先按能力过滤再选负载最小的。策略3优先级调度关键任务优先from enum import IntEnum from collections import deque class Priority(IntEnum): LOW 1 MEDIUM 2 HIGH 3 CRITICAL 4 class PriorityScheduler: 优先级调度器——关键任务插队执行 def __init__(self, agents: list[BaseAgent]): self.agents agents self.queues {p: deque() for p in Priority} def enqueue(self, task: SubTask, priority: Priority Priority.MEDIUM): self.queues[priority].append(task) def dequeue(self) - SubTask | None: 从高到低取任务 for priority in sorted(Priority, reverseTrue): if self.queues[priority]: return self.queues[priority].popleft() return None # 使用 scheduler PriorityScheduler(agents) scheduler.enqueue(SubTask(idt1, ...), Priority.HIGH) scheduler.enqueue(SubTask(idt2, ...), Priority.LOW) # t1会先被调度即使t2先入队六、角色交互协议Agent之间怎么说话如果说角色设计是谁是谁交互协议就是怎么沟通。这相当于多Agent系统的OSI七层模型。统一消息格式from dataclasses import dataclass, field from datetime import datetime from enum import Enum from typing import Any class MessageType(Enum): TASK_ASSIGN task_assign # 分配任务 TASK_RESULT task_result # 返回结果 TASK_QUERY task_query # 询问进度 REVIEW_REQUEST review_request # 请求审查 REVIEW_RESULT review_result # 审查结果 ERROR error # 错误通知 HEARTBEAT heartbeat # 心跳保活 dataclass class AgentMessage: 所有Agent之间通信的统一信封 msg_id: str msg_type: MessageType sender: str # 发送者Agent名称 receiver: str # 接收者Agent名称或broadcast广播 task_id: str | None # 关联的任务ID payload: dict[str, Any] # 任务内容/结果/错误信息 timestamp: str field(default_factorylambda: datetime.now().isoformat()) retry_count: int 0 class MessageBus: 消息总线——协调者的核心通信基础设施 def __init__(self): self.inboxes: dict[str, list[AgentMessage]] {} self.history: list[AgentMessage] [] def register(self, agent_name: str): self.inboxes[agent_name] [] def send(self, msg: AgentMessage): 发送消息到目标Agent的收件箱 if msg.receiver broadcast: for inbox in self.inboxes.values(): inbox.append(msg) elif msg.receiver in self.inboxes: self.inboxes[msg.receiver].append(msg) else: raise ValueError(f未知接收者: {msg.receiver}) self.history.append(msg) def receive(self, agent_name: str) - list[AgentMessage]: 拉取Agent收件箱中的所有未读消息 msgs self.inboxes.get(agent_name, []) self.inboxes[agent_name] [] return msgs def get_history(self, task_id: str) - list[AgentMessage]: 按任务ID查询历史消息——用于调试和审计 return [m for m in self.history if m.task_id task_id]效率技巧3消息总线 可追溯的聊天记录。出了Bug翻消息历史比翻日志快10倍。错误处理与超时重试import asyncio from typing import Callable class RobustCoordinator: 健壮的协调器——处理各种意外情况 def __init__(self, message_bus: MessageBus, max_retries: int 3, timeout: float 30.0): self.bus message_bus self.max_retries max_retries self.timeout timeout self.pending_tasks: dict[str, asyncio.Task] {} async def dispatch_with_retry(self, task: SubTask, agent: BaseAgent) - dict: 分发任务并处理重试/超时 msg AgentMessage( msg_idfmsg_{task[id]}_{datetime.now().timestamp()}, msg_typeMessageType.TASK_ASSIGN, sendercoordinator, receiveragent.name, task_idtask[id], payload{content: task[content]} ) for attempt in range(1, self.max_retries 1): try: msg.retry_count attempt - 1 self.bus.send(msg) # 等待Agent执行带超时 result await asyncio.wait_for( self._wait_for_response(agent.name, task[id]), timeoutself.timeout ) return result except asyncio.TimeoutError: print(f[重试] {agent.name} 超时第{attempt}次重试...) # 超时重试时可以换一个Agent if attempt self.max_retries: return {status: failed, error: f任务{task[id]}超时已重试{self.max_retries}次} continue except Exception as e: print(f[错误] {agent.name} 执行失败: {e}第{attempt}次重试...) if attempt self.max_retries: return {status: failed, error: str(e)} continue return {status: failed, error: 未知错误} async def _wait_for_response(self, agent_name: str, task_id: str) - dict: 轮询等待Agent返回结果 while True: await asyncio.sleep(0.5) msgs self.bus.receive(coordinator) for msg in msgs: if msg.msg_type MessageType.TASK_RESULT and msg.task_id task_id: return msg.payload # 实际使用时建议加累计超时机制七、动态角色调整静态角色分配的问题是任务一会儿重一会儿轻固定团队要么忙死要么闲死。动态扩缩Agent Pool模式class AgentPool: Agent池——按需创建/回收Agent实例 def __init__(self): self.pool: dict[str, list[BaseAgent]] { code_agent: [], test_agent: [], doc_agent: [], } self.min_size 1 self.max_size 5 def get_agent(self, role: str) - BaseAgent | None: 从池中获取一个空闲Agent没有就创建 available [a for a in self.pool.get(role, []) if a.workload 2] if available: return min(available, keylambda a: a.workload) # 池中不够用新建一个不超过最大数 if len(self.pool.get(role, [])) self.max_size: new_agent self._create_agent(role) self.pool.setdefault(role, []).append(new_agent) return new_agent return None # 池满了需要排队 def _create_agent(self, role: str) - BaseAgent: 创建新Agent实例 idx len(self.pool.get(role, [])) if role code_agent: return CodeAgent(f码农{idx1}号, role, [python]) elif role test_agent: return TestAgent(f测试{idx1}号, role, [unit_test]) else: return BaseAgent(f通用{idx1}号, role, []) def scale_down(self, role: str): 回收空闲Agent pool self.pool.get(role, []) idle_agents [a for a in pool if a.workload 0] while len(pool) self.min_size and idle_agents: agent idle_agents.pop() pool.remove(agent) print(f[缩容] 回收Agent: {agent.name})八、完整实战软件开发多Agent团队理论讲完了来个完整可运行的例子——模拟一个需求→架构→编码→测试的四角色开发团队。import time from typing import Optional # 角色定义 class RequirementAnalyzer(BaseAgent): 需求分析师拆需求、写PRD def __init__(self): super().__init__(需求分析师-张三, requirement_analyzer, [requirement, analysis]) def can_handle(self, task): return 需求 in task.get(content, ) or task.get(type) requirement def execute(self, task): print(f {self.name} 正在分析需求...) return { status: done, output: { user_stories: [用户登录, 密码找回, 会话管理], tech_stack: Python FastAPI React, modules: [auth_module, session_module, ui_module] } } class ArchitectAgent(BaseAgent): 架构师设计系统架构 def __init__(self): super().__init__(架构师-李四, architect, [architecture, design]) def can_handle(self, task): return 架构 in task.get(content, ) or task.get(type) architecture def execute(self, task): print(f ️ {self.name} 正在设计架构...) requirement task.get(context, {}) return { status: done, output: { architecture: 分层架构 (Controller → Service → Repository), components: requirement.get(modules, []), data_flow: REST API → Service Layer → Database } } class CodeGeneratorAgent(BaseAgent): 编码Agent根据架构设计写代码 def __init__(self, name: str 码农-王五): super().__init__(name, code_generator, [code, implementation]) def can_handle(self, task): return task.get(type) in (code, implementation) def execute(self, task): module task.get(context, {}).get(module, unknown) print(f {self.name} 正在编写 {module} 模块...) time.sleep(0.3) # 模拟编码耗时 return { status: done, output: f# {module}.py - Auto Generated class {module.title().replace(_, )}Service: def __init__(self): pass def execute(self, params): # TODO: 实现业务逻辑 return {{result: ok}} } class TesterAgent(BaseAgent): 测试Agent写测试用例并验证 def __init__(self): super().__init__(测试-赵六, tester, [test, verification]) def can_handle(self, task): return task.get(type) test def execute(self, task): print(f {self.name} 正在写测试用例...) code task.get(context, {}).get(code, ) return { status: done, output: { test_cases: [test_login_success, test_login_failure, test_session_expiry], coverage: 85%, passed: True, code: code[:30] ... if code else 无代码 } } # 协调器 class DevTeamCoordinator: 开发团队协调器 def __init__(self): self.bus MessageBus() self.agents { requirement: RequirementAnalyzer(), architect: ArchitectAgent(), coder1: CodeGeneratorAgent(码农-王五), coder2: CodeGeneratorAgent(码农-钱七), tester: TesterAgent(), } for name in self.agents: self.bus.register(name) self.bus.register(coordinator) def run_project(self, requirement: str): 执行完整的开发流程 print(f\n{*50}) print(f 启动项目: {requirement}) print(f{*50}\n) # 阶段1需求分析 result self.agents[requirement].execute({ type: requirement, content: requirement }) print(f ✅ 需求分析完成: {result[output][user_stories]}) # 阶段2架构设计 arch_result self.agents[architect].execute({ type: architecture, content: 设计系统架构, context: result[output] }) print(f ✅ 架构设计完成: {arch_result[output][architecture]}) # 阶段3并行编码 modules arch_result[output][components] code_results [] coder_names [coder1, coder2] for i, module in enumerate(modules): coder self.agents[coder_names[i % len(coder_names)]] code_result coder.execute({ type: code, content: f编写{module}模块, context: {module: module} }) code_results.append({module: module, code: code_result[output]}) print(f ✅ {module} 编码完成) # 阶段4测试 print(f\n{*50}) print(f 项目总结) print(f{*50}) for cr in code_results: test_result self.agents[tester].execute({ type: test, content: f测试{cr[module]}, context: {code: cr[code]} }) status ✅ 通过 if test_result[output][passed] else ❌ 失败 print(f {status} {cr[module]} | 覆盖率: {test_result[output][coverage]}) print(f\n 项目完成共完成 {len(modules)} 个模块的开发与测试) # 运行演示 if __name__ __main__: coordinator DevTeamCoordinator() coordinator.run_project(开发一个用户认证系统包括登录、注册、密码找回功能) # 输出示例: # # 启动项目: 开发一个用户认证系统... # # 需求分析师-张三 正在分析需求... # ✅ 需求分析完成: [用户登录, 密码找回, 会话管理] # ️ 架构师-李四 正在设计架构... # ✅ 架构设计完成: 分层架构 (Controller → Service → Repository) # 码农-王五 正在编写 auth_module 模块... # ✅ auth_module 编码完成 # 码农-钱七 正在编写 session_module 模块... # ✅ session_module 编码完成 # 码农-王五 正在编写 ui_module 模块... # ✅ ui_module 编码完成 # ... # 项目完成共完成 3 个模块的开发与测试九、避坑指南 效率技巧三个避坑点回顾#坑后果解法1一个Agent承担太多职责比单Agent还差严格遵守单一职责原则2每个Agent用不同的I/O格式协调器崩溃统一消息协议AgentMessage3请求全发给一个Agent一个忙死其他摸鱼能力匹配负载均衡组合拳三个效率技巧回顾#技巧效果1任务拆解时做原子性检查避免二次拆解浪费2能力匹配负载均衡组合又快又不浪费资源3消息总线 可追溯聊天记录调试效率翻10倍文末三件套1. 关键知识点四大角色模板Planner拆活、Executor干活、Reviewer查活、Coordinator派活三条分配算法能力匹配、负载均衡、优先级调度——组队用统一消息协议AgentMessage MessageBus 所有Agent的英语动态扩缩AgentPool模式按负载自动增减Agent2. 下篇预告《L4实战——多Agent协作系统搭建三Agent记忆与上下文管理》角色分好了任务也分配了但还有一个灵魂问题没解决Agent怎么记住刚才干了什么下篇给你讲短期记忆vs长期记忆、上下文窗口管理与压缩、跨Agent共享记忆、RAG记忆检索实战。关注我不迷路。3. 交流 代码觉得有用就三连点赞收藏关注你的支持是我写下去的唯一动力。有任何问题欢迎评论区交流每条我都会看。CSDN标签多Agent、角色设计、任务分配、LangGraph、协作系统、Agent架构、任务编排