用HelloAgents写A2A多Agent系统,代码量直接少了一半
用HelloAgents写A2A多Agent系统代码量直接少了一半写在前面上一篇文章我们用原生A2A SDK写了两个Agent的协作代码量不小——要自己管理Agent Card、处理任务状态、维护会话、写HTTP服务……跑通是跑通了但写起来确实有点繁琐。这篇文章我们来看看HelloAgents框架是怎么封装A2A的。说实话我第一次用HelloAgents的A2A工具的时候最大的感受就是省事——很多原生SDK里需要自己写的样板代码框架都帮你封装好了你只需要关注业务逻辑。今天我就带大家看看HelloAgents的A2A工具都提供了什么以及怎么用它快速搭建多Agent系统。中间会对比原生SDK的写法让你直观感受到框架的价值。一、HelloAgents对A2A做了哪些封装在动手之前先看看HelloAgents在A2A方面提供了哪些工具。我整理了一下主要有这几块1. A2AAgent类这是最核心的类。你只需要继承它实现几个回调方法一个完整的A2A服务端Agent就写好了。不需要自己管HTTP服务、路由、Agent Card生成这些东西。2. A2AClient类封装了A2A客户端的所有操作——连接、发消息、创建任务、订阅状态。比原生客户端用起来更顺手错误处理也更完善。3. AgentRegistryAgent注册中心这是HelloAgents的一个亮点。它提供了一个内置的Agent注册中心Agent启动时自动注册其他Agent可以通过能力描述发现并连接它。原生A2A SDK里没有这个你得自己搞服务发现。4. MultiAgentOrchestrator多Agent编排器如果你需要协调多个Agent完成一个复杂任务这个编排器能帮你管理任务分解、分发、汇总。不用自己写调度逻辑。5. 内置的会话和状态管理HelloAgents自动帮你管理会话状态、任务状态、上下文传递。原生SDK里这些都得自己维护很容易出bug。这几块加起来基本上把多Agent系统里的脏活累活都包了。你只需要写每个Agent的业务逻辑剩下的交给框架。二、用HelloAgents写一个A2A服务端Agent我们先从最简单的开始——用HelloAgents写一个A2A服务端Agent。跟上一篇的计算器Agent做同样的事你可以对比一下代码量。# calculator_agent.pyfromhelloagentsimportA2AAgent,TaskResultclassCalculatorAgent(A2AAgent):name计算器助手description一个简单的计算器智能体支持加减乘除capabilities[calculation]asyncdefhandle_task(self,task):处理任务只需要关注业务逻辑try:afloat(task.input.get(a,0))bfloat(task.input.get(b,0))optask.input.get(op,)ifop:resultabelifop-:resulta-belifop*:resulta*belifop/:resulta/bifb!0elsefloat(inf)else:returnTaskResult.error(f不支持的运算符{op})returnTaskResult.success({result:result,expression:f{a}{op}{b}{result}})exceptExceptionase:returnTaskResult.error(str(e))# 启动Agent一行代码搞定if__name____main__:CalculatorAgent().run(host0.0.0.0,port8000)对比一下上一篇原生SDK的写法你会发现不需要手动定义Agent Card类属性自动生成不需要手动创建HTTP服务run()方法搞定不需要手动管理Task状态返回TaskResult就行不需要自己处理异常框架有默认错误处理代码量少了差不多一半而且更清晰——你一眼就能看出这个Agent是干什么的业务逻辑跟协议细节完全分离了。三、用HelloAgents写A2A客户端客户端的封装也很到位。我们来看看怎么用HelloAgents的A2AClient调用上面的计算器Agent# client.pyfromhelloagentsimportA2AClientimportasyncioasyncdefmain():# 创建客户端并连接clientawaitA2AClient.connect(http://localhost:8000)# 自动获取Agent Card打印对方信息print(f已连接{client.agent_card.name})print(f能力{client.agent_card.capabilities})# 创建任务一行代码resultawaitclient.create_task_and_wait(input{a:15,b:27,op:},timeout30)ifresult.success:print(f计算结果{result.output[expression]})else:print(f任务失败{result.error})awaitclient.close()if__name____main__:asyncio.run(main())注意这个create_task_and_wait方法——它把创建任务 → 轮询状态 → 获取结果这三步合成了一步。原生SDK里你得自己写循环轮询这里直接帮你封装好了。如果你不想等任务完成只想创建然后异步处理也可以用create_task# 创建任务不等待taskawaitclient.create_task(input{a:1,b:2})# 订阅状态变化asyncforeventinclient.subscribe_task(task.id):print(f状态{event.status})ifevent.statusin[completed,failed]:break发消息也很简单# 发送普通消息replyawaitclient.send_message(你好帮我算个东西)print(f回复{reply.content})四、多Agent协作的完整例子上面的例子都是单Agent调用我们来看看HelloAgents怎么处理多Agent协作。假设我们要做一个旅行规划系统有三个Agent旅行规划Agent接收用户需求分解任务协调其他Agent机票Agent查询和预订机票酒店Agent查询和预订酒店用HelloAgents的MultiAgentOrchestrator来实现# travel_system.pyfromhelloagentsimportA2AAgent,A2AClient,MultiAgentOrchestrator,TaskResult# 机票AgentclassFlightAgent(A2AAgent):name机票助手description查询和预订机票capabilities[flight_search,flight_booking]asyncdefhandle_task(self,task):iftask.typesearch:returnTaskResult.success({flights:[{flight:CA1501,time:08:30,price:580},{flight:MU5101,time:10:15,price:620}]})eliftask.typebook:returnTaskResult.success({order_id:FL12345,status:confirmed})returnTaskResult.error(未知任务类型)# 酒店AgentclassHotelAgent(A2AAgent):name酒店助手description查询和预订酒店capabilities[hotel_search,hotel_booking]asyncdefhandle_task(self,task):iftask.typesearch:returnTaskResult.success({hotels:[{name:如家酒店,price:299,rating:4.5},{name:汉庭酒店,price:259,rating:4.3}]})eliftask.typebook:returnTaskResult.success({order_id:HT67890,status:confirmed})returnTaskResult.error(未知任务类型)# 旅行规划Agent协调者classTravelPlannerAgent(A2AAgent):name旅行规划助手description帮助用户规划完整旅行方案capabilities[travel_planning]def__init__(self):super().__init__()# 在初始化时连接其他Agentself.flight_clientNoneself.hotel_clientNoneasyncdefon_start(self):Agent启动时的回调用来建立连接self.flight_clientawaitA2AClient.connect(http://localhost:8001)self.hotel_clientawaitA2AClient.connect(http://localhost:8002)asyncdefhandle_task(self,task):destinationtask.input.get(destination)daystask.input.get(days,1)# 并行调用机票和酒店Agentflight_taskself.flight_client.create_task_and_wait(input{type:search,destination:destination})hotel_taskself.hotel_client.create_task_and_wait(input{type:search,destination:destination,days:days})flight_result,hotel_resultawaitasyncio.gather(flight_task,hotel_task)# 汇总结果returnTaskResult.success({destination:destination,flights:flight_result.output[flights],hotels:hotel_result.output[hotels],summary:f为您找到{len(flight_result.output[flights])}个航班和{len(hotel_result.output[hotels])}家酒店})# 启动三个Agentif__name____main__:importasyncioasyncdefstart_all():awaitFlightAgent().start(port8001)awaitHotelAgent().start(port8002)awaitTravelPlannerAgent().start(port8000)asyncio.run(start_all())这个例子展示了HelloAgents的几个强大之处on_start回调Agent启动时自动执行可以用来建立连接、加载资源不用自己管生命周期。并行调用用asyncio.gather可以同时调用多个Agent框架层面完全支持异步。任务结果统一所有Agent的返回都是TaskResult处理起来很统一。启动简单每个Agent调用start()就能跑端口配置一下就行。五、Agent注册中心自动发现的魔力上面的例子里旅行规划Agent是硬编码了机票和酒店Agent的地址localhost:8001和localhost:8002。但在真实系统中Agent的地址可能会变数量也可能动态增减。HelloAgents提供了AgentRegistry来解决这个问题# 启动注册中心fromhelloagentsimportAgentRegistry registryAgentRegistry()awaitregistry.start(port9000)# Agent启动时自动注册classFlightAgent(A2AAgent):name机票助手registry_urlhttp://localhost:9000# 指定注册中心地址# ... 其他代码# 客户端通过注册中心发现AgentclientawaitA2AClient.discover(registry_urlhttp://localhost:9000,capabilityflight_search# 按能力查找)有了注册中心之后Agent启动时自动注册关闭时自动注销客户端不需要知道具体地址按能力查找就行支持多个同能力Agent的负载均衡Agent上下线对客户端透明这个功能在多Agent系统里太重要了。原生A2A SDK完全没有服务发现你得自己集成Consul、etcd之类的东西HelloAgents直接内置了。六、跟原生SDK的对比用了一段时间HelloAgents的A2A工具之后我做了一个跟原生SDK的对比维度原生A2A SDKHelloAgents A2A工具创建服务端Agent需要手动写HTTP服务、路由、Agent Card继承A2AAgent实现回调即可任务状态管理自己维护状态机框架自动管理返回TaskResult会话管理自己用session_id关联框架自动维护客户端调用创建任务→轮询→取结果三步create_task_and_wait一步到位服务发现无需自己集成内置AgentRegistry多Agent编排自己写调度逻辑内置MultiAgentOrchestrator错误处理自己try-catch统一异常处理TaskResult.error代码量相同功能约100行约40-50行学习曲线较陡需要理解协议细节平缓关注业务逻辑即可当然原生SDK也有它的优势——更灵活、更轻量、不依赖框架。如果你只需要一个非常简单的A2A通信原生SDK也够用。但如果要做稍微复杂一点的多Agent系统HelloAgents的封装能省很多事。七、我踩的几个坑用HelloAgents的A2A工具也不是完全一帆风顺说几个我遇到的问题坑1Agent的name不能重复。注册中心是按name来标识Agent的如果两个Agent叫同一个名字注册会冲突。我一开始图省事两个测试Agent都叫测试助手结果第二个注册不上。后来改成不同名字就好了。坑2capabilities要写准确。客户端按capability查找Agent的时候是精确匹配的。如果你注册的是flight_search客户端查flight是查不到的。建议统一命名规范比如用领域.动作的格式flight.search、flight.book。坑3长任务要设置合理的timeout。create_task_and_wait默认超时是30秒。如果你的任务处理时间比较长比如调用外部API、跑数据分析一定要手动设大一点的timeout否则会超时报错。坑4Agent之间的循环调用要小心。A调用BB又调用A这种循环调用如果没有终止条件会死循环。框架目前没有自动检测循环调用的机制需要自己在业务逻辑里注意。写在最后HelloAgents的A2A工具给我最大的感受是恰到好处的封装。它没有把A2A协议藏得太深——你依然能理解底层在发生什么但它把那些重复的、容易出错的样板代码都包了让你专注于业务逻辑。我觉得这就是好框架应该有的样子不是替你做所有决定而是把那些没技术含量但又必须做的事情做掉让你把精力花在真正有价值的地方。当然框架也不是银弹。特别复杂的场景、需要深度定制协议行为的场景可能还是得用原生SDK。但对于90%的多Agent应用场景HelloAgents的封装已经足够好了。下一篇文章我们会聊聊怎么在智能体中真正使用A2A工具——包括大模型怎么决定调用哪个Agent、怎么处理Agent返回的结果、多Agent协作中的错误恢复等。你们在用HelloAgents或者其他Agent框架的时候有没有觉得哪些封装特别好用或者哪些地方不够灵活欢迎在评论区聊聊。下一篇预告在智能体中使用A2A工具。我们会把A2A跟大模型真正结合起来看看Agent是怎么自主决定委托任务、跟其他Agent协商、处理协作结果的。

