""" 基于官方 a2a-sdk 库的 A2A 协议实现 使用官方 a2a-sdk 库实现 Agent-to-Agent Protocol 功能。 官方仓库: https://github.com/a2aproject/a2a-python 安装: pip install a2a-sdk """ from typing import Dict, Any, List, Optional import asyncio try: from a2a.client import A2AClient from a2a.types import Message A2A_AVAILABLE = True except ImportError: A2A_AVAILABLE = False A2AClient = None Message = None class A2AServer: """A2A 服务器(使用 Flask 提供 HTTP API)""" def __init__( self, name: str, description: str, version: str = "1.0.0", capabilities: Optional[Dict[str, Any]] = None ): """ 初始化 A2A 服务器 Args: name: Agent 名称 description: Agent 描述 version: Agent 版本 capabilities: Agent 能力描述 """ self.name = name self.description = description self.version = version self.capabilities = capabilities or {} self.skills = {} def add_skill(self, skill_name: str, func): """添加技能到服务器""" self.skills[skill_name] = func return func def skill(self, skill_name: str): """装饰器方式添加技能""" def decorator(func): self.add_skill(skill_name, func) return func return decorator def run(self, host: str = "0.0.0.0", port: int = 5000): """运行服务器(使用 Flask 提供 HTTP API)""" try: from flask import Flask, request, jsonify except ImportError: raise ImportError( "A2A server requires Flask. Install it with: pip install flask" ) app = Flask(self.name) # 禁用 Flask 的日志输出(可选) import logging log = logging.getLogger('werkzeug') log.setLevel(logging.ERROR) @app.route('/info', methods=['GET']) def get_info(): """获取 Agent 信息""" return jsonify(self.get_info()) @app.route('/skills', methods=['GET']) def list_skills(): """列出所有技能""" return jsonify({ "skills": list(self.skills.keys()), "count": len(self.skills) }) @app.route('/execute/', methods=['POST']) def execute_skill(skill_name): """执行指定技能""" if skill_name not in self.skills: return jsonify({ "error": f"Skill '{skill_name}' not found", "available_skills": list(self.skills.keys()) }), 404 try: data = request.get_json() or {} text = data.get('text', data.get('query', '')) # 调用技能函数 result = self.skills[skill_name](text) return jsonify({ "skill": skill_name, "result": result, "status": "success" }) except Exception as e: return jsonify({ "error": str(e), "skill": skill_name, "status": "error" }), 500 @app.route('/ask', methods=['POST']) def ask(): """通用问答接口(自动选择技能)""" try: data = request.get_json() or {} question = data.get('question', data.get('text', '')) # 简单策略:尝试所有技能,返回第一个非错误结果 for skill_name, skill_func in self.skills.items(): try: result = skill_func(question) if result and not result.startswith("Error"): return jsonify({ "answer": result, "skill_used": skill_name, "status": "success" }) except: continue return jsonify({ "answer": "No suitable skill found for this question", "status": "no_match" }) except Exception as e: return jsonify({ "error": str(e), "status": "error" }), 500 @app.route('/health', methods=['GET']) def health(): """健康检查""" return jsonify({"status": "healthy", "agent": self.name}) # 启动服务器 print(f"🚀 A2A 服务器 '{self.name}' 启动在 {host}:{port}") print(f"📋 描述: {self.description}") print(f"🛠️ 可用技能: {list(self.skills.keys())}") print(f"📡 API 端点:") print(f" - GET {host}:{port}/info - 获取 Agent 信息") print(f" - GET {host}:{port}/skills - 列出技能") print(f" - POST {host}:{port}/execute/ - 执行技能") print(f" - POST {host}:{port}/ask - 通用问答") print(f" - GET {host}:{port}/health - 健康检查") print() app.run(host=host, port=port, debug=False) def get_info(self) -> Dict[str, Any]: """获取服务器信息""" return { "name": self.name, "description": self.description, "version": self.version, "capabilities": self.capabilities, "protocol": "A2A", "skills": list(self.skills.keys()) } class A2AClient: """A2A 客户端(通过 HTTP 与 A2AServer 通信)""" def __init__(self, server_url: str): """ 初始化 A2A 客户端 Args: server_url: 服务器 URL(例如:http://localhost:5000) """ self.server_url = server_url.rstrip('/') def ask(self, question: str) -> str: """ 向 Agent 提问(通用接口) Args: question: 问题文本 Returns: Agent 的回答 """ try: import requests response = requests.post( f"{self.server_url}/ask", json={"question": question}, timeout=30 ) response.raise_for_status() return response.json().get("answer", "No response") except Exception as e: return f"Error communicating with agent: {str(e)}" def execute_skill(self, skill_name: str, text: str = "") -> Dict[str, Any]: """ 执行指定技能 Args: skill_name: 技能名称 text: 输入文本 Returns: 执行结果 """ try: import requests response = requests.post( f"{self.server_url}/execute/{skill_name}", json={"text": text}, timeout=30 ) response.raise_for_status() return response.json() except Exception as e: return {"error": f"Failed to execute skill: {str(e)}", "status": "error"} def get_info(self) -> Dict[str, Any]: """获取 Agent 信息""" try: import requests response = requests.get(f"{self.server_url}/info", timeout=10) response.raise_for_status() return response.json() except Exception as e: return {"error": f"Failed to get agent info: {str(e)}"} def list_skills(self) -> List[str]: """列出 Agent 的技能""" try: import requests response = requests.get(f"{self.server_url}/skills", timeout=10) response.raise_for_status() return response.json().get("skills", []) except Exception as e: return [] class AgentNetwork: """基于官方 a2a-sdk 库的 Agent 网络(概念性实现)""" def __init__(self, name: str = "Agent Network"): """ 初始化 Agent 网络 Args: name: 网络名称 """ self.name = name self.agents = {} # agent_name -> agent_url def add_agent(self, agent_name: str, agent_url: str): """ 添加 Agent 到网络 Args: agent_name: Agent 名称 agent_url: Agent URL """ self.agents[agent_name] = agent_url def get_agent(self, agent_name: str) -> A2AClient: """ 获取网络中的 Agent Args: agent_name: Agent 名称 Returns: A2A 客户端实例 """ if agent_name not in self.agents: raise ValueError(f"Agent '{agent_name}' not found in network") return A2AClient(self.agents[agent_name]) def list_agents(self) -> List[Dict[str, Any]]: """列出所有 Agent""" return [ {"name": name, "url": url} for name, url in self.agents.items() ] def discover_agents(self, urls: List[str]) -> int: """ 从 URL 列表中发现 Agent Args: urls: URL 列表 Returns: 发现的 Agent 数量 """ discovered = 0 for url in urls: try: client = A2AClient(url) info = client.get_info() if "name" in info and "error" not in info: self.add_agent(info["name"], url) discovered += 1 except Exception: continue return discovered class AgentRegistry: """基于官方 a2a-sdk 库的 Agent 注册中心(概念性实现)""" def __init__(self, name: str = "Agent Registry", description: str = "Central agent registry"): """ 初始化 Agent 注册中心 Args: name: 注册中心名称 description: 注册中心描述 """ self.name = name self.description = description self.registered_agents = {} def register_agent(self, agent_name: str, agent_url: str, metadata: Optional[Dict[str, Any]] = None): """注册 Agent""" self.registered_agents[agent_name] = { "url": agent_url, "metadata": metadata or {}, "registered_at": __import__("datetime").datetime.now().isoformat() } def unregister_agent(self, agent_name: str): """注销 Agent""" if agent_name in self.registered_agents: del self.registered_agents[agent_name] def list_agents(self) -> List[Dict[str, Any]]: """列出所有注册的 Agent""" return [ {"name": name, **info} for name, info in self.registered_agents.items() ] def find_agent(self, agent_name: str) -> Optional[Dict[str, Any]]: """查找特定 Agent""" return self.registered_agents.get(agent_name) def get_info(self) -> Dict[str, Any]: """获取注册中心信息""" return { "name": self.name, "description": self.description, "protocol": "A2A", "type": "registry", "registered_agents": len(self.registered_agents) } # 示例:创建一个简单的 A2A Agent def create_example_agent() -> A2AServer: """创建一个示例 A2A Agent""" if not A2A_AVAILABLE: raise ImportError( "Cannot create example agent: a2a-sdk library not available. " "Install it with: pip install a2a-sdk" ) server = A2AServer( name="Example A2A Agent", description="A simple example A2A agent", version="1.0.0", capabilities={"chat": True, "calculation": True} ) # 添加计算技能 def calculator_skill(text: str) -> str: """计算数学表达式""" # 从文本中提取表达式 import re match = re.search(r'calculate\s+(.+)', text, re.IGNORECASE) if match: expression = match.group(1).strip() try: # 安全的表达式求值(仅支持基本运算) allowed_chars = set("0123456789+-*/() .") if not all(c in allowed_chars for c in expression): return "Error: Invalid characters in expression" result = eval(expression) return f"The result is: {result}" except Exception as e: return f"Calculation error: {str(e)}" return "Please provide an expression to calculate" server.add_skill("calculate", calculator_skill) # 添加问候技能 def greeting_skill(text: str) -> str: """生成问候语""" import re match = re.search(r'hello|hi|greet', text, re.IGNORECASE) if match: return "Hello! I'm an A2A agent. How can I help you today?" return "Hi there!" server.add_skill("greet", greeting_skill) return server if __name__ == "__main__": try: # 创建并运行示例 Agent agent = create_example_agent() print(f"🚀 Starting {agent.name}...") print(f"📝 {agent.description}") print(f"🔌 Protocol: A2A") print(f"📡 Version: {agent.version}") print(f"🛠️ Skills: {list(agent.skills.keys())}") print() agent.run(host="0.0.0.0", port=5000) except ImportError as e: print(f"❌ {e}") print("💡 Install the A2A SDK: pip install a2a-sdk") print("📖 Official repository: https://github.com/a2aproject/a2a-python")