# 步骤1:导入所需的库和模块
import asyncio # 导入 asyncio 库,用于实现异步和并发操作
from python_a2a import AgentNetwork, AIAgentRouter, A2AClient, Task, Message, MessageRole, TextContent # 从 python_a2a 库导入 Agent 协作所需的核心类和对象
from langchain_openai import ChatOpenAI # 导入 LangChain 的 ChatOpenAI,用于与大语言模型交互
from langchain_core.prompts import PromptTemplate # 导入 LangChain 的 PromptTemplate,用于定义提示模板
from langchain_core.output_parsers import StrOutputParser # 导入 LangChain 的 StrOutputParser,用于解析 LLM 输出为字符串
import json # 导入 json 库,用于处理 JSON 格式的数据
import uuid # 导入 uuid 库,用于生成唯一的任务 ID
from time import sleep # 导入 sleep 函数,用于模拟处理延迟
from agent_learn.config import Config # 导入自定义的 Config 类,用于加载配置信息
import re # 导入 re 模块,用于正则表达式处理
# 步骤2:初始化配置和LLM
# 2.1 从配置文件加载配置
conf = Config()
# 2.2 配置 LLM 用于分解查询
decompose_llm = ChatOpenAI(
model=conf.model_name,
api_key=conf.api_key,
base_url=conf.base_url,
temperature=0.1,
streaming=True #启用流式处理
)
# 2.3 定义分解查询的提示模板
decompose_prompt = PromptTemplate.from_template("""
将以下用户查询分解为独立的子查询,每个子查询对应一个单一意图。
返回 JSON 格式的列表:{{"sub_queries": ["子查询1", "子查询2", ...]}}
示例:
查询: "预订票,查天气"
输出: {{"sub_queries": ["预订票", "查天气"]}}
查询: {query}
""")
# 2.4 构建分解链
decompose_chain = decompose_prompt | decompose_llm | StrOutputParser()
# 步骤3:主函数,执行多意图协作流程
async def main():
# 1)创建 AgentNetwork
# 实例化对象
network = AgentNetwork(name='TravelAgentNetwork')
# 添加 agent name可以自己定义
network.add(name='WeatherAgent', agent_or_url='http://127.0.0.1:5008')
network.add(name='TicketAgent', agent_or_url='http://127.0.0.1:5009')
# 打印agent server信息
for agent_info in network.list_agents():
print(json.dumps(agent_info, indent=4, ensure_ascii=False))
# 2)创建AIAgentRouter
# 创建路由器
router = AIAgentRouter(llm_client=A2AClient("http://127.0.0.1:5555"),
agent_network=network)
# 3)测试查询
queries = [
"帮我查下北京的天气,并预订一张从北京到上海的火车票", # 复合意图
]
for query in queries:
print(f"[主控日志] 用户查询: '{query}'")
try:
# 3.1)使用 LLM 分解查询为子查询
decompose_result = decompose_chain.invoke({"query": query})
print(f"[主控日志] 分解结果: {decompose_result}")
# 使用正则表达式清理LLM输出中的JSON标记
decompose_response = re.sub(r'^```json\n|\n```$', '', decompose_result.strip())
decompose_data = json.loads(decompose_response)
# 从JSON中获取子查询列表,如果失败则使用原始查询
sub_queries = decompose_data.get("sub_queries", [query])
except Exception as e:
print(f"[主控日志] 分解失败: {e}")
sub_queries = [query] # 发生错误时,将原始查询作为唯一的子查询
print(f"[主控日志] 子查询列表: {sub_queries}")
# 3.2)处理每一个子查询,获取对应的处理任务,后续再一起执行!
tasks = [] # 创建一个空列表,用于存放所有要并行执行的异步任务
agent_names = [] # 创建一个空列表,用于记录每个任务对应的Agent名称
confidences = [] # 创建一个空列表,用于记录路由的置信度
for sub_query in sub_queries: # 遍历所有分解出的子查询
print(f"[主控日志] 子查询: '{sub_query}'")
# 使用路由器选择agent
agent_name, confidence = router.route_query(sub_query)
print(f"[主控日志] 匹配的agent: '{agent_name}', 匹配度: {confidence}")
if agent_name:
# 基于 agent_name 获取对应的 agent server
agent_client = network.get_agent(agent_name)
if agent_client:
# Message用来存储具体的任务内容
message = Message(content=TextContent(text=sub_query), role=MessageRole.USER)
# Task中存储和封装Message
agent_task = Task(message=message.to_dict(), id="task-" + str(uuid.uuid4()))
# 记录所有task:因为没有使用 await,那么这个异步函数不会被执行,会返回一个未被处理的协程对象,但里面的代码不会运行
tasks.append(agent_client.send_task_async(agent_task))
agent_names.append(agent_name)
confidences.append(confidence)
confidence = sum(confidences) / len(confidences) if confidences else 0.1
print("===========所有子查询置信度的平均值==============")
print(confidence)
# 3.3)并行执行任务!
if tasks:
# 使用 asyncio.gather 并行执行所有任务,并收集结果
results = await asyncio.gather(*tasks, return_exceptions=True)
print("[主控日志]检查query拆解任务之后的所有 任务结果:")
print(results)
# 3.4)处理和打印任务结果
for i, result in enumerate(results):
if isinstance(result, Exception): # 检查结果是否是异常(任务执行失败)
print(f"[主控日志] {agent_names[i]} 处理错误: {str(result)}")
else: # 任务成功完成
print(f"[主控日志] {agent_names[i]} 收到完整响应:")
print(json.dumps(result.to_dict(), indent=4, ensure_ascii=False)) # 格式化打印完整的A2A任务响应
# 解析 artifacts 中的 parts
print(f"\n[主控日志] {agent_names[i]} 解析 artifacts 中的 parts:")
for artifact in result.artifacts:
if "parts" in artifact: # 检查是否存在 parts 字段
for part in artifact["parts"]:
part_type = part.get("type") # 获取 part 的类型
if part_type == "text":
print(f"Text 结果: {part.get('text')}")
elif part_type == "error":
print(f"Error 消息: {part.get('message')}")
elif part_type == "function_response": # 如果类型是函数响应
print(
f"Function Response: name={part.get('name')}, response={part.get('response')}")
else: # 其他未知类型
print(f"未知类型: {part}")
else: # 如果任务列表为空
print("[主控日志] 未找到合适代理")
print('*'*80)
# break
if __name__ == '__main__':
asyncio.run(main())