相关新闻

基于 SpringBoot+Vue 的数字化文创作品展览与电商交易服务平台的设计与实现

基于 SpringBoot+Vue 的数字化文创作品展览与电商交易服务平台的设计与实现

选题背景与意义 随着数字技术的迅猛发展和文化消费模式的深刻变革,传统文化与现代科技的融合已成为推动文化产业转型升级的重要路径。在这一背景下,数字化文创作品展览与电商交易服务平台应运而生,成为连接创作者、消费者与文化资源的关键桥梁…

2026/10/15 5:04:07 阅读更多 →
LeetCode 1148 文章浏览 I:SQL条件过滤、去重与排序的经典实战

LeetCode 1148 文章浏览 I:SQL条件过滤、去重与排序的经典实战

这道题我有一个很深的印象——不是因为解法复杂,恰恰相反,它是不少人在LeetCode上接触的第一道数据库题:表结构简单、逻辑直白、最后只输出去重后的ID列表。“1148. 文章浏览 I”看起来简单到有点像是在送分,但它其实把SQL查询里最…

2026/10/15 5:03:07 阅读更多 →
易语言乐玩插件多线程索引方案:告别串线崩溃,稳定并发找图

易语言乐玩插件多线程索引方案:告别串线崩溃,稳定并发找图

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 5:03:07 阅读更多 →

最新新闻

51单片机八路抢答器:防误触发+双定时器协同+硬件级锁定

51单片机八路抢答器:防误触发+双定时器协同+硬件级锁定

简介:本资源是一份面向电子类专业学生与单片机初学者的完整课程设计文档,聚焦基于AT89C51单片机实现八路抢答器的软硬件全流程方案,解决课堂实践、课程设计及小型竞赛场景中抢答控制、编号锁定、声光提示等核心功能实现问题。文档为纯Word格式…

2026/10/15 5:49:37 阅读更多 →
ViBe运动目标检测:Python实现与调参避坑指南

ViBe运动目标检测:Python实现与调参避坑指南

1. 为什么选择ViBe做运动目标检测做过视频监控、智能交通或者人机交互项目的朋友,大概率都绕不开一个基础问题:怎么把画面里“动的东西”从背景里抠出来。帧差法太粗糙,光流法计算量又大,高斯混合模型参数多、收敛慢,对…

2026/10/15 5:49:37 阅读更多 →
51单片机八路抢答器实战:中断消抖、状态机仲裁与数码管驱动

51单片机八路抢答器实战:中断消抖、状态机仲裁与数码管驱动

简介:本资源是一份面向电子类专业学生与单片机初学者的完整课程设计文档,聚焦基于AT89C51单片机实现八路抢答器的软硬件全流程方案。文档详述了主持人控制、8路独立按键响应、编号锁存与LED数码管实时显示、声光提示(蜂鸣器LED)、…

2026/10/15 5:49:37 阅读更多 →
智能体框架核心设计:会话管理、工具调用、MCP与记忆系统实战

智能体框架核心设计:会话管理、工具调用、MCP与记忆系统实战

近两年做智能体(Agent)项目的人越来越多,但大多数团队都卡在同一个地方:模型能聊天,但干不了实事。要让大模型真正“上手干活”,绕不开会话管理、工具调用、外部协议接入、记忆系统这四根柱子。我最近在做的…

2026/10/15 5:49:37 阅读更多 →
ELK日志分析平台实战:从部署到索引调优的完整指南

ELK日志分析平台实战:从部署到索引调优的完整指南

1. 为什么半夜总是你在看日志——ELK栈解决的真实痛点做后端开发和运维的朋友,大概率都经历过这种场面:凌晨两三点被电话叫醒,说线上服务报错,用户操作卡死。你睡眼惺忪地打开跳板机,先查进程在不在,再翻日…

2026/10/15 5:49:37 阅读更多 →
SMU02C监控单元实战排障与网管对接全指南

SMU02C监控单元实战排障与网管对接全指南

简介:本资源为华为SMU02C站点监控单元(V500R001C50版本)官方用户手册PDF文档,面向通信电源系统领域的销售工程师、技术支持工程师及现场维护人员,用于掌握该智能监控模块的安装部署、多方式管理(LCD本地操作…

2026/10/15 5:48:37 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →