多 Agent 协作架构:从单兵作战到团队协同的设计演进
一、一个 Agent 干不了所有事
让一个 Agent 完成复杂任务,就像让一个人同时做产品经理、设计师和程序员------理论上可行,实际上每个环节都做得半吊子。一个 Agent 既要理解用户意图、又要规划执行步骤、还要调用工具、还要检查结果,上下文窗口被各种指令塞满,幻觉率直线上升。
多 Agent 协作的核心思路是分而治之:每个 Agent 只负责一件事,做到极致。规划 Agent 负责拆解任务,检索 Agent 负责找资料,编码 Agent 负责写代码,审查 Agent 负责检查质量。它们通过消息传递协同工作,就像一个高效的项目团队。但多 Agent 系统的难点不在单个 Agent 的能力,而在协作机制------谁指挥谁、信息怎么流转、冲突怎么解决、失败怎么回滚。
二、多 Agent 协作的架构模式
2.1 三种协作模式
多 Agent 协作有三种经典模式:
主从模式(Orchestrator-Worker):一个主 Agent 负责任务分解和调度,多个从 Agent 负责执行。主 Agent 掌握全局视图,从 Agent 只看局部任务。优点是控制流清晰,缺点是主 Agent 是单点瓶颈。
对等模式(Peer-to-Peer):所有 Agent 地位平等,通过协商达成共识。适合去中心化场景,但协商成本高,容易陷入死循环。
管道模式(Pipeline):Agent 按固定顺序串联,前一个的输出是后一个的输入。适合线性工作流,但不支持并行和条件分支。
2.2 主从协作架构
三、多 Agent 协作框架的实现
3.1 Agent 基础抽象
python
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Any
from enum import Enum
import asyncio
import json
import uuid
class AgentRole(Enum):
"""Agent角色类型"""
ORCHESTRATOR = "orchestrator" # 主控
RETRIEVER = "retriever" # 检索
CODER = "coder" # 编码
REVIEWER = "reviewer" # 审查
EXECUTOR = "executor" # 执行
class MessagePriority(Enum):
"""消息优先级"""
LOW = 0
NORMAL = 1
HIGH = 2
URGENT = 3
@dataclass
class AgentMessage:
"""Agent间传递的消息"""
id: str = field(default_factory=lambda: str(uuid.uuid4()))
sender: str = ""
receiver: str = "" # 空字符串表示广播
content: str = ""
metadata: Dict[str, Any] = field(default_factory=dict)
priority: MessagePriority = MessagePriority.NORMAL
reply_to: Optional[str] = None # 回复的消息ID
timestamp: float = 0.0
@dataclass
class TaskResult:
"""任务执行结果"""
task_id: str
agent_id: str
success: bool
output: Any = None
error: Optional[str] = None
metadata: Dict[str, Any] = field(default_factory=dict)
class BaseAgent(ABC):
"""Agent基类:定义统一接口"""
def __init__(
self,
agent_id: str,
role: AgentRole,
description: str = "",
):
self.agent_id = agent_id
self.role = role
self.description = description
self._message_queue: asyncio.Queue[AgentMessage] = asyncio.Queue()
self._running = False
@abstractmethod
async def process(self, message: AgentMessage) -> TaskResult:
"""处理接收到的消息,子类必须实现"""
...
async def receive(self, message: AgentMessage):
"""接收消息"""
await self._message_queue.put(message)
async def run(self):
"""Agent主循环"""
self._running = True
while self._running:
try:
message = await asyncio.wait_for(
self._message_queue.get(),
timeout=1.0,
)
result = await self.process(message)
# 将结果发送回消息总线
await self._on_result(result)
except asyncio.TimeoutError:
continue
except Exception as e:
# 异常不中断主循环
print(f"[{self.agent_id}] 处理异常: {e}")
def stop(self):
"""停止Agent"""
self._running = False
async def _on_result(self, result: TaskResult):
"""结果回调,由子类覆盖"""
pass
3.2 消息总线与协作编排
python
class MessageBus:
"""消息总线:Agent间的通信中枢
支持点对点发送和主题广播,
所有消息经过总线中转,便于监控和调试。
"""
def __init__(self):
self._agents: Dict[str, BaseAgent] = {}
self._topic_subscribers: Dict[str, List[str]] = {}
self._message_log: List[AgentMessage] = []
def register(self, agent: BaseAgent):
"""注册Agent"""
self._agents[agent.agent_id] = agent
def subscribe(self, agent_id: str, topic: str):
"""订阅主题"""
if topic not in self._topic_subscribers:
self._topic_subscribers[topic] = []
self._topic_subscribers[topic].append(agent_id)
async def send(self, message: AgentMessage):
"""发送消息"""
self._message_log.append(message)
if message.receiver:
# 点对点发送
agent = self._agents.get(message.receiver)
if agent:
await agent.receive(message)
else:
# 广播到所有Agent
for agent in self._agents.values():
if agent.agent_id != message.sender:
await agent.receive(message)
async def broadcast_to_topic(self, topic: str, message: AgentMessage):
"""向主题订阅者广播"""
subscribers = self._topic_subscribers.get(topic, [])
for agent_id in subscribers:
msg = AgentMessage(
sender=message.sender,
receiver=agent_id,
content=message.content,
metadata={**message.metadata, "topic": topic},
)
await self.send(msg)
def get_message_log(self) -> List[AgentMessage]:
"""获取消息日志(调试用)"""
return self._message_log
class OrchestratorAgent(BaseAgent):
"""主控Agent:负责任务分解和调度"""
def __init__(self, bus: MessageBus):
super().__init__(
agent_id="orchestrator",
role=AgentRole.ORCHESTRATOR,
description="任务分解与调度中心",
)
self.bus = bus
self._pending_tasks: Dict[str, Dict] = {}
self._completed_tasks: Dict[str, TaskResult] = {}
async def process(self, message: AgentMessage) -> TaskResult:
"""处理用户请求或子任务结果"""
if message.metadata.get("type") == "user_request":
return await self._handle_user_request(message)
elif message.metadata.get("type") == "task_result":
return await self._handle_task_result(message)
else:
return TaskResult(
task_id=message.id,
agent_id=self.agent_id,
success=False,
error="未知消息类型",
)
async def _handle_user_request(
self, message: AgentMessage
) -> TaskResult:
"""分解用户请求为子任务"""
user_input = message.content
# 任务分解(实际应调用LLM)
sub_tasks = self._decompose_task(user_input)
# 为每个子任务分配Agent
for task in sub_tasks:
task_id = str(uuid.uuid4())
self._pending_tasks[task_id] = task
# 根据任务类型选择Agent
target_agent = self._select_agent(task["type"])
# 发送子任务
await self.bus.send(AgentMessage(
sender=self.agent_id,
receiver=target_agent,
content=task["description"],
metadata={
"type": "sub_task",
"task_id": task_id,
"parent_request": message.id,
},
))
return TaskResult(
task_id=message.id,
agent_id=self.agent_id,
success=True,
output=f"已分解为{len(sub_tasks)}个子任务",
)
async def _handle_task_result(
self, message: AgentMessage
) -> TaskResult:
"""处理子任务完成结果"""
task_id = message.metadata.get("task_id", "")
result_data = message.content
self._completed_tasks[task_id] = TaskResult(
task_id=task_id,
agent_id=message.sender,
success=True,
output=result_data,
)
# 检查是否所有子任务都完成
if len(self._completed_tasks) == len(self._pending_tasks):
# 汇总结果
final_result = self._aggregate_results()
return TaskResult(
task_id="final",
agent_id=self.agent_id,
success=True,
output=final_result,
)
return TaskResult(
task_id=task_id,
agent_id=self.agent_id,
success=True,
output="子任务完成,等待其他子任务",
)
def _decompose_task(self, user_input: str) -> List[Dict]:
"""任务分解逻辑(简化实现)"""
return [
{"type": "retrieval", "description": f"检索与以下需求相关的资料: {user_input}"},
{"type": "coding", "description": f"根据需求编写代码: {user_input}"},
{"type": "review", "description": f"审查代码质量: {user_input}"},
]
def _select_agent(self, task_type: str) -> str:
"""根据任务类型选择Agent"""
mapping = {
"retrieval": "retriever",
"coding": "coder",
"review": "reviewer",
}
return mapping.get(task_type, "executor")
def _aggregate_results(self) -> str:
"""汇总所有子任务结果"""
parts = []
for task_id, result in self._completed_tasks.items():
parts.append(f"[{task_id}] {result.output}")
return "\n".join(parts)
class CollaborativeSystem:
"""多Agent协作系统"""
def __init__(self):
self.bus = MessageBus()
self.agents: Dict[str, BaseAgent] = {}
def add_agent(self, agent: BaseAgent):
"""添加Agent"""
self.agents[agent.agent_id] = agent
self.bus.register(agent)
async def start(self):
"""启动所有Agent"""
tasks = [agent.run() for agent in self.agents.values()]
await asyncio.gather(*tasks)
async def submit_request(self, user_input: str) -> str:
"""提交用户请求"""
message = AgentMessage(
sender="user",
receiver="orchestrator",
content=user_input,
metadata={"type": "user_request"},
)
await self.bus.send(message)
return "请求已提交"
3.3 使用示例
python
async def main():
system = CollaborativeSystem()
# 添加主控Agent
orchestrator = OrchestratorAgent(system.bus)
system.add_agent(orchestrator)
# 添加检索Agent
retriever = BaseAgent.__new__(BaseAgent) # 简化示例
# 实际应实现具体的process方法
# 启动系统
await system.submit_request(
"实现一个Python的快速排序算法,要求有完整的类型注解和单元测试"
)
asyncio.run(main())
四、多 Agent 系统的工程挑战
4.1 上下文膨胀与信息丢失
多 Agent 协作最大的工程挑战是上下文管理。每个 Agent 需要足够的上下文才能做出正确决策,但上下文窗口有限。主控 Agent 把任务分给编码 Agent 时,如果只传了任务描述没传检索结果,编码 Agent 就在"盲写"。如果传了所有上下文,又可能超出窗口限制。
解决方案是分层上下文传递:主控 Agent 维护完整的任务上下文,子 Agent 只接收与自身任务相关的摘要。摘要的质量直接决定子 Agent 的输出质量,这又引入了"谁来生成摘要"的问题------通常由主控 Agent 自己做,增加了它的负担。
4.2 死锁与活锁
多 Agent 系统可能出现死锁:Agent A 等 Agent B 的结果,Agent B 等 Agent A 的结果。也可能出现活锁:审查 Agent 总是拒绝编码 Agent 的输出,编码 Agent 反复修改但始终不通过,两个 Agent 无限循环。
预防死锁的方法是设置最大重试次数和超时机制。预防活锁的方法是引入"升级"机制------连续 N 次审查不通过时,将问题升级到更高层级的 Agent 或直接返回部分结果。
4.3 适用与禁用场景
适用场景:复杂任务的分步执行(代码生成+测试+审查)、需要多源信息的综合分析、长链路工作流的自动化。
禁用场景:简单任务(单 Agent 足够,多 Agent 反而增加延迟)、对延迟极度敏感的场景(Agent 间通信有开销)、需要强一致性的场景(异步协作难以保证一致性)。
五、总结
多 Agent 协作的核心价值是分而治之------每个 Agent 专注一件事,通过消息传递协同完成复杂任务。主从模式是最实用的协作架构,主控 Agent 负责任务分解和结果汇总,子 Agent 负责执行。消息总线是协作的基础设施,所有 Agent 间的通信都经过总线中转,便于监控、调试和扩展。上下文管理是多 Agent 系统最大的工程挑战,分层摘要和按需传递是主要的缓解策略。死锁和活锁是异步协作的固有风险,必须通过超时、重试上限和升级机制来防范。多 Agent 不是万能的------简单任务用单 Agent 更快更好,只有当任务复杂度超过单 Agent 的处理能力时,多 Agent 的协作收益才值得付出额外的系统复杂度。