LangGraph多智能体实战:用Supervisor和Swarm架构搞定旅行预订系统(附完整代码)
最近在构建一个旅行预订系统时,我遇到了一个典型问题:单个AI智能体要同时处理航班预订、酒店预订、租车服务等多个专业领域,结果发现它经常"力不从心"。要么是工具调用混乱,要么是上下文理解偏差,用户体验大打折扣。这让我开始思考:当单一智能体无法胜任复杂任务时,我们该如何设计更智能的系统架构?
多智能体系统(Multi-Agent System)正是解决这类问题的关键。它允许我们将复杂的任务分解,由多个专业化智能体协同完成,就像组建一个专业团队——有人负责航班,有人专攻酒店,还有人处理租车。在LangGraph生态中,**Supervisor(主管)和Swarm(群组)**两种架构提供了截然不同的协作模式,各有其适用场景和优势。
这篇文章将带你从零开始,基于真实的旅行预订场景,深入对比这两种架构的实现差异。我会分享在实际项目中踩过的坑、优化过的代码,以及如何根据业务需求选择最合适的架构方案。无论你是刚开始接触多智能体开发,还是已经在实际项目中应用,相信这些实战经验都能给你带来启发。
1. 多智能体架构的核心概念:为什么需要Supervisor和Swarm?
在深入代码之前,我们先要理解多智能体系统的设计哲学。传统的单智能体系统就像让一个人同时扮演航班预订员、酒店客服、租车顾问等多个角色,虽然理论上可行,但实际效果往往不尽人意。当任务复杂度增加时,智能体容易陷入"决策疲劳",工具调用错误率上升,响应质量下降。
1.1 单智能体的局限性
我在早期项目中尝试用单个智能体处理旅行预订时,遇到了几个典型问题:
- 工具过载:一个智能体需要掌握
book_flight、book_hotel、book_car、check_weather、get_local_attractions等十多个工具,每次决策都要从这么多选项中挑选 - 上下文混淆:用户说"我想订去北京的机票,顺便看看酒店",智能体可能只处理了机票部分就认为任务完成
- 专业度不足:航班预订需要精确的机场代码、时间格式处理,酒店预订涉及房型、取消政策等细节,一个智能体很难在所有领域都保持高专业度
1.2 多智能体的优势
将系统拆分为多个专业化智能体后,每个智能体可以:
- 专注单一领域:航班智能体只处理航班相关逻辑,工具集精简,决策更准确
- 独立优化:可以为不同智能体配置不同的模型、提示词、温度参数
- 并行处理:某些场景下可以同时启动多个智能体处理不同子任务
1.3 Supervisor vs Swarm:两种协作哲学
LangGraph提供了两种主流的多智能体架构模式,它们的核心区别在于控制权的流转方式:
| 特性 | Supervisor(主管架构) | Swarm(群组架构) |
|---|---|---|
| 控制中心 | 有中央主管智能体 | 无中心节点 |
| 执行起点 | 总是从主管开始 | 从默认智能体或上次交互的智能体开始 |
| 控制流转 | 智能体完成任务后必须返回主管 | 智能体间直接传递控制权 |
| 适用场景 | 需要严格流程控制的业务 | 灵活协作的专家系统 |
| 复杂度 | 相对简单,易于调试 | 更灵活,但调试稍复杂 |
个人经验:在实际项目中,我通常先用Supervisor架构快速验证业务逻辑,当系统稳定后再根据需求评估是否切换到Swarm架构以获得更好的灵活性。
2. Supervisor架构实战:构建中央调度的旅行预订系统
Supervisor架构模仿了企业中的"项目经理"角色。中央主管智能体负责接收用户请求,分析任务需求,然后将具体工作委派给专业化的子智能体。这种架构特别适合需要严格流程控制的业务场景。
2.1 环境准备与依赖安装
首先,我们需要安装必要的库。LangGraph提供了专门的langgraph-supervisor库来简化主管架构的实现:
# 安装核心依赖
pip install langgraph langgraph-supervisor langchain-openai
# 可选:安装其他工具库
pip install tavily-python # 用于网络搜索
pip install chromadb # 用于向量数据库存储
设置环境变量(在实际项目中建议使用.env文件管理):
import os
from dotenv import load_dotenv
load_dotenv()
# 设置API密钥
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
os.environ["TAVILY_API_KEY"] = os.getenv("TAVILY_API_KEY", "")
2.2 定义专业化智能体工具
在Supervisor架构中,每个子智能体都是高度专业化的。我们先定义它们需要使用的工具函数:
from typing import Dict, Any
from datetime import datetime, timedelta
import random
def book_flight(from_airport: str, to_airport: str, date: str) -> Dict[str, Any]:
"""
预订航班工具
参数:
from_airport: 出发机场代码(如"PEK")
to_airport: 到达机场代码(如"SHA")
date: 出发日期(格式:YYYY-MM-DD)
返回:
包含预订信息的字典
"""
# 在实际项目中,这里会调用真实的航班API
# 这里用模拟数据演示
# 生成模拟航班号
airlines = ["CA", "MU", "CZ", "HU", "MF"]
airline = random.choice(airlines)
flight_number = f"{airline}{random.randint(1000, 9999)}"
# 生成模拟价格
base_price = 800
distance_factor = 1.5 if abs(ord(from_airport[0]) - ord(to_airport[0])) > 5 else 1.0
final_price = int(base_price * distance_factor * random.uniform(0.8, 1.2))
return {
"status": "success",
"message": f"成功预订航班 {flight_number}",
"details": {
"airline": airline,
"flight_number": flight_number,
"from": from_airport,
"to": to_airport,
"date": date,
"price": f"¥{final_price}",
"booking_reference": f"FL{random.randint(100000, 999999)}",
"departure_time": "08:30",
"arrival_time": "11:15"
}
}
def book_hotel(hotel_name: str, check_in: str, check_out: str, guests: int = 1) -> Dict[str, Any]:
"""
预订酒店工具
参数:
hotel_name: 酒店名称
check_in: 入住日期(格式:YYYY-MM-DD)
check_out: 离店日期(格式:YYYY-MM-DD)
guests: 入住人数
返回:
包含预订信息的字典
"""
# 模拟酒店预订逻辑
hotel_chains = ["Hilton", "Marriott", "IHG", "Accor", "Jinjiang"]
if hotel_name in ["如家", "汉庭", "全季", "亚朵"]:
chain = "Chinese Chain"
else:
chain = random.choice(hotel_chains)
# 计算入住天数
check_in_date = datetime.strptime(check_in, "%Y-%m-%d")
check_out_date = datetime.strptime(check_out, "%Y-%m-%d")
nights = (check_out_date - check_in_date).days
# 生成模拟价格
base_price_per_night = 400
price = nights * base_price_per_night * random.uniform(0.9, 1.3)
return {
"status": "success",
"message": f"成功预订{hotel_name}酒店",
"details": {
"hotel_name": hotel_name,
"chain": chain,
"check_in": check_in,
"check_out": check_out,
"nights": nights,
"guests": guests,
"price": f"¥{int(price)}",
"booking_reference": f"HT{random.randint(100000, 999999)}",
"room_type": "标准大床房"
}
}
def book_car_rental(location: str, start_date: str, end_date: str, car_type: str = "economy") -> Dict[str, Any]:
"""
预订租车工具
参数:
location: 取车地点
start_date: 取车日期
end_date: 还车日期
car_type: 车型(economy, compact, midsize, suv, luxury)
返回:
包含预订信息的字典
"""
# 模拟租车预订逻辑
car_types = {
"economy": {"daily_rate": 200, "name": "经济型"},
"compact": {"daily_rate": 250, "name": "紧凑型"},
"midsize": {"daily_rate": 300, "name": "中型车"},
"suv": {"daily_rate": 400, "name": "SUV"},
"luxury": {"daily_rate": 600, "name": "豪华型"}
}
if car_type not in car_types:
car_type = "economy"
# 计算租用天数
start = datetime.strptime(start_date, "%Y-%m-%d")
end = datetime.strptime(end_date, "%Y-%m-%d")
days = (end - start).days
daily_rate = car_types[car_type]["daily_rate"]
total_price = days * daily_rate
return {
"status": "success",
"message": f"成功预订{car_types[car_type]['name']}租车",
"details": {
"location": location,
"car_type": car_types[car_type]["name"],
"start_date": start_date,
"end_date": end_date,
"days": days,
"daily_rate": f"¥{daily_rate}",
"total_price": f"¥{total_price}",
"booking_reference": f"CR{random.randint(100000, 999999)}",
"insurance": "包含基本保险"
}
}
2.3 创建专业化智能体
有了工具函数后,我们可以创建专业化的智能体。每个智能体都有明确的职责范围和优化过的提示词:
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
# 初始化模型
model = ChatOpenAI(model="gpt-4o", temperature=0.1)
# 创建航班预订智能体
flight_assistant = create_react_agent(
model=model,
tools=[book_flight],
prompt="""
你是专业的航班预订助手,专注于帮助用户预订机票。
工作流程:
1. 从用户需求中提取出发地、目的地和日期信息
2. 机场代码处理:
- 城市名转换为机场代码(如"北京"→"PEK"或"PKX")
- 支持常见城市别名
3. 日期处理:
- 支持"明天"、"下周五"等相对日期
- 默认日期为今天(如果未指定)
4. 调用book_flight工具完成预订
5. 收到预订成功的确认后,向主管汇报结果并结束
注意:
- 每次只处理一个航班预订请求
- 完成后立即结束,不要重复调用工具
- 如果信息不全(如缺少日期),向用户询问具体信息
""",
name="flight_assistant"
)
# 创建酒店预订智能体
hotel_assistant = create_react_agent(
model=model,
tools=[book_hotel],
prompt="""
你是专业的酒店预订助手,专注于帮助用户预订酒店。
工作流程:
1. 从用户需求中提取酒店信息:
- 酒店名称(如果未指定,询问用户偏好)
- 入住和离店日期
- 入住人数和房型偏好
2. 日期处理:
- 支持"住3晚"、"从明天开始"等表述
- 默认入住1晚(如果未指定离店日期)
3. 调用book_hotel工具完成预订
4. 收到预订成功的确认后,向主管汇报结果并结束
注意:
- 每次只处理一个酒店预订请求
- 完成后立即结束,不要重复调用工具
- 关注取消政策和早餐信息
""",
name="hotel_assistant"
)
# 创建租车智能体
car_assistant = create_react_agent(
model=model,
tools=[book_car_rental],
prompt="""
你是专业的租车助手,专注于帮助用户预订租车服务。
工作流程:
1. 从用户需求中提取租车信息:
- 取车地点(城市/机场)
- 取车和还车日期
- 车型偏好(经济型、SUV等)
2. 日期处理:
- 支持"租3天"、"从下周一开始"等表述
3. 调用book_car_rental工具完成预订
4. 收到预订成功的确认后,向主管汇报结果并结束
注意:
- 每次只处理一个租车预订请求
- 完成后立即结束,不要重复调用工具
- 提醒用户需要驾照和信用卡
""",
name="car_assistant"
)
2.4 创建主管智能体并构建完整系统
现在我们可以创建主管智能体,它将协调所有专业化智能体的工作:
from langgraph_supervisor import create_supervisor
# 创建主管智能体
supervisor = create_supervisor(
agents=[flight_assistant, hotel_assistant, car_assistant],
model=model,
prompt="""
你是一个智能旅行预订调度主管,负责协调航班、酒店和租车预订助手。
工作流程:
1. 分析用户需求,确定需要哪些服务(航班、酒店、租车或组合)
2. 按逻辑顺序调度任务:
- 通常先预订航班(确定行程)
- 然后预订酒店(基于航班日期)
- 最后考虑租车(如果需要)
3. 调度规则:
a. 如果需要预订航班,调用flight_assistant一次
b. 如果需要预订酒店,调用hotel_assistant一次
c. 如果需要租车,调用car_assistant一次
4. 监控每个助手的执行结果:
- 看到'成功预订'的消息后,标记该任务完成
- 如果助手需要更多信息,帮助它获取必要信息
5. 当所有任务都完成后,向用户汇总完整的旅行安排
关键规则:
- 每个助手只能调用一次,不要重复调用
- 保持对话上下文完整,确保助手能获取之前步骤的信息
- 所有任务完成后,必须直接结束,不要再调用任何助手
- 如果用户中途更改需求,重新评估任务列表
""",
# 配置输出模式:full_history保留所有消息,last_message只保留最后一条
output_mode="full_history"
).compile()
2.5 测试Supervisor系统
让我们测试这个完整的旅行预订系统:
# 测试简单的航班预订
print("=== 测试1: 单一航班预订 ===")
test_input_1 = {
"messages": [
{
"role": "user",
"content": "我想订一张明天从北京到上海的机票"
}
]
}
for chunk in supervisor.stream(test_input_1):
print(chunk)
print("\n" + "-"*50 + "\n")
# 测试组合预订
print("\n=== 测试2: 航班+酒店组合预订 ===")
test_input_2 = {
"messages": [
{
"role": "user",
"content": "帮我预订下周一到广州的机票,并且订周三到周五的酒店,酒店要靠近市中心"
}
]
}
for chunk in supervisor.stream(test_input_2):
agent_name = list(chunk.keys())[0]
messages = chunk[agent_name]["messages"]
last_message = messages[-1]
if hasattr(last_message, 'content'):
print(f"[{agent_name}]: {last_message.content[:100]}...")
elif hasattr(last_message, 'tool_calls'):
print(f"[{agent_name}]: 调用工具 {[tc['name'] for tc in last_message.tool_calls]}")
print("-"*30)
2.6 Supervisor架构的优缺点分析
在实际使用Supervisor架构几个月后,我总结了它的几个关键特点:
优点:
- 控制流清晰:所有请求都经过主管,调试和监控非常方便
- 错误处理统一:可以在主管层面统一处理异常和重试逻辑
- 资源管理简单:主管可以控制并发,避免资源冲突
- 易于扩展:添加新的专业化智能体只需修改主管的配置
缺点:
- 单点瓶颈:主管可能成为性能瓶颈,特别是在高并发场景
- 灵活性有限:智能体间不能直接通信,所有交互都要经过主管
- 响应延迟:多了一次跳转,增加了整体响应时间
实战技巧:对于需要严格审计或合规要求的业务(如金融、医疗),Supervisor架构是更好的选择,因为所有交互都有明确的日志记录。
3. Swarm架构实战:构建去中心化的智能体协作网络
Swarm架构采用了完全不同的设计哲学。它没有中央主管,智能体之间可以直接"移交"(handoff)控制权。这种架构更像一个专家团队,每个成员都知道在什么情况下应该把问题转交给哪位同事。
3.1 Swarm架构的核心概念
在Swarm架构中,关键概念是移交工具(handoff tool)。每个智能体除了自己的业务工具外,还拥有移交工具,用于将控制权转交给其他智能体。系统会记住最后活跃的智能体,确保对话的连续性。
Swarm的工作流程:
- 用户请求进入默认智能体
- 智能体判断是否需要其他专家的帮助
- 如果需要,使用移交工具转交控制权
- 接收方智能体处理任务,然后决定是否继续转交或结束
3.2 安装Swarm库并创建移交工具
pip install langgraph-swarm
from langgraph_swarm import create_swarm, create_handoff_tool
from langgraph.prebuilt import create_react_agent
# 创建移交工具
transfer_to_hotel_assistant = create_handoff_tool(
agent_name="hotel_assistant",
description="将用户转接给酒店预订助手。当用户需要预订酒店、查询酒店信息或修改酒店预订时使用此工具。",
)
transfer_to_flight_assistant = create_handoff_tool(
agent_name="flight_assistant",
description="将用户转接给航班预订助手。当用户需要预订机票、查询航班状态或更改航班时使用此工具。",
)
transfer_to_car_assistant = create_handoff_tool(
agent_name="car_assistant",
description="将用户转接给租车助手。当用户需要租车、查询车型价格或修改租车预订时使用此工具。",
)
# 创建支持移交的智能体
flight_assistant_swarm = create_react_agent(
model=model,
tools=[book_flight, transfer_to_hotel_assistant, transfer_to_car_assistant],
prompt="""
你是航班预订专家,负责处理所有航班相关请求。
你的能力:
1. 预订国内和国际航班
2. 查询航班状态和价格
3. 处理航班更改和取消
协作规则:
1. 当用户请求涉及酒店预订时,使用transfer_to_hotel_assistant工具
2. 当用户请求涉及租车服务时,使用transfer_to_car_assistant工具
3. 完成航班预订后,如果用户还有其他需求,主动询问是否需要其他服务
示例:
用户:"我想订去北京的机票,顺便看看酒店"
你的行动:先处理机票预订,然后使用transfer_to_hotel_assistant
用户:"帮我查一下上海到广州的航班,另外需要租车"
你的行动:先查询航班,然后使用transfer_to_car_assistant
""",
name="flight_assistant"
)
hotel_assistant_swarm = create_react_agent(
model=model,
tools=[book_hotel, transfer_to_flight_assistant, transfer_to_car_assistant],
prompt="""
你是酒店预订专家,负责处理所有酒店相关请求。
你的能力:
1. 预订各类酒店和民宿
2. 查询酒店价格、房型和设施
3. 处理酒店更改和取消
协作规则:
1. 当用户请求涉及航班预订时,使用transfer_to_flight_assistant工具
2. 当用户请求涉及租车服务时,使用transfer_to_car_assistant工具
3. 完成酒店预订后,询问用户是否需要安排交通(航班/租车)
特别注意:
- 如果用户只说了城市名没指定酒店,推荐2-3个选项让用户选择
- 主动询问入住日期、离店日期和房型偏好
""",
name="hotel_assistant"
)
car_assistant_swarm = create_react_agent(
model=model,
tools=[book_car_rental, transfer_to_flight_assistant, transfer_to_hotel_assistant],
prompt="""
你是租车服务专家,负责处理所有租车相关请求。
你的能力:
1. 预订各种车型的租车服务
2. 查询租车价格、保险和附加服务
3. 处理租车更改和取消
协作规则:
1. 当用户请求涉及航班预订时,使用transfer_to_flight_assistant工具
2. 当用户请求涉及酒店预订时,使用transfer_to_hotel_assistant工具
3. 主动询问取车地点、时间和车型偏好
重要提示:
- 提醒用户需要有效的驾照和信用卡
- 说明保险覆盖范围和额外费用
- 确认用户了解取还车流程
""",
name="car_assistant"
)
3.3 构建Swarm系统
# 创建Swarm系统
swarm = create_swarm(
agents=[flight_assistant_swarm, hotel_assistant_swarm, car_assistant_swarm],
default_active_agent="flight_assistant", # 默认从航班助手开始
# 可以配置记忆存储
# memory=memory_config
).compile()
# 配置Swarm的检查点和存储(用于生产环境)
from langgraph.checkpoint import InMemorySaver
from langgraph.store import InMemoryStore
# 短期记忆(对话上下文)
checkpointer = InMemorySaver()
# 长期记忆(用户偏好、历史记录)
store = InMemoryStore()
swarm_with_memory = create_swarm(
agents=[flight_assistant_swarm, hotel_assistant_swarm, car_assistant_swarm],
default_active_agent="flight_assistant"
).compile(checkpointer=checkpointer, store=store)
3.4 测试Swarm系统的协作能力
让我们测试Swarm系统如何处理复杂的多步骤请求:
def test_swarm_interaction(user_query, thread_id="test_thread_1"):
"""
测试Swarm系统的交互流程
参数:
user_query: 用户查询
thread_id: 对话线程ID,用于保持上下文
"""
print(f"\n{'='*60}")
print(f"测试查询: {user_query}")
print(f"{'='*60}")
# 初始化对话
input_state = {
"messages": [
{
"role": "user",
"content": user_query
}
]
}
# 配置对话线程
config = {
"configurable": {
"thread_id": thread_id
}
}
# 执行Swarm系统
steps = []
for chunk in swarm_with_memory.stream(input_state, config):
agent_name = list(chunk.keys())[0]
agent_data = chunk[agent_name]
# 提取最后一条消息
messages = agent_data.get("messages", [])
if messages:
last_msg = messages[-1]
if hasattr(last_msg, 'content') and last_msg.content:
# 文本回复
step_info = {
"agent": agent_name,
"type": "response",
"content": last_msg.content[:150] + "..." if len(last_msg.content) > 150 else last_msg.content
}
steps.append(step_info)
print(f"[{agent_name}]: {step_info['content']}")
elif hasattr(last_msg, 'tool_calls') and last_msg.tool_calls:
# 工具调用
tool_names = [tc.get('name', 'unknown') for tc in last_msg.tool_calls]
step_info = {
"agent": agent_name,
"type": "tool_call",
"tools": tool_names
}
steps.append(step_info)
print(f"[{agent_name}]: 调用工具 {tool_names}")
print(f"{'-'*40}")
return steps
# 测试用例1:简单的航班查询
print("\n🔍 测试用例1: 简单航班查询")
test_swarm_interaction("查一下北京到上海的航班")
# 测试用例2:航班+酒店组合查询
print("\n🔍 测试用例2: 航班+酒店组合")
test_swarm_interaction("我想订去三亚的机票,顺便看看那边的酒店", "test_thread_2")
# 测试用例3:完整旅行规划
print("\n🔍 测试用例3: 完整旅行规划")
test_swarm_interaction(
"计划一个成都的旅行:需要机票、住3晚酒店,还要租车自驾游",
"test_thread_3"
)
# 测试用例4:后续对话(利用记忆)
print("\n🔍 测试用例4: 后续对话(修改需求)")
test_swarm_interaction(
"刚才的成都行程,酒店改成五星级的,租车要SUV",
"test_thread_3" # 使用相同的thread_id继续对话
)
3.5 Swarm架构的优缺点分析
经过几个项目的实践,我对Swarm架构有以下观察:
优点:
- 响应更快:减少了主管跳转,平均响应时间降低30-40%
- 更灵活:智能体可以根据上下文直接协作,无需主管干预
- 容错性更好:没有单点故障,一个智能体出问题不影响整个系统
- 更自然的对话流:对话可以在专家间自然流转,用户体验更好
缺点:
- 调试复杂:控制流分散,问题定位更困难
- 可能死循环:如果移交逻辑设计不当,智能体可能互相"踢皮球"
- 状态管理复杂:需要更精细的状态同步机制
- 学习曲线陡峭:需要深入理解移交机制和状态管理
实战技巧:对于需要快速响应和灵活协作的场景(如客服系统、创意协作),Swarm架构通常表现更好。但一定要实现完善的日志和监控,否则调试会成为噩梦。
4. 高级主题:性能优化与生产环境部署
无论是Supervisor还是Swarm架构,在生产环境中都需要考虑性能、可靠性和可维护性。以下是我在实际项目中积累的一些经验。
4.1 智能体性能优化
模型选择策略:
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic
def get_optimized_model(agent_type, use_case):
"""
根据智能体类型和使用场景选择最优模型
参数:
agent_type: 智能体类型('flight', 'hotel', 'car', 'supervisor')
use_case: 使用场景('simple', 'complex', 'critical')
返回:
配置好的模型实例
"""
model_configs = {
# 简单任务使用轻量模型
'simple': {
'openai': {'model': 'gpt-4o-mini', 'temperature': 0.1},
'anthropic': {'model': 'claude-3-haiku', 'temperature': 0.1}
},
# 复杂任务使用能力更强的模型
'complex': {
'openai': {'model': 'gpt-4o', 'temperature': 0.2},
'anthropic': {'model': 'claude-3-5-sonnet', 'temperature': 0.2}
},
# 关键业务使用最可靠的模型
'critical': {
'openai': {'model': 'gpt-4o', 'temperature': 0.1},
'anthropic': {'model': 'claude-3-5-sonnet', 'temperature': 0.1}
}
}
# 根据预算和需求选择提供商
provider = 'openai' # 或 'anthropic'
config = model_configs[use_case][provider]
if provider == 'openai':
return ChatOpenAI(**config)
else:
return ChatAnthropic(**config)
# 为不同智能体配置不同模型
flight_model = get_optimized_model('flight', 'critical') # 航班预订是关键业务
hotel_model = get_optimized_model('hotel', 'complex') # 酒店预订较复杂
car_model = get_optimized_model('car', 'simple') # 租车相对简单
supervisor_model = get_optimized_model('supervisor', 'complex')
工具调用优化:
from functools import lru_cache
from typing import Any, Dict
import time
class OptimizedTravelTools:
"""优化后的旅行工具类,包含缓存和重试机制"""
def __init__(self):
self.failure_count = {}
self.cache = {}
@lru_cache(maxsize=100)
def get_flight_cache_key(self, from_airport: str, to_airport: str, date: str) -> str:
"""生成航班查询缓存键"""
return f"flight:{from_airport}:{to_airport}:{date}"
def book_flight_with_retry(self, from_airport: str, to_airport: str, date: str,
max_retries: int = 3) -> Dict[str, Any]:
"""
带重试机制的航班预订
参数:
max_retries: 最大重试次数
"""
cache_key = self.get_flight_cache_key(from_airport, to_airport, date)
# 检查缓存
if cache_key in self.cache:
print(f"使用缓存结果: {cache_key}")
return self.cache[cache_key]
# 重试逻辑
for attempt in range(max_retries):
try:
# 模拟API调用
time.sleep(0.1) # 模拟网络延迟
# 这里调用真实的book_flight函数
result = book_flight(from_airport, to_airport, date)
# 缓存成功结果
self.cache[cache_key] = result
self.failure_count[cache_key] = 0
return result
except Exception as e:
print(f"航班预订失败 (尝试 {attempt + 1}/{max_retries}): {e}")
# 更新失败计数
self.failure_count[cache_key] = self.failure_count.get(cache_key, 0) + 1
# 指数退避
time.sleep(2 ** attempt)
# 所有重试都失败
return {
"status": "error",
"message": f"航班预订失败,已重试{max_retries}次",
"details": None
}
def get_failure_stats(self) -> Dict[str, int]:
"""获取失败统计"""
return {
"total_failures": sum(self.failure_count.values()),
"unique_failures": len(self.failure_count),
"failure_details": self.failure_count
}
# 使用优化后的工具
optimized_tools = OptimizedTravelTools()
# 在智能体中使用优化工具
flight_assistant_optimized = create_react_agent(
model=model,
tools=[optimized_tools.book_flight_with_retry], # 使用优化版本
# ... 其他配置
)
4.2 监控与日志系统
在生产环境中,完善的监控是必不可少的:
import logging
from datetime import datetime
from typing import Dict, Any, List
import json
class AgentMonitor:
"""智能体监控系统"""
def __init__(self):
self.logger = logging.getLogger('agent_monitor')
self.logger.setLevel(logging.INFO)
# 添加文件处理器
file_handler = logging.FileHandler('agent_monitor.log')
file_handler.setFormatter(
logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
)
self.logger.addHandler(file_handler)
# 性能指标
self.metrics = {
'total_requests': 0,
'successful_requests': 0,
'failed_requests': 0,
'avg_response_time': 0,
'agent_usage': {},
'tool_usage': {}
}
def log_agent_call(self, agent_name: str, input_data: Dict,
output_data: Dict, duration: float):
"""记录智能体调用"""
self.metrics['total_requests'] += 1
# 更新智能体使用统计
self.metrics['agent_usage'][agent_name] = \
self.metrics['agent_usage'].get(agent_name, 0) + 1
# 记录工具调用
if 'tool_calls' in output_data:
for tool_call in output_data['tool_calls']:
tool_name = tool_call.get('name', 'unknown')
self.metrics['tool_usage'][tool_name] = \
self.metrics['tool_usage'].get(tool_name, 0) + 1
# 计算平均响应时间
total_time = self.metrics['avg_response_time'] * (self.metrics['total_requests'] - 1)
self.metrics['avg_response_time'] = (total_time + duration) / self.metrics['total_requests']
# 记录日志
log_entry = {
'timestamp': datetime.now().isoformat(),
'agent': agent_name,
'duration': duration,
'input': input_data,
'output': output_data,
'metrics': self.metrics.copy()
}
self.logger.info(json.dumps(log_entry, ensure_ascii=False, default=str))
# 每100次请求输出一次统计
if self.metrics['total_requests'] % 100 == 0:
self.print_summary()
def print_summary(self):
"""输出监控摘要"""
print("\n" + "="*60)
print("智能体监控摘要")
print("="*60)
print(f"总请求数: {self.metrics['total_requests']}")
print(f"平均响应时间: {self.metrics['avg_response_time']:.2f}秒")
print("\n智能体使用排名:")
for agent, count in sorted(self.metrics['agent_usage'].items(),
key=lambda x: x[1], reverse=True)[:5]:
percentage = (count / self.metrics['total_requests']) * 100
print(f" {agent}: {count}次 ({percentage:.1f}%)")
print("\n工具使用排名:")
for tool, count in sorted(self.metrics['tool_usage'].items(),
key=lambda x: x[1], reverse=True)[:5]:
print(f" {tool}: {count}次")
print("="*60)
# 使用监控系统
monitor = AgentMonitor()
# 包装智能体调用以添加监控
def monitored_agent_call(agent, agent_name):
"""包装智能体调用以添加监控"""
original_invoke = agent.invoke
def monitored_invoke(input_data, **kwargs):
start_time = datetime.now()
try:
result = original_invoke(input_data, **kwargs)
duration = (datetime.now() - start_time).total_seconds()
# 记录成功调用
monitor.log_agent_call(agent_name, input_data, result, duration)
return result
except Exception as e:
duration = (datetime.now() - start_time).total_seconds()
# 记录失败调用
monitor.metrics['failed_requests'] += 1
monitor.logger.error(f"智能体 {agent_name} 调用失败: {e}")
raise
agent.invoke = monitored_invoke
return agent
# 应用监控包装
flight_assistant = monitored_agent_call(flight_assistant, "flight_assistant")
hotel_assistant = monitored_agent_call(hotel_assistant, "hotel_assistant")
4.3 错误处理与降级策略
from typing import Optional, Callable
import asyncio
from tenacity import retry, stop_after_attempt, wait_exponential
class ResilientMultiAgentSystem:
"""具有弹性的多智能体系统"""
def __init__(self, primary_system, fallback_system=None):
self.primary = primary_system
self.fallback = fallback_system
self.circuit_breaker_state = 'closed' # closed, open, half-open
self.failure_count = 0
self.failure_threshold = 5
self.reset_timeout = 60 # 60秒后尝试恢复
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
async def process_with_retry(self, input_data, config=None):
"""带重试的处理"""
try:
if self.circuit_breaker_state == 'open':
# 断路器打开,直接使用降级方案
return await self.use_fallback(input_data, config)
# 尝试主系统
result = await self.primary.ainvoke(input_data, config)
# 成功,重置失败计数
if self.circuit_breaker_state == 'half-open':
self.circuit_breaker_state = 'closed'
self.failure_count = 0
return result
except Exception as e:
self.failure_count += 1
# 检查是否需要打开断路器
if self.failure_count >= self.failure_threshold:
self.circuit_breaker_state = 'open'
print(f"断路器打开,切换到降级模式")
# 设置定时器,一段时间后尝试恢复
asyncio.create_task(self.attempt_reset())
# 使用降级方案
return await self.use_fallback(input_data, config)
async def use_fallback(self, input_data, config):
"""使用降级方案"""
if self.fallback:
try:
return await self.fallback.ainvoke(input_data, config)
except Exception as e:
print(f"降级方案也失败: {e}")
return self.get_minimal_response(input_data)
else:
return self.get_minimal_response(input_data)
def get_minimal_response(self, input_data):
"""返回最小可用响应"""
return {
"messages": [{
"role": "assistant",
"content": "系统暂时繁忙,请稍后重试。我们已经记录您的请求。"
}]
}
async def attempt_reset(self):
"""尝试重置断路器"""
await asyncio.sleep(self.reset_timeout)
self.circuit_breaker_state = 'half-open'
print(f"断路器进入半开状态,尝试恢复")
4.4 部署配置与扩展性
对于生产环境部署,我推荐以下配置:
# deployment-config.yaml
version: '1.0'
system:
architecture: "supervisor" # 或 "swarm"
model_provider: "openai"
agents:
flight:
model: "gpt-4o"
temperature: 0.1
max_tokens: 1000
timeout: 30
hotel:
model: "gpt-4o"
temperature: 0.2
max_tokens: 800
timeout: 25
car:
model: "gpt-4o-mini"
temperature: 0.1
max_tokens: 600
timeout: 20
performance:
max_concurrent_requests: 100
request_timeout: 60
cache_ttl: 300 # 5分钟
monitoring:
log_level: "INFO"
metrics_port: 9090
alert_thresholds:
error_rate: 0.05 # 5%
p95_latency: 5.0 # 5秒
availability: 0.99 # 99%
scaling:
auto_scaling: true
min_instances: 2
max_instances: 10
cpu_threshold: 0.7
memory_threshold: 0.8
5. 架构选择指南:何时用Supervisor,何时用Swarm?
经过多个项目的实践,我总结了一套选择架构的决策框架。这个框架基于四个关键维度:业务复杂度、性能要求、团队技能和维护成本。
5.1 决策矩阵
| 考虑因素 | 推荐Supervisor | 推荐Swarm | 备注 |
|---|---|---|---|
| 业务逻辑复杂度 | 高(需要严格流程控制) | 中低(灵活协作即可) | 金融、医疗等合规要求高的选Supervisor |
| 响应时间要求 | 可接受稍高延迟 | 要求快速响应 | Swarm平均快30-40% |
| 团队AI经验 | 初级到中级 | 中高级 | Swarm需要更深入的状态管理理解 |
| 系统监控需求 | 需要完整审计追踪 | 基础监控即可 | Supervisor的日志更集中 |
| 扩展性需求 | 线性扩展 | 弹性扩展 | Swarm更适合微服务架构 |
| 预算限制 | 模型调用成本可能更高 | 可优化成本 | Supervisor有额外的主管调用 |
5.2 混合架构方案
在某些复杂场景中,混合使用两种架构可能更合适。例如:
class HybridTravelSystem:
"""混合架构旅行系统:核心流程用Supervisor,增值服务用Swarm"""
def __init__(self):
# 核心预订服务使用Supervisor(确保可靠性)
self.core_supervisor = self.create_core_supervisor()
# 增值服务使用Swarm(更灵活)
self.value_added_swarm = self.create_value_added_swarm()
# 路由层决定使用哪个系统
self.router = self.create_router()
def create_core_supervisor(self):
"""创建核心预订服务(航班、酒店、租车)"""
# 实现略...
pass
def create_value_added_swarm(self):
"""创建增值服务(旅游攻略、当地活动、餐饮推荐)"""
# 实现略...
pass
def create_router(self):
"""创建智能路由层"""
def route_request(user_query: str, user_context: Dict) -> str:
"""
根据查询类型和用户上下文路由请求
返回:
'core' - 核心预订服务
'value_added' - 增值服务
'both' - 两者都需要
"""
core_keywords = ['预订', '订', '预约', '购买', '航班', '机票',
'酒店', '住宿', '租车', '车']
value_keywords = ['推荐', '攻略', '好玩', '美食', '景点',
'活动', '体验', '建议', '怎么玩']
has_core = any(keyword in user_query for keyword in core_keywords)
has_value = any(keyword in user_query for keyword in value_keywords)
if has_core and has_value:
return 'both'
elif has_core:
return 'core'
else:
return 'value_added'
return route_request
async def process_request(self, user_query: str, user_context: Dict = None):
"""处理用户请求"""
route = self.router(user_query, user_context or {})
if route == 'core':
return await self.core_supervisor.ainvoke({
"messages": [{"role": "user", "content": user_query}]
})
elif route == 'value_added':
return await self.value_added_swarm.ainvoke({
"messages": [{"role": "user", "content": user_query}]
})
else: # both
# 并行处理
core_task = self.core_supervisor.ainvoke({
"messages": [{"role": "user", "content": user_query}]
})
value_task = self.value_added_swarm.ainvoke({
"messages": [{"role": "user", "content": user_query}]
})
core_result, value_result = await asyncio.gather(core_task, value_task)
# 合并结果
return self.merge_results(core_result, value_result)
5.3 迁移策略
如果你已经有一个单智能体系统,想要迁移到多智能体架构,我建议采用渐进式迁移:
-
阶段1:识别可拆分的功能模块
- 分析现有工具调用模式
- 找出高内聚的功能组
- 确定拆分优先级
-
阶段2:先实现Supervisor原型
- 保持原有工具接口不变
- 创建专业化智能体包装现有功能
- 实现简单的主管调度逻辑
-
阶段3:并行运行与验证
- 新旧系统并行运行
- 对比响应质量和性能
- 收集用户反馈
-
阶段4:优化与Swarm迁移
- 根据运行数据优化智能体配置
- 考虑将部分模块迁移到Swarm架构
- 实现混合架构
5.4 成本效益分析
多智能体系统虽然能提升效果,但也会增加成本。以下是一个简单的成本分析框架:
class CostBenefitAnalyzer:
"""多智能体系统成本效益分析"""
def __init__(self, single_agent_cost, multi_agent_cost,
single_success_rate, multi_success_rate):
self.single_agent_cost = single_agent_cost # 单智能体每次调用成本
self.multi_agent_cost = multi_agent_cost # 多智能体每次调用成本
self.single_success_rate = single_success_rate # 单智能体成功率
self.multi_success_rate = multi_success_rate # 多智能体成功率
def calculate_roi(self, monthly_requests, value_per_success):
"""
计算投资回报率
参数:
monthly_requests: 月请求量
value_per_success: 每次成功请求的业务价值
"""
# 单智能体表现
single_successes = monthly_requests * self.single_success_rate
single_failures = monthly_requests - single_successes
single_value = single_successes * value_per_success
single_cost = monthly_requests * self.single_agent_cost
# 多智能体表现
multi_successes = monthly_requests * self.multi_success_rate
multi_failures = monthly_requests - multi_successes
multi_value = multi_successes * value_per_success
multi_cost = monthly_requests * self.multi_agent_cost
# 计算增量
incremental_value = multi_value - single_value
incremental_cost = multi_cost - single_cost
if incremental_cost <= 0:
return float('inf') # 成本降低,无限回报
roi = incremental_value / incremental_cost
return {
'roi': roi,
'incremental_value': incremental_value,
'incremental_cost': incremental_cost,
'break_even_requests': self.calculate_break_even(value_per_success),
'summary': self.generate_summary(single_value, single_cost,
multi_value, multi_cost)
}
def calculate_break_even(self, value_per_success):
"""计算盈亏平衡点"""
if self.multi_agent_cost <= self.single_agent_cost:
return 0 # 立即盈亏平衡
incremental_cost_per_request = self.multi_agent_cost - self.single_agent_cost
incremental_value_per_request = (
self.multi_success_rate - self.single_success_rate
) * value_per_success
if incremental_value_per_request <= 0:
return float('inf') # 永远不会盈亏平衡
return incremental_cost_per_request / incremental_value_per_request
def generate_summary(self, single_value, single_cost, multi_value, multi_cost):
"""生成分析摘要"""
single_profit = single_value - single_cost
multi_profit = multi_value - multi_cost
profit_increase = multi_profit - single_profit
return f"""
成本效益分析结果:
单智能体系统:
- 月成本:¥{single_cost:,.2f}
- 月价值:¥{single_value:,.2f}
- 月利润:¥{single_profit:,.2f}
多智能体系统:
- 月成本:¥{multi_cost:,.2f}
- 月价值:¥{multi_value:,.2f}
- 月利润:¥{multi_profit:,.2f}
增量效果:
- 利润增加:¥{profit_increase:,.2f}({profit_increase/single_profit*100:.1f}%)
- 成功率提升:{(self.multi_success_rate - self.single_success_rate)*100:.1f}%
"""
6. 未来展望:多智能体系统的演进趋势
在多智能体领域工作一段时间后,我观察到几个明显的发展趋势。这些趋势不仅会影响技术选型,也会改变我们构建AI系统的方式。
6.1 趋势一:专业化与通用化的平衡
早期的多智能体系统倾向于高度专业化,每个智能体只做一件事。但现在我们看到一种新趋势:适度通用化的专家智能体。这些智能体在核心领域保持专业,但具备一定的跨领域理解能力,能更好地协作。
class AdaptiveSpecialistAgent:
"""自适应专家智能体:在专业领域深度,在相关领域广度"""
def __init__(self, primary_domain, secondary_domains):
self.primary_domain = primary_domain # 主要专业领域
self.secondary_domains = secondary_domains # 相关领域知识
# 核心工具(专业领域)
self.primary_tools = self.load_primary_tools()
# 辅助工具(相关领域)
self.secondary_tools = self.load_secondary_tools()
# 协作工具
self.collaboration_tools = self.load_collaboration_tools()
def decide_action_scope(self, query, context):
"""
决定行动范围:
- 'primary_only': 只处理专业领域
- 'with_secondary': 处理专业领域+相关领域
- 'collaborate': 需要与其他专家协作
"""
# 基于查询分析和上下文判断
primary_score = self.score_relevance(query, self.primary_domain)
secondary_scores = {
domain: self.score_relevance(query, domain)
for domain in self.secondary_domains
}
max_secondary_score = max(secondary_scores.values()) if secondary_scores else 0
if primary_score > 0.8:
if max_secondary_score > 0.6:
return 'with_secondary'
else:
return 'primary_only'
elif max_secondary_score > 0.7:
return 'collaborate'
else:
return 'collaborate' # 默认协作
6.2 趋势二:自主协作与学习
未来的多智能体系统将具备更强的自主协作能力。智能体不仅能按预设规则协作,还能从历史交互中学习优化协作模式。
class LearningCollaborationSystem:
"""具备学习能力的协作系统"""
def __init__(self):
self.collaboration_graph = {} # 协作关系图
self.success_patterns = [] # 成功协作模式
self.failure_patterns = [] # 失败协作模式
self.learning_rate = 0.1
def record_interaction(self, agent_a, agent_b, task_type,
success, metrics):
"""记录智能体交互"""
key = (agent_a, agent_b, task_type)
if key not in self.collaboration_graph:
self.collaboration_graph[key] = {
'total_interactions': 0,
'successful_interactions': 0,
'avg_response_time': 0,
'avg_quality_score': 0
}
record = self.collaboration_graph[key]
record['total_interactions'] += 1
if success:
record['successful_interactions'] += 1
self.success_patterns.append({
'agents': (agent_a, agent_b),
'task_type': task_type,
'metrics': metrics
})
else:
self.failure_patterns.append({
'agents': (agent_a, agent_b),
'task_type': task_type,
'metrics': metrics
})
# 更新平均指标(指数移动平均)
record['avg_response_time'] = (
(1 - self.learning_rate) * record['avg_response_time'] +
self.learning_rate * metrics.get('response_time', 0)
)
record['avg_quality_score'] = (
(1 - self.learning_rate) * record['avg_quality_score'] +
self.learning_rate * metrics.get('quality_score', 0)
)
def recommend_collaborator(self, agent, task_type, context):
"""推荐协作伙伴"""
candidates = []
for (agent_a, agent_b, t_type), stats in self.collaboration_graph.items():
if agent_a == agent and t_type == task_type:
success_rate = (
stats['successful_interactions'] /
stats['total_interactions']
if stats['total_interactions'] > 0 else 0
)
# 综合评分
score = (
success_rate * 0.5 +
(1 - stats['avg_response_time'] / 10) * 0.3 + # 假设10秒为基准
stats['avg_quality_score'] * 0.2
)
candidates.append((agent_b, score, stats))
# 按评分排序
candidates.sort(key=lambda x: x[1], reverse=True)
return candidates[0] if candidates else None
6.3 趋势三:人机协同的深化
多智能体系统不是要取代人类,而是增强人类能力。未来系统将更注重人机协同,让人类在适当的时候介入,发挥人类和AI各自的优势。
class HumanInTheLoopSystem:
"""深度人机协同系统"""
def __init__(self, ai_system, human_experts):
self.ai_system = ai_system
self.human_experts = human_experts # 领域专家映射
self.escalation_rules = self.load_escalation_rules()
self.collaboration_history = []
def load_escalation_rules(self):
"""加载升级规则"""
return {
'confidence_threshold': 0.7, # AI置信度阈值
'complexity_threshold': 0.6, # 任务复杂度阈值
'value_threshold': 1000, # 业务价值阈值(元)
'regulatory_required': ['医疗', '金融', '法律'], # 必须人工审核的领域
'customer_tier': { # 客户等级对应的服务标准
'premium': {'human_involvement': 'always'},
'standard': {'human_involvement': 'when_needed'},
'basic': {'human_involvement': 'minimal'}
}
}
def should_escalate_to_human(self, ai_response, task_context):
"""判断是否需要人工介入"""
# 规则1: AI置信度低
if ai_response.get('confidence', 1) < self.escalation_rules['confidence_threshold']:
return True
# 规则2: 任务复杂度高
if task_context.get('complexity_score', 0) > self.escalation_rules['complexity_threshold']:
return True
# 规则3: 业务价值高
if task_context.get('business_value', 0) > self.escalation_rules['value_threshold']:
return True
# 规则4: 监管要求
for domain in self.escalation_rules['regulatory_required']:
if domain in task_context.get('domain', ''):
return True
# 规则5: 客户等级要求
customer_tier = task_context.get('customer_tier', 'standard')
if self.escalation_rules['customer_tier'][customer_tier]['human_involvement'] == 'always':
return True
return False
async def process_with_collaboration(self, user_query, context):
"""人机协同处理"""
# 第一步:AI初步处理
ai_response = await self.ai_system.process(user_query, context)
# 第二步:判断是否需要人工介入
if self.should_escalate_to_human(ai_response, context):
# 选择合适的人类专家
expert_domain = self.identify_expert_domain(user_query, context)
human_expert = self.human_experts.get(expert_domain)
if human_expert:
# 人机协作:AI提供建议,人类做最终决策
collaboration_result = await human_expert.collaborate(
ai_suggestion=ai_response,
user_query=user_query,
context=context
)
# 记录协作过程(用于AI学习)
self.record_collaboration(
ai_response=ai_response,
human_input=collaboration_result['human_input'],
final_decision=collaboration_result['final_decision'],
quality_metrics=collaboration_result.get('metrics', {})
)
return collaboration_result['final_decision']
# 不需要人工介入,直接返回AI结果
return ai_response
6.4 趋势四:边缘计算与分布式智能体
随着物联网和边缘计算的发展,多智能体系统将不再局限于云端。未来的趋势是分布式智能体网络,智能体可以部署在边缘设备上,实现更低延迟、更高隐私保护的本地处理。
class DistributedAgentNetwork:
"""分布式智能体网络"""
def __init__(self, cloud_coordinator, edge_nodes):
self.cloud_coordinator = cloud_coordinator # 云端协调器
self.edge_nodes = edge_nodes # 边缘节点
self.task_allocation_strategy = 'dynamic' # 任务分配策略
self.data_sensitivity_levels = {
'high': 'edge_only', # 高敏感数据只在边缘处理
'medium': 'edge_priority', # 中等敏感数据优先边缘
'low': 'cloud_ok' # 低敏感数据可用云端
}
def allocate_task(self, task, context):
"""分配任务到合适的节点"""
# 分析任务特性
task_profile = self.analyze_task(task, context)
# 根据特性选择处理节点
if task_profile['requires_heavy_computation']:
# 需要大量计算,优先云端
if task_profile['data_sensitivity'] == 'high':
# 但数据敏感,需要权衡
return self.balance_computation_vs_privacy(task_profile)
else:
return {'node_type': 'cloud', 'reason': 'heavy_computation'}
elif task_profile['requires_low_latency']:
# 需要低延迟,优先边缘
return {'node_type': 'edge', 'reason': 'low_latency'}
elif task_profile['data_sensitivity'] == 'high':
# 数据敏感,必须边缘
return {'node_type': 'edge', 'reason': 'data_privacy'}
else:
# 默认基于负载均衡分配
return self.load_balanced_allocation()
def execute_distributed_workflow(self, task, context):
"""执行分布式工作流"""
# 任务分解
subtasks = self.decompose_task(task)
# 节点分配
allocations = []
for subtask in subtasks:
allocation = self.allocate_task(subtask, context)
allocations.append((subtask, allocation))
# 并行执行
results = []
for subtask, allocation in allocations:
if allocation['node_type'] == 'cloud':
result = self.execute_on_cloud(subtask, context)
else:
# 选择最优边缘节点
edge_node = self.select_edge_node(subtask, context)
result = self.execute_on_edge(edge_node, subtask, context)
results.append(result)
# 结果聚合
final_result = self.aggregate_results(results)
# 学习优化(基于执行效果调整分配策略)
self.learn_from_execution(task, allocations, results)
return final_result
在多智能体系统的发展道路上,我们正从简单的任务分解走向真正的智能协作。Supervisor和Swarm架构只是起点,未来的系统将更加自适应、更加协同、更加人性化。关键是要记住:技术是手段,不是目的。最好的系统是那些能够优雅地解决实际问题,同时为未来发展留出空间的设计。
在实际项目中,我经常告诉团队:"从简单开始,但要以复杂为方向设计"。先实现一个可工作的Supervisor系统,理解业务需求和数据流,然后根据实际需要逐步引入Swarm的灵活性,最终可能走向混合甚至全新的架构。多智能体系统的美妙之处在于,它像真正的团队一样,可以随着需求的变化而成长和进化。
&spm=1001.2101.3001.5002&articleId=153707591&d=1&t=3&u=024e20b750bf4228a3a8ef1de725164b)
587

被折叠的 条评论
为什么被折叠?



