摘要:随着大语言模型(LLM)从单任务处理走向复杂跨领域业务求解,单一 Agent(单体智能体)由于 Prompt 膨胀、工具过多导致的召回稀释(Tool Dilution)、上下文污染(Context Pollution)以及规划深度不足,正迅速触碰到性能天花板。
多智能体系统(Multi-Agent System, MAS) 通过"分而治之"的设计哲学,将复杂的系统目标解耦至多个具有专业角色、独立工具集与独立上下文的专精 Agent。而在多 Agent 体系中,如何设计高效的协作拓扑 与确定性的动态切换/控制权移交(Handoff)机制,是决定系统稳定性、响应延迟与成本控制的核心命题。
本文将从单 Agent 的结构性瓶颈出发,深入拆解四大主流多 Agent 协作拓扑(主从层级式、点对点接力式、黑板共享式、动态图工作流);详细剖析动态切换协议设计(意图路由、状态迁移、上下文无损裁剪与死循环熔断);并基于 Python 异步生态提供一套开箱即用、具备工业级韧性的多 Agent 动态路由与协同框架实战源码。
一、 为什么单 Agent 走向终结?多 Agent 系统的必然性
在构建复杂的 LLM 应用(如全自动软件开发流水线、企业 ERP 智能中枢、跨业务客服系统)时,很多团队最初尝试使用"单一巨型 Agent":把 30 个外部工具、数千字的 System Prompt 以及全量业务规则塞入一个模型上下文中。
然而,单体 Agent 架构在面临复杂长流程时,必然遭遇以下四大结构性困境:
┌────────────────────────────────────────────────────────────────────────┐
│ 单体 Agent 的四大结构性困境 │
├──────────────────┬─────────────────────────────────────────────────────┤
│ 1. 规则与角色干扰│ 赋予模型的角色越杂,模型越容易混淆职责,遵循性急剧下降 │
├──────────────────┼─────────────────────────────────────────────────────┤
│ 2. 工具选择稀释 │ 当可用工具超过 10~20 个时,模型选择错误工具的概率呈指数上升│
├──────────────────┼─────────────────────────────────────────────────────┤
│ 3. 上下文过度污染│ 检索出来的无关历史与中间计算碎片挤占窗口,引发严重幻觉│
├──────────────────┼─────────────────────────────────────────────────────┤
│ 4. 成本与延迟失控│ 每次简单的工具调用都要携带全量巨型 Prompt,无法利用缓存│
└──────────────────┴─────────────────────────────────────────────────────┘
【单体 Agent (Monolithic Agent)】
用户请求 ──► [ 巨型 Prompt + 30 个工具 + 庞大上下文 ] ──► 输出混乱、延迟高、易幻觉
【多 Agent 协作 (Multi-Agent Modularization)】
用户请求 ──► [ 分流路由 / Router ]
│
┌─────────┼─────────┐
▼ ▼ ▼
[销售专家] [售后技术] [财务开票] (每个 Agent 仅持 3~5 个专属工具与精简上下文)
多 Agent 架构的核心优势
-
关注点分离(Separation of Concerns):每个 Agent 仅拥有极度专注的 Prompt 边界与最小化的工具集(Tool Set),极大降低了单次决策的推理复杂度。
-
异构模型混用(Heterogeneous LLM Routing):分流与规划可以使用高推理能力的大模型(如 DeepSeek-R1、GPT-4o),而具体的格式清洗或简单检索可以派发给极低成本的轻量级小模型(如 GPT-4o-mini、7B 本地模型),大幅优化 ROI。
-
上下文隔离与独立维护:各 Agent 维护独立的 Working Memory,交互时仅传递结构化的输出结果,避免无关历史碎片污染其他环节。
二、 多 Agent 协作的四大主流拓扑模式
在设计多 Agent 系统前,必须根据业务场景的确定性与灵活性需求,选择合理的协作拓扑架构。
┌─────────────────────────────────────────┐
│ 多 Agent 协作拓扑形态 │
└────────────────────┬────────────────────┘
│
┌──────────────────┬───────────────┴───────────────┬──────────────────┐
▼ ▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 主从层级式 │ │ 点对点接力 │ │ 黑板共享式 │ │ 动态图工作流│
│ (Supervisor) │ │ (Peer Handoff│ │ (Blackboard) │ │ (Graph-based)│
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
2.1 主从层级式(Supervisor / Router Pattern)
这是工业界最常见、最可控的模式。系统中存在一个"主管(Supervisor / Master Agent)",负责接收用户输入、分解任务、调度具体的"工蜂(Worker Agents)",并汇总结算。
┌─────────────────────┐
│ Supervisor Agent │
└──────────┬──────────┘
│ 任务指派 / 汇总
┌────────────────────────┼────────────────────────┐
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Research Agent │ │ Coder Agent │ │ Reviewer Agent │
└──────────────────┘ └──────────────────┘ └──────────────────┘
-
核心机制:Worker 之间彼此不可见、不直接通信。Worker 完成局部任务后,将结果上报给 Supervisor,由 Supervisor 决定下一步是派发给下一个 Worker 还是直接回复用户。
-
优点:控制流极其清晰,便于进行全局权限校验、成本统计与审计,不易出现混乱死循环。
-
缺点:Supervisor 容易成为单点瓶颈;每次中间交互都需要经过 Supervisor 转发,Token 消耗较大。
2.2 点对点接力式(Peer-to-Peer / Swarm Handoff Pattern)
以 OpenAI Swarm 架构为代表的轻量级接力协作模式。系统中没有常驻的中心调度器,每个 Agent 都有能力直接将"控制权与上下文"移交给另一个更专业的 Agent。
[用户输入] ──► [Triage Agent (分诊)]
│
│ transfer_to_billing() (控制权移交)
▼
[Billing Agent (财务)]
│
│ transfer_to_technical() (控制权移交)
▼
[Technical Agent (技术支持)] ──► [输出最终结果]
-
核心机制 :通过在 Function Calling 中暴露特定的转移函数(如
transfer_to_sales_agent())。当模型认为当前问题超出其专业范围时,自主调用转移函数返回新 Agent 的引用,宿主环境随即切换当前活跃的 Agent。 -
优点:极度扁平、轻量、低延迟,去中心化设计让业务链路非常直接。
-
缺点:缺乏全局监管,若未设置严格的 TTL(生存时间)或循环检测,容易在两个 Agent 之间发生"踢皮球(Ping-Pong Handover)"死循环。
2.3 黑板共享式(Blackboard / Shared State Store Pattern)
源自经典人工智能架构。系统中存在一个全局共享的状态存储中心(Blackboard / Event Pool),多个专精 Agent 共同监听黑板上的数据变动,并自主决定何时介入。
┌────────────────────────────────────────────────────────────────────────┐
│ 全局共享黑板 (Shared Blackboard) │
│ - 任务目标状态 - 当前代码制品 (Artifacts) - 待解决 Bug 清单 │
└─────────┬──────────────────────┬───────────────────────┬───────────────┘
│ 读写数据 │ 读写数据 │ 读写数据
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Architect Agent │ │ Frontend Agent │ │ Database Agent │
│ (设计数据结构) │ │ (消费结构写UI) │ │ (消费结构写SQL) │
└──────────────────┘ └──────────────────┘ └──────────────────┘
-
核心机制:基于事件驱动(Event-Driven)或状态变更轮询。例如架构师 Agent 将数据库 Schema 发布到黑板后,前端 Agent 和后端 Agent 同时感知到事件并并行启动工作,产出合并回黑板。
-
优点:天然支持高并发与异构 Agent 协作,解耦程度最高。
-
缺点:状态冲突解决(Conflict Resolution)和并发一致性控制复杂度高,需要引入分布式锁或乐观锁机制。
2.4 动态图工作流(Dynamic Graph Workflow / LangGraph Style)
将整个系统的协作建模为一张有向状态图(State Graph)。节点(Nodes)是 Agent 或 Python 执行函数,边(Edges)是带有条件判断的逻辑分支。
┌──────────────┐
│ [Start Node] │
└──────┬───────┘
│
▼
┌──────────────┐
│ [Draft Plan] │
└──────┬───────┘
│
▼
┌─────────────────────┐
┌──────►│ [Code Generator] │
│ └──────────┬──────────┘
│ │
│ ▼
│ ┌─────────────────────┐
│ │ [Unit Tester] │
│ └──────────┬──────────┘
│ │
│ ▼
│ / 单元测试是否通过? \
└──[否]── ◄ ► ──[是]──► [End Node]
\ /
-
核心机制:支持循环(Cyclic)、分支判断与人工介入(Human-in-the-loop)。通过显式定义图的转移条件,精准控制执行路径。
-
优点:兼具灵活性与强确定性,特别适合需要"生成-测试-反思-修正"闭环的代码或报告生成任务。
-
缺点:需要预先对业务流程有清晰的图结构建模,冷启动设计成本稍高。
三、 动态切换(Handoff)核心机制深度设计
动态切换是多 Agent 系统的"中枢神经"。一个健壮的 Handoff 机制必须解决三大核心问题:何时切(Routing Trigger) 、怎么切(State Handover) 、如何防爆(Safety & Loop Prevention)。
┌────────────────────────────────────────────────────────────────────────┐
│ 动态切换机制 (Handoff) 三大核心环节 │
├──────────────────┬─────────────────────────────────────────────────────┤
│ 1. 意图分流与触发│ - 语义路由 (Semantic Router) │
│ │ - 专用分类器 (Triage LLM) │
│ │ - 原生函数调用分发 (Function Calling Handoff) │
├──────────────────┼─────────────────────────────────────────────────────┤
│ 2. 状态与上下文接力│ - 无损全量移交 (Full State Migration) │
│ │ - 摘要与结构化传递 (Summary-based Handoff) │
│ │ - 隔离域传递 (Scoped Context Handover) │
├──────────────────┼─────────────────────────────────────────────────────┤
│ 3. 运行防御与控制│ - 跳数硬上限 (Hop Limit / Max Steps) │
│ │ - 历史环路检测 (Visited Hash Detection) │
│ │ - 超时与降级机制 (Fallback to Supervisor/Human) │
└──────────────────┴─────────────────────────────────────────────────────┘
3.1 切换触发机制:三种路由判定路径
1. 基于 Function Calling 的自主动态让渡(Autonomous Handoff)
在 Agent 的工具定义中,注入系统内置的切换工具:
{
"name": "transfer_to_billing_agent",
"description": "当用户问题涉及充值、退款、发票、账单查询时,必须调用此工具将控制权移交发票财务专家",
"parameters": {
"type": "object",
"properties": {
"reason": {"type": "string", "description": "移交原因"},
"user_intent_summary": {"type": "string", "description": "对用户诉求的核心提炼"}
},
"required": ["reason", "user_intent_summary"]
}
}
当大模型判断当前上下文符合工具描述时,直接触发 tool_calls,宿主引擎解析该调用并执行 Agent 切换。
2. 前置轻量级语义路由器(Semantic Router / Embedding Classifier)
对于意图非常明确的场景,不需要每次都调用昂贵的大模型进行分类。
-
原理:预先为每个 Agent 维护一组代表性的样本语句(Utterances),计算其向量并存入内存。
-
执行:用户输入到达后,计算 Query 向量,通过余弦相似度(Cosine Similarity)在 5 毫秒内计算出最近匹配的 Agent。若相似度高于阈值(如 0.85),直接定向路由,跳过 Triage Agent 的 LLM 推理,大幅降低延迟与费用。
3.2 状态与上下文接力(Context Handover Protocol)
切换 Agent 时,最忌讳的是机械地把当前 Agent 产生的所有冗长中间思考、无效工具报错直接复制给下一个 Agent。这会导致下游 Agent 的上下文迅速耗尽并受到干扰。
生产级系统通常采用以下三种上下文迁移协议:
【协议 A:全量追加传递 (适用于短链条/紧密协作)】
Context_B = Context_A + [System_Prompt_B]
【协议 B:摘要提取接力 (适用于长长上下文跨部门切换)】
Context_B = [System_Prompt_B] + [LLM_Generated_Summary(Context_A)] + [User_Original_Query]
【协议 C:结构化 Payload 传递 (工业级推荐)】
Context_B = [System_Prompt_B] + [Structured_Handoff_Payload(Slots, Intent, Auth_Info)]
工业级标准:结构化 Payload 移交规范
定义标准的强类型数据协议(Pydantic 规范),确保跨 Agent 传递的数据绝对受控:
from pydantic import BaseModel, Field
from typing import Dict, Any, Optional
class HandoffPayload(BaseModel):
source_agent: str = Field(description="移交方 Agent 名称")
target_agent: str = Field(description="接收方 Agent 名称")
user_id: str = Field(description="用户全局唯一ID")
intent: str = Field(description="已识别的用户核心意图")
extracted_slots: Dict[str, Any] = Field(default_factory=dict, description="已提取的实体槽位 (如 order_id, product_name)")
handoff_reason: str = Field(description="切换原因说明")
raw_query: str = Field(description="用户原始最新输入")
3.3 运行防御机制:防踢皮球与死循环熔断
在去中心化或双向切换系统中,极易出现 Ping-Pong Loop(乒乓死循环):
-
销售 Agent 认为技术问题该找技术 Agent;
-
技术 Agent 认为涉及价格又转回给销售 Agent。
防御策略组合拳:
-
TTL 跃点计数器(Hop Counter) :全局请求携带
hop_count,每经历一次 Agent 切换则hop_count += 1。一旦达到阈值(如max_hops = 5),强行拦截并将控制权收缴至兜底 Supervisor 或人工客服。 -
访问轨迹哈希环检测(Cycle Detection) :维护一个有序访问链表
visited_path = ["Triage", "Sales", "Tech", "Sales"]。当算法检测到出现重复循环子序列(如Sales -> Tech -> Sales)时,判定为逻辑锁死,触发熔断。[切换请求] ──► 检查 Hop Count >= Max Hops? ──[是]──► 触发熔断 ──► 接入兜底/人工
│ [否]
▼
检查是否命中环路特征? ─────────[是]──► 强制终止 ──► 降级 Supervisor
│ [否]
▼
正常执行 Agent 上下文迁移与激活
四、 共享记忆、状态总线与黑板架构设计
在复杂多 Agent 系统中,除了上下文(Context)传递,还需要考虑持久化的记忆与状态存储。
┌────────────────────────────────────────────────────────────────────────┐
│ 多 Agent 分层存储与通信矩阵 │
├──────────────────┬───────────────────────┬─────────────────────────────┤
│ 存储/通信层级 │ 技术实现方案 │ 适用数据类型 │
├──────────────────┼───────────────────────┼─────────────────────────────┤
│ 1. 局部私有记忆 │ 内存 List[Dict] │ 个人未完成的中间思考与临时变量│
├──────────────────┼───────────────────────┼─────────────────────────────┤
│ 2. 会话共享总线 │ Redis / In-Memory Dict│ 当前会话的槽位、全局锁、状态 │
├──────────────────┼───────────────────────┼─────────────────────────────┤
│ 3. 长期知识资产 │ 向量数据库 (Qdrant) │ 企业知识库、历史对话案例 │
├──────────────────┼───────────────────────┼─────────────────────────────┤
│ 4. 异步事件通信 │ Kafka / Redis Streams │ 跨 Agent 异步解耦任务通知 │
└──────────────────┴───────────────────────┴─────────────────────────────┘
乐观并发控制(Optimistic Locking)在黑板模式中的应用
当多个 Agent 同时尝试修改全局共享状态(例如:前端 Agent 和后端 Agent 同时尝试修改项目计划表的同一字段)时,必须通过版本号机制防止数据覆盖:
class BlackboardState(BaseModel):
version: int = 1
data: Dict[str, Any] = Field(default_factory=dict)
def update_blackboard(key: str, value: Any, expected_version: int) -> bool:
# 模拟从 Redis 获取当前状态
current_state = get_current_state()
if current_state.version != expected_version:
# 版本号不匹配,说明已被其他 Agent 先行修改,触发更新冲突重试
return False
current_state.data[key] = value
current_state.version += 1
save_state(current_state)
return True
五、 端到端生产级实战:手搓动态多 Agent 路由与接力系统
下面提供一份完整、生产级、基于原生 Python 异步并发生态构建的多 Agent 协作与动态切换系统。
本实现包含:
-
三个专精 Agent :
TriageAgent(分诊接待)、BillingAgent(财务账单)、TechSupportAgent(技术运维); -
标准 Handoff 协议:通过 Function Calling 实现结构化让渡;
-
全局执行引擎:包含死循环熔断、跳数限制、上下文精准提取与状态流转。
5.1 环境准备
pip install openai pydantic
5.2 核心代码实现
import os
import json
import asyncio
import logging
from typing import List, Dict, Any, Optional, Callable, Tuple
from pydantic import BaseModel, Field
# 配置结构化日志输出
logging.basicConfig(level=logging.INFO, format="%(asctime)s - [%(levelname)s] - %(message)s")
logger = logging.getLogger("MultiAgentRuntime")
# ==================== 1. 核心协议与实体模型 ====================
class HandoffSignal(Exception):
"""用于在工具执行中抛出切换控制权的特殊信号"""
def __init__(self, target_agent_name: str, payload: Dict[str, Any]):
self.target_agent_name = target_agent_name
self.payload = payload
class AgentTool(BaseModel):
name: str
description: str
parameters: Dict[str, Any]
func: Callable
class AgentContext:
"""全局会话运行时上下文"""
def __init__(self, session_id: str, user_id: str):
self.session_id = session_id
self.user_id = user_id
self.global_state: Dict[str, Any] = {}
self.hop_count: int = 0
self.visited_history: List[str] = []
# ==================== 2. Agent 基类定义 ====================
class BaseAgent:
def __init__(self, name: str, system_prompt: str, model: str = "gpt-4o-mini"):
self.name = name
self.system_prompt = system_prompt
self.model = model
self.tools: Dict[str, AgentTool] = {}
def register_tool(self, name: str, description: str, parameters: Dict[str, Any], func: Callable):
self.tools[name] = AgentTool(name=name, description=description, parameters=parameters, func=func)
def get_tools_schema(self) -> List[Dict[str, Any]]:
return [
{
"type": "function",
"function": {
"name": tool.name,
"description": tool.description,
"parameters": tool.parameters
}
}
for tool in self.tools.values()
]
# ==================== 3. 具体业务工具与 Handoff 函数定义 ====================
# --- 财务工具 ---
async def tool_query_invoice(order_id: str) -> str:
logger.info(f"[财务系统] 正在查询订单 {order_id} 的发票状态...")
await asyncio.sleep(0.3)
return json.dumps({"order_id": order_id, "invoice_status": "ISSUED", "amount": 299.00, "url": "https://invoice.example.com/pdf/123"})
# --- 技术运维工具 ---
async def tool_restart_server(server_id: str) -> str:
logger.info(f"[运维系统] 正在向服务器 {server_id} 发送重启指令...")
await asyncio.sleep(0.5)
return json.dumps({"server_id": server_id, "status": "RESTARTED", "uptime": "0 min"})
# --- 动态切换工具 (Handoff Functions) ---
async def transfer_to_billing(reason: str, order_id: Optional[str] = None) -> str:
"""切换至财务结算专家"""
raise HandoffSignal("BillingAgent", {"reason": reason, "order_id": order_id})
async def transfer_to_tech_support(reason: str, server_id: Optional[str] = None) -> str:
"""切换至技术运维专家"""
raise HandoffSignal("TechSupportAgent", {"reason": reason, "server_id": server_id})
# ==================== 4. 初始化多 Agent 角色 ====================
def create_agent_system() -> Dict[str, BaseAgent]:
agents = {}
# 1. 前置分诊 Agent (Triage Agent)
triage = BaseAgent(
name="TriageAgent",
system_prompt="你是一位负责客户接待的前台服务专家。仔细倾听用户诉求,并将其准确转交给对应的专业技术或财务支持部门。不要自行回答深度专业问题。"
)
triage.register_tool(
name="transfer_to_billing",
description="当用户问题涉及发票、退款、账单、支付时调用此工具移交财务专家",
parameters={
"type": "object",
"properties": {
"reason": {"type": "string", "description": "转交财务的原因"},
"order_id": {"type": "string", "description": "若用户提及了订单号则提取传入,否则传空"}
},
"required": ["reason"]
},
func=transfer_to_billing
)
triage.register_tool(
name="transfer_to_tech_support",
description="当用户问题涉及服务器宕机、Bug 报错、系统部署、重启等技术运维故障时调用此工具移交技术专家",
parameters={
"type": "object",
"properties": {
"reason": {"type": "string", "description": "转交技术支持的原因"},
"server_id": {"type": "string", "description": "若用户提及了服务器ID则提取传入,否则传空"}
},
"required": ["reason"]
},
func=transfer_to_tech_support
)
agents[triage.name] = triage
# 2. 财务专家 Agent (Billing Agent)
billing = BaseAgent(
name="BillingAgent",
system_prompt="你是一位资深的财务结算专家,专精于处理订单发票、退款结算与账单查询。回答风格严谨、专业。"
)
billing.register_tool(
name="query_invoice",
description="根据订单号查询电子发票详情及下载链接",
parameters={
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "6位以上订单编号"}
},
"required": ["order_id"]
},
func=tool_query_invoice
)
# 财务也可在必要时转给技术
billing.register_tool(
name="transfer_to_tech_support",
description="如果用户在财务沟通过程中提出了系统崩溃、报错等技术问题,可调用此工具转交技术支持",
parameters={"type": "object", "properties": {"reason": {"type": "string"}}, "required": ["reason"]},
func=transfer_to_tech_support
)
agents[billing.name] = billing
# 3. 技术支持 Agent (Tech Support Agent)
tech = BaseAgent(
name="TechSupportAgent",
system_prompt="你是一位高级云运维工程师,负责诊断服务器运行状态、系统排错与运维指令下发。语言风格简练有力。"
)
tech.register_tool(
name="restart_server",
description="安全重启指定的云服务器实例",
parameters={
"type": "object",
"properties": {
"server_id": {"type": "string", "description": "服务器唯一实例标识符,例如 srv-bj-001"}
},
"required": ["server_id"]
},
func=tool_restart_server
)
agents[tech.name] = tech
return agents
# ==================== 5. 工业级多 Agent 调度编排引擎 ====================
class MultiAgentOrchestrator:
def __init__(self, agents: Dict[str, BaseAgent], max_hops: int = 5):
from openai import AsyncOpenAI
self.agents = agents
self.max_hops = max_hops
self.client = AsyncOpenAI(
api_key=os.getenv("OPENAI_API_KEY", "your-api-key"),
base_url=os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1")
)
async def execute_turn(self, user_query: str, session_context: AgentContext) -> str:
"""执行单轮用户交互,支持跨 Agent 动态接力"""
current_agent_name = "TriageAgent" # 默认由分诊前台接待
messages: List[Dict[str, Any]] = [
{"role": "user", "content": user_query}
]
logger.info(f"======== 开启会话执行: Session[{session_context.session_id}] ========")
logger.info(f"初始接待 Agent: [{current_agent_name}] | 用户输入: {user_query}")
while True:
# 1. 熔断与死循环检测
session_context.hop_count += 1
session_context.visited_history.append(current_agent_name)
if session_context.hop_count > self.max_hops:
logger.error(f"【熔断告警】Agent 切换跳数已达 {self.max_hops} 次,触发防爆机制!")
return "抱歉,当前业务协同流程较为复杂,已为您自动转接人工高级客服团队为您处理。"
# 环路检测 (简单乒乓环路判定)
if len(session_context.visited_history) >= 4:
last_four = session_context.visited_history[-4:]
if last_four[0] == last_four[2] and last_four[1] == last_four[3]:
logger.error(f"【环路告警】检测到 Agent 陷入乒乓震荡: {last_four},强行终止!")
return "系统检测到业务诉求存在循环转接,已终止自动化流程并记录日志。"
current_agent = self.agents[current_agent_name]
logger.info(f"--- [Hop {session_context.hop_count}] Agent 运行中: [{current_agent_name}] ---")
# 2. 构造符合当前 Agent 视角的独立上下文
turn_messages = [{"role": "system", "content": current_agent.system_prompt}] + messages
tools_schema = current_agent.get_tools_schema()
# 3. 发起大模型推理
try:
response = await self.client.chat.completions.create(
model=current_agent.model,
messages=turn_messages,
tools=tools_schema if tools_schema else None,
tool_choice="auto" if tools_schema else None,
temperature=0.0
)
except Exception as e:
logger.error(f"调用模型发生网络或鉴权异常: {e}")
return f"系统服务繁忙,底层调用失败: {str(e)}"
msg_obj = response.choices[0].message
tool_calls = msg_obj.tool_calls
# 4. 如果模型未发起工具调用,说明当前 Agent 已经可以给出最终结论
if not tool_calls:
logger.info(f"Agent [{current_agent_name}] 任务完成,准备输出最终答案。")
return msg_obj.content or "(无文本输出)"
# 5. 处理工具调用
# 记录模型的思考与工具调用意图
messages.append(msg_obj.model_dump(exclude_none=True))
for tool_call in tool_calls:
func_name = tool_call.function.name
func_args_raw = tool_call.function.arguments
logger.info(f"触发动作: [{current_agent_name}] -> Tool:[{func_name}] Args:{func_args_raw}")
target_tool = current_agent.tools.get(func_name)
if not target_tool:
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps({"error": f"Tool {func_name} not found"})
})
continue
try:
args_dict = json.loads(func_args_raw)
# 执行具体函数
result = await target_tool.func(**args_dict)
# 正常工具执行完成,将结果装入上下文
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"name": func_name,
"content": result
})
except HandoffSignal as handoff:
# 捕获到动态切换信号!
logger.warning(
f"【控制权移交】[{current_agent_name}] ➔ [{handoff.target_agent_name}] "
f"原因: {handoff.payload.get('reason')} | 携带载荷: {handoff.payload}"
)
# 核心技术点:无损上下文接力与精简
# 模拟向新 Agent 投递转移说明,并切换活跃指针
current_agent_name = handoff.target_agent_name
# 注入系统级切换通知,告知新 Agent 上下文由谁转交而来
messages.append({
"role": "system",
"content": f"[系统控制权变更] 本次对话已从前序部门移交给 {current_agent_name}。转交附言: {json.dumps(handoff.payload, ensure_ascii=False)}。请直接根据前序信息为用户办理,避免重复询问用户已知信息。"
})
# 跳出当前工具轮次,直接让新 Agent 接入下一个循环
break
# ==================== 6. 场景模拟与端到端运行验证 ====================
async def main():
agent_pool = create_agent_system()
orchestrator = MultiAgentOrchestrator(agent_pool, max_hops=4)
# 模拟用户 Session 状态
context_session_1 = AgentContext(session_id="SESS_8888", user_id="USER_001")
# 场景 A:财务发票诉求,测试 Triage -> Billing 动态接力
query_1 = "你好,请帮我查一下订单号 ORD-202607-99 的电子发票开具情况。"
print(f"\n==================== 测试用例 1 ====================")
answer_1 = await orchestrator.execute_turn(query_1, context_session_1)
print(f"\n【最终用户端收到的回复】:\n{answer_1}\n")
# 场景 B:技术运维诉求,测试 Triage -> TechSupport 动态接力
context_session_2 = AgentContext(session_id="SESS_9999", user_id="USER_002")
query_2 = "大事不好了!我们的生产服务器 srv-bj-001 发生告警,请帮我执行紧急重启!"
print(f"\n==================== 测试用例 2 ====================")
answer_2 = await orchestrator.execute_turn(query_2, context_session_2)
print(f"\n【最终用户端收到的回复】:\n{answer_2}\n")
if __name__ == "__main__":
asyncio.run(main())
六、 生产级可观测性与分布式追踪(Tracing & OpenTelemetry)
在单 Agent 系统中,排查错误只需查看单次请求的日志;但在多 Agent 系统中,一次用户提问可能触发 3 次 Agent 切换和 5 次工具调用。如果缺乏全链路追踪,线上排错将如同大海捞针。
┌────────────────────────────────────────────────────────────────────────┐
│ 多 Agent 分布式追踪 Span 拓扑模型 │
└──────────────────────────────────┬─────────────────────────────────────┘
│ Trace: session_trace_001
┌─────────────────────────────────┴─────────────────────────────────┐
│ Span 1: TriageAgent.execute (Duration: 350ms) │
│ ├─ Span 1.1: LLM.Generate (Prompt Tokens: 420, Output: 35) │
│ └─ Span 1.2: Tool.transfer_to_billing (Handoff Triggered) │
└─────────────────────────────────┬─────────────────────────────────┘
│ Context Propagation
┌─────────────────────────────────┴─────────────────────────────────┐
│ Span 2: BillingAgent.execute (Duration: 820ms) │
│ ├─ Span 2.1: LLM.Generate (Prompt Tokens: 610, Output: 40) │
│ ├─ Span 2.2: Tool.query_invoice (HTTP GET 200 OK) │
│ └─ Span 2.3: LLM.FinalSynthesis (Prompt Tokens: 750, Output: 90)│
└───────────────────────────────────────────────────────────────────┘
生产级追踪指标体系
构建多 Agent 系统时,必须将以下指标采集并接入 Prometheus/Grafana 或 Langfuse/Arize Phoenix:
-
Handoff Efficiency(移交有效率) :
有效移交率 = 成功在目标 Agent 解决的次数 / 触发 Handoff 的总次数若该比率过低,说明 Triage Agent 的路由 Prompt 需要重新调优。 -
Hop Count Distribution(跳数分布):监控 95% 的请求是否能在 2 跳内解决。若 P99 跳数显著升高,说明出现了冗余流转。
-
Per-Agent Token Consumption(Agent 维度成本分摊):精准统计每个专精 Agent 消耗的 Token 比例,定位系统中哪个 Agent 是"成本刺客"。
七、 总结与前沿演进
多 Agent 系统的协作与动态切换机制,是实现复杂场景企业级大模型落地的核心技术。
┌─────────────────────────────────────────────────────────────────────────┐
│ 多 Agent 协作系统设计演进四步法 │
├─────────────────────────────────────────────────────────────────────────┤
│ 1. 职责边界清晰化:每个 Agent 遵循单一职责原则,工具集控制在 3~5 个内 │
│ 2. 协议强类型化 :使用 Pydantic 规范 Handoff Payload,消灭无序上下文 │
│ 3. 运行防御前置化:设置跳数硬上限 (TTL)、环路哈希熔断与超时回滚 │
│ 4. 链路可观测化 :基于 OpenTelemetry 实现跨 Agent 级联分布式追踪 │
└─────────────────────────────────────────────────────────────────────────┘
随着多模态大模型与推理模型(Reasoning Models)的持续演进,多 Agent 正在从"静态手工编排 "向"基于环境反馈的自主动态拓扑生成"迈进。
理解并掌握多 Agent 的拓扑设计、状态接力协议与工程防御体系,将帮助架构师和开发者在面对高复杂度业务系统时,构建出兼具高智能、高鲁棒性与低成本的企业级 AI 应用基础设施。