client.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. """
  2. A2A Demo Client — 展示 A2A 协议核心价值
  3. 流程:
  4. 1. 发现两个 Agent 的能力(Agent Card)
  5. 2. 分别提交任务给不同的 Agent
  6. 3. 展示跨 Agent 协作:问答 Agent 回答 → 翻译 Agent 翻译
  7. """
  8. import asyncio
  9. import httpx
  10. from a2a.client import A2ACardResolver, ClientConfig, create_client
  11. from a2a.helpers import new_text_message, display_agent_card
  12. from a2a.types import Role, SendMessageRequest
  13. AGENTS = {
  14. "问答": "http://127.0.0.1:9999",
  15. "翻译": "http://127.0.0.1:9998",
  16. }
  17. def extract_text(task) -> str:
  18. """从 Task 的 artifacts 中提取回复文本"""
  19. texts = []
  20. if task.artifacts:
  21. for artifact in task.artifacts:
  22. for part in artifact.parts:
  23. t = part.text.strip() if part.text else ""
  24. if t:
  25. texts.append(t)
  26. return "\n".join(texts)
  27. async def main():
  28. async with httpx.AsyncClient() as http_client:
  29. # ═══════════════════════════════════════════════
  30. # Phase 1: 发现多个 Agent 的能力
  31. # ═══════════════════════════════════════════════
  32. print("=" * 70)
  33. print(" Phase 1: 🔍 发现 Agent 能力(Agent Card)")
  34. print(" A2A 协议让 Client 可以在运行期发现 Agent 能干什么")
  35. print("=" * 70)
  36. cards = {}
  37. for name, url in AGENTS.items():
  38. print(f"\n ▶ 发现 {name} Agent → {url}")
  39. resolver = A2ACardResolver(httpx_client=http_client, base_url=url)
  40. card = await resolver.get_agent_card()
  41. cards[name] = card
  42. # 只取关键信息展示,不打印全量
  43. skills_str = ", ".join(s.name for s in card.skills) if card.skills else "(无)"
  44. print(f" Agent: {card.name} | 技能: {skills_str}")
  45. # ═══════════════════════════════════════════════
  46. # Phase 2: 分别调用不同的 Agent
  47. # ═══════════════════════════════════════════════
  48. print("\n" + "=" * 70)
  49. print(" Phase 2: 🤝 通过相同协议调用不同 Agent")
  50. print(" 不管是问答还是翻译,Client 都走同一套 A2A 接口")
  51. print("=" * 70)
  52. for name, card in cards.items():
  53. print(f"\n ── {name} Agent ──")
  54. config = ClientConfig(streaming=False)
  55. client = await create_client(agent=card, client_config=config)
  56. # 给每个 Agent 一个适合它的任务
  57. if name == "问答":
  58. query = "Explain what A2A protocol is in one sentence"
  59. else:
  60. query = "请把下面这句话翻译成英文:人工智能正在改变世界"
  61. print(f" 输入: {query}")
  62. message = new_text_message(query, role=Role.ROLE_USER)
  63. request = SendMessageRequest(message=message)
  64. async for response in client.send_message(request):
  65. text = extract_text(response.task)
  66. if text:
  67. # 缩进展示,区分输入输出
  68. for line in text.split("\n"):
  69. print(f" 输出: {line}")
  70. await client.close()
  71. # ═══════════════════════════════════════════════
  72. # Phase 3: 跨 Agent 协作(这才是 A2A 的精髓)
  73. # ═══════════════════════════════════════════════
  74. print("\n" + "=" * 70)
  75. print(" Phase 3: 🔄 跨 Agent 协作管道")
  76. print(" 问答 Agent 的回答 → 翻译 Agent 翻译成英文")
  77. print(" 不同 Agent 通过标准协议接力,无需定制适配")
  78. print("=" * 70)
  79. # 3a. 先问问题
  80. question = "什么是 A2A 协议?用一句话说"
  81. print(f"\n Step 1: 用户提问 → 问答 Agent")
  82. print(f" 输入: {question}")
  83. qa_card = cards["问答"]
  84. qa_client = await create_client(agent=qa_card, client_config=ClientConfig(streaming=False))
  85. qa_msg = new_text_message(question, role=Role.ROLE_USER)
  86. async for resp in qa_client.send_message(SendMessageRequest(message=qa_msg)):
  87. qa_answer = extract_text(resp.task)
  88. await qa_client.close()
  89. print(f" 问答 Agent 回复: {qa_answer[:100]}...")
  90. # 3b. 把回答送去翻译
  91. print(f"\n Step 2: 问答结果 → 翻译 Agent")
  92. print(f" 输入: (上一步的回答,翻译成英文)")
  93. trans_card = cards["翻译"]
  94. trans_client = await create_client(agent=trans_card, client_config=ClientConfig(streaming=False))
  95. trans_msg = new_text_message(f"把下面这句话翻译成英文:{qa_answer}", role=Role.ROLE_USER)
  96. async for resp in trans_client.send_message(SendMessageRequest(message=trans_msg)):
  97. trans_result = extract_text(resp.task)
  98. await trans_client.close()
  99. print(f" 翻译 Agent 输出: {trans_result[:200]}...")
  100. # ═══════════════════════════════════════════════
  101. print("\n" + "=" * 70)
  102. print(" ✅ A2A Demo 完成")
  103. print(" 🔑 关键点:")
  104. print(" • 两个 Agent 能力完全不同(问答 vs 翻译)")
  105. print(" • Client 通过 Agent Card 动态发现它们的能力")
  106. print(" • Client 用同一套 A2A 协议与两者通信,零适配代码")
  107. print(" • 跨 Agent 管道自动流转,无需中间格式转换")
  108. print("=" * 70)
  109. if __name__ == "__main__":
  110. asyncio.run(main())