05|协议实战(下):通过 A2A,你的智能体不仅能对话还可以协作!

你好,我是黄佳。

上节课我们完成了快速搭建MCP RAG服务,这节课我们继续进行协议实战,感受一下A2A的协议用法。

下面我将逐步给你展示一个通过A2A协议搭建的智能体平台,让你的智能体不仅能够相互对话,还能够协作协力来完成一个任务。

图片

在这个基于 A2A 协议的智能体平台中,用户在浏览器端发出指令后,前端会将该请求传给 Host Agent,由它负责解析用户意图、拆解具体子任务,并且并行触发多个 Remote Agent;每个 Remote Agent 通过 A2A Client 将子任务封装为标准的 JSON-RPC 请求,发送给远端对应的 A2A Server,再由后者调用各自擅长的智能体模块(如 LangGraph Agent负责外汇兑换、Google ADK Agent负责报销收据、Crew AI Agent负责根据文字内容来生成图片等)执行并返回结果;最后,Host Agent 汇总并格式化各路反馈,一并呈现给用户,实现多智能体的分工协作与能力互补。

项目准备工作

我们先来搞定一些必要的准备工作。

安装Python3.12版本

A2A协议非常新,所以它对环境的要求也是很高的。因此,要确保我们已经安装了Python 3.12版本。如果你的系统没有这个版本,那就要更新一下。

下面是在Ubuntu系统中更新Python的代码示例:

sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
sudo apt install -y python3.12 python3.12-venv python3.12-dev

在Ubuntu系统中,检查 Python 3.12 是否安装成功:

python3.12 --version
Python 3.12.10

其他各种系统的版本安装我就不赘述了。

克隆项目代码库

安装好Python包之后,就可以来到这里下载我为你准备的这套A2A Demo代码,并用下面的命令把它Clone到你的本机。

git clone https://github.com/huangjia2019/a2a-in-action.git 

这一套代码,是我基于Google官方A2A仓库复制出来并简单改造过的教学版本,我会基于这套代码为你详细讲解A2A协议的实现细节。

图片

项目克隆到本机之后呢,你会看下面的目录结构。

图片

其中agents目录中,就包含后续课程中要讲解的一系列A2A Agents示例。而Demo目录则是我们下面要演示的协议实战示例。

图片

我们打开demo目录,再打开其中的ui目录,你会注意到其中有一个pyproject.toml文件。这是一个供UV使用的 Python 项目的环境配置文件,主要用于定义项目的元数据、依赖、构建方式等(其实,每一个Agent目录中,以及项目的根目录中,都会有这样一个配置文件,因为每一个Agent 服务所需要的环境各不相同)。

Google API key

这个项目以及后续要学习的许多Agents都需要一个Google API key,我们可以通过这个链接创建一个,并通过.env来配置这个密钥,提供给程序使用。

图片

可以把这个.env文件放置在A2A-IN-ACTION项目根目录下。

好,下面就可以启动这个A2A项目并展示Agents之间的通信能力了。

启动A2A Demo项目

先通过cd demo/ui命令进入A2A Demo项目的目录。

使用下面的命令来启动这个Demo。

uv run main.py

在第一次启动的同时,uv命令会安装一系列所需的包。

图片

同时,应用程序将成功在12000端口启动。

图片

你将看到如下所示的和Agent交互对话的窗口。

图片

而你的A2A Demo应用也能够接收到你的对话,服务顺畅地跑起来了。

图片

选择最下面的Setting按钮,我们先设置一下Google API Key(相当于又手工设置了环境变量GOOGLE_API_KEY),同时选择接收图文输出。

图片

此时,你可以顺畅地和Host进行对话,在这个Chat窗口后面,系统内部其实是有一个名叫“Simple Agent”的简单智能体(Host Agent或叫做Local Agent)负责和我们对话。

图片

当然,这个简单智能体的能力有限。比如当我问他“如何把20欧元转换成美元”,他说他没有能力查找汇率。当我让它列出智能体的列表,它说目前这个应用中找不到任何外部智能体。其中,目前应用程序中只有它这一个Local Agent,看起来它的能力也仅限于陪聊。

就像MCP Host也要进行一些配置,才能够连接到外部的MCP服务,看来我们也需要进行一些配置,才能够调用其他Agent的能力。

下面,我们就选择Agents选项卡,来配置一系列的Remote Agents,也就是外部Agents。我们先来添加一个Currency Agent。

首先,进入agents/langgraph目录,然后通过 uv run . 命令把这个Agent服务跑起来。—— 这是一个专门负责汇率计算的Agent,能够实时的访问各种国家的货币汇率信息。

图片
好,此时远程Agent服务中,我们可以在应用中添加这个Currency Agent了!

图片

选择Agent的名称和端口,添加好的Agent如下图所示。

图片

重新开始对话,你就能发现,这时候Local Agent遇到货币兑换这样的难题就不会再捉襟见肘了。

图片

几轮对话过后,选择Task List选项卡,可以看到一系列的对话列表。

图片

此时,在服务器的后台,我们也可以看到Local Host和远程服务的交互过程。

图片

好,那么现在我们看到了一个Local Agent(也叫Host Agent,即本地Agent),通过A2A协议调用了外部Agent的能力。底层是如何实现的?让我们来一起剖析一下关键设计。

A2A Demo的设计实现

从整体架构上看,一个A2A 系统由以下主要组件构成:

  • Agent Card: 代理的身份标识和能力声明。

  • Skill: 代理可执行的具体能力。

  • Task Manager: 处理任务流和状态管理。

  • Server: 提供HTTP接口让其他代理/客户端访问。

而在这些关键组件实现的基础之上,还需要为Demo应用创建UI,并注册服务,还要通过一系列的通信机制让外部Agent和Host Agent(本地Agent)能够相互对话,进行能力的发现。

UI 层入口与服务注册

首先我们简单介绍UI层的实现。在文件夹demo/ui/pages.py中,就这个应用的前端页面。

图片

文件demo/ui/main.py中通过 FastAPI 启动后端服务,并用 Mesop 框架组织前端页面。

  from service.server.server import ConversationServer
  ...
  app = FastAPI()
  router = APIRouter()
  agent_server = ConversationServer(router)
  app.include_router(router)

这段代码将所有与智能体对话相关的API路由注册到 FastAPI 应用,核心逻辑都在 ConversationServer 里。

Host Agent 服务实现

前端服务需要首先和本地Agent建立连接,才能实现和用户的交互对话。文件demo/ui/service/server/server.py中的ConversationServer 类是 UI 与 Host Agent 之间的桥梁,负责路由注册和请求分发。初始化时会根据环境变量选择 ADKHostManager(真实多智能体调度)或 InMemoryFakeAgentManager(假数据)。

此处的关键方法是:

  • async def _send_message(self, request: Request),它接收前端消息,调用 self.manager.process_message(message) 进行处理(异步线程),并返回消息ID。

  • async def _register_agent(self, request: Request),支持动态注册远程Agent,调用 self.manager.register_agent(url)。

  • async def _list_agents(self),返回当前已注册的所有Agent信息。

这些API接口就是A2A协议在本地Host侧的“落地实现”,所有对话、任务、Agent管理都通过这里转发。

Host Agent 调度与A2A协议实现

下面我们来分析本地Agent是如何实现A2A协议的。

在文件demo/ui/service/server/adk_host_manager.py中,ADKHostManager 继承自 ApplicationManager,是真正的“智能体大脑”。

此处的关键属性和方法如下:

  • self._host_agent = HostAgent([], self.task_callback),这里的 HostAgent 是多智能体调度的核心,负责多智能体的注册、能力发现、任务分发、回调等,是 Host 侧的“大脑”。这个类的定义位于hosts/multiagent/host_agent.py 文件。

  • async def process_message(self, message: Message),处理用户消息,维护会话、消息、事件等,并通过 self._host_runner.run_async(…) 触发智能体推理和任务流转。

  • def register_agent(self, url),支持通过URL动态注册远程Agent,Agent信息会被加入 _agents 列表,供Host调度。

  • @property def agents(self),返回所有已注册的AgentCard(能力描述卡片),用于能力发现和展示。

这里的 process_message 方法会将用户输入转为标准的A2A消息格式,交由 HostAgent 进行多智能体协作处理,最终结果再通过事件流返回。

HostAgent 通过 remote_agent_connection.py 维护与每个远程 Agent 的连接和能力卡片(AgentCard)—— 这也是A2A协议的核心交互机制

Remote Agents和Agent Card

在agent目录中,有一系列可以配置到Demo应用中的外部(Remote)Agents,每个子目录就是一个外部 Agent 的实现。在刚才的Demo环节,我们以通过LangGraph 实现的货币转换Agent为例,启动并手动注册了它。

图片

具体来说:

  • agents/langgraph/agent.py中的CurrencyAgent,用 LangGraph 框架和 Google Gemini API 实现了货币兑换的智能体逻辑,支持流式和同步调用。

  • agents/langgraph/main.py中通过 A2AServer(A2A协议服务端实现)将 CurrencyAgent 以 HTTP 服务形式暴露出来,并注册了自己的 AgentCard,即能力卡片。

Agent Card是A2A协议的关键内核概念之一,它负责定义代理的元数据(名称、描述、URL、版本等),声明支持的输入/输出模态(如文本、图像等)同时列出代理提供的技能清单(skill),其目的是让你的代理能够被发现,并让其他系统知道如何与它交互。这是实现“代理之间互相通信”(Agent-to-Agent)的基础。

agent_card = AgentCard(
    name='Currency Agent',
    description='Helps with exchange rates for currencies',
    url=f'http://{host}:{port}/',
    version='1.0.0',
    defaultInputModes=CurrencyAgent.SUPPORTED_CONTENT_TYPES,
    defaultOutputModes=CurrencyAgent.SUPPORTED_CONTENT_TYPES,
    capabilities=capabilities,
    skills=[skill],
)

你可以把它想象成你的 AI 代理(Agent)的 “名片” 或 “说明书”。它是一个标准化的信息包(通常是 JSON 格式),用来告诉其他代理或系统这个代理叫什么名字(name)、它是干什么的(description)、在哪里可以找到它并与之通信(url,包含主机和端口)、它支持哪些基本能力(capabilities)、它具体能完成哪些任务或技能(skills,比如货币兑换服务),以及版本号、默认沟通方式等其他元数据。

A2AServer则是A2A的协议服务端实现,其中的Task Manager负责任务生命周期管理,状态追踪和更新(WORKING、COMPLETED、ERROR等),处理同步/异步请求(on_send_task 和 on_send_task_subscribe),生成适当的响应格式以及错误处理和恢复。

server = A2AServer(
      agent_card=agent_card,
      task_manager=AgentTaskManager(
          agent=CurrencyAgent(),
          notification_sender_auth=notification_sender_auth,
      ),
      host=host,
      port=port,
  )

这样,langgraph 目录下的 Agent 就成为了一个标准的 A2A 协议远程 Agent,具备独立服务能力和能力自描述。

A2A Client 端实现

最后我们来看一下A2A Client 端的实现逻辑。文件demo/ui/service/client/client.py中的ConversationClient 类封装了与远程Agent的HTTP通信,所有请求都以 JSON-RPC 格式发送。

此处的关键方法如下:

  • async def send_message(self, payload: SendMessageRequest),通过HTTP POST将消息发送到远程Agent的 /message/send 接口。

  • async def register_agent(self, payload: RegisterAgentRequest),远程注册Agent。

其它如 list_agents、list_tasks、get_events 等,均为A2A协议的标准接口,负责A2A协议“客户端”的标准实现,并与远端Agent进行协议对接。

总结一下

好,总结一下。Google A2A 框架提供了一个灵活而标准化的通信机制,让各个 AI 代理能够基于面向技能的设计,通过清晰的身份标识和能力声明,以统一的协议实现同步或异步的交互,并在此过程中依赖完善的状态管理与错误处理,以模块化、可扩展的架构共同构建更复杂的应用场景。

在具体实现上,每个 Agent 启动时会生成自己的 AgentCard,内含名称、描述、服务 URL 以及所支持的能力和技能等关键信息;启动后,Agent 通过 A2A Server 将自己的 AgentCard 向注册中心登记,而 Host 端则通过注册/发现机制(如调用 demo/ui/utils/agent_card.py 中的 get_agent_card 接口)远程拉取所有 AgentCard,实现能力路由与展示,从而完成代理之间的能力发现与互操作。

思考题

  1. 请你研究一下Agents目录中的外部Agents,每一个具有什么能力,能完成什么任务。

  2. 请你在这个应用程序中,添加更多的Agent,让多个Agent协作完成更为复杂的任务,比如发票的报销工作。

怎么样,这个应用像不像一个简版的Manus,那么在后续A2A每一课的讲解中我们将更深入的剖析具体agents的设计以及agents之间是怎样交互和协调工作的,敬请期待。

精选留言

  • 黄佳

    2025-06-24 13:12:46

    我觉得这个A2A示例里面的多智能体协作框架的设计还是挺有启发的。简单说就是Client端需要有一个调度Agent,然后它去负责调用别的Agent能力。
    作者回复

    这种调度 Agent(Orchestrator)+ 专职能力 Agent的模式,是多 Agent 系统里最常见也最清晰的设计。
    Orchestrator = 调度中枢,负责规划、派发、重试、聚合;
    Worker Agent = 专职能力,各司其职、轻量可靠;
    A2A 协议为二者之间提供双向流、订阅/通知、并发控制等机制,确保整个系统既灵活又高可用。

    2025-07-22 10:56:54

  • 悟空聊架构

    2025-06-19 17:54:32

    整理了下课后习题解答+示例代码运行报错问题汇总+调试技巧,详见这里:https://github.com/huangjia2019/a2a-in-action/issues/1
    第1题简答:从YouTube视频中提取隐藏字幕、按需生成惊艳的高质量图像、根据报销金额和用途,协助用户完成报销流程、解析文件、从文本中提取结构化的联系信息、行程规划。
    第2题因报销 Agent 一直报错,暂未找到原因。还需要再研究下。
    作者回复

    悟空,你太强大了。

    强推每一位同学认真看一下:https://github.com/huangjia2019/a2a-in-action/issues/1

    悟空呀,果然你才是真正的师傅。写的这么清晰,准确,面面俱到。

    大家看完了悟空的记录,允许我向大家推荐悟空的公众号 “悟空聊架构” —— 一个Java程序员进阶资深工程师的全部内容都在那里了。

    P.S. 我和悟空之前并不认识,我也并没有关注过悟空的公众号,只是像悟空所说,因为他搜索到这个课程而结缘,然后又因为悟空开了一个PR,发现了他的Github和公众号,就是这样。感恩奇妙的缘分。也向Java爱好者推荐悟空对Java各个技术栈妙趣横生的故事化剖析。像读小说一样学架构。

    2025-06-19 23:36:13

  • Jxin

    2025-07-10 20:30:05

    1. 核心对比:A to A 与传统 gRPC Server to Server

    ◦ 相似点:主体及能力定义高度相似,A to A 中的“agent”类似传统架构中的“server”,agent 的“skill”对应 server 的接口/能力项;服务注册与发现机制相近。

    ◦ 差异点:最大差异在于调度方式,A to A 由“agent client”自动决策调用哪个 agent 的哪个技能;传统开发中通过在 server 里写死代码实现调度。

    2. A to A 模式的优势

    ◦ 减少程序员编写“管道逻辑”的成本:以往整合多个能力(如地图查询、酒店/机票预订等)需跨团队协调并,手动编写大量串联逻辑,最后联调上线。A to A 中只需将这些能力注册到 host agent,由其自动决策调度以满足上层需求。

    ◦ 对企业级大型系统映射更友好:相比 MCP 模式,更适合现有大型系统切换,一个 server 可对应一个 agent,通过描述 agent 的“card”(能力载体)实现映射,概念更清晰,减少繁杂感。

    3. A to A 模式的潜在问题

    ◦ 当注册的 agent 量级过大、对应的“card”(能力载体)繁多时,agent 的决策准确性和场景适应性存疑。

    ◦ 每个 agent 的“card”中技能点的描述需要较多转化工作。

    4. 针对问题的解决方案设想

    ◦ 让 agent 引入“快照”机制:对已识别的服务决策规则(如两个服务的交互逻辑)进行快照并写死到代码中;新增agent时,经一段时间观察,识别决策规则,快照固化到代码。

    ◦ 效果:快照范围内的决策通过固定代码路由,避免 agent 和客户端的决策复杂度随服务数量增加而持续上升。

    ◦ autoagent :通过工具解析现有 server 的接口文档、业务逻辑,自动生成 agent 的能力描述,降低 A to A 协议落地门槛,实现现有 server 向 A to A 架构的快速转换。
    作者回复

    我觉得总结和分析的很棒,尤其是快照,autoagent和分域分层的几个设想。大家觉得呢??

    2025-07-22 11:23:42

  • klee

    2025-08-03 20:26:01

    赶回来留个言,强烈建议大家使用cursor (或者其它AI IDE)进行编程,这里面google api key 确实是个大门槛,就算申请下来key, google 的服务也有可能对大陆不可用。所以建议大家clone项目到本地后,可以让cursor帮你修改一下,让它支持本地部署的ollama模型。本地部署 ollama 很简单,可以参考这个 https://www.cnblogs.com/xuxueli/p/18696287。如果运行项目遇到什么问题,也可以让cursor来帮你debug,事半功倍。
    作者回复

    好的,这位同学所言极是。Cursor,Agument Code, Claude Code,Gemini CLI都可以用起来。同时,字节的Trae,阿里的Qwen-Code, 腾讯的CodeBuddy也都试试,毕竟国货用着方便。对吧!

    2025-08-06 15:47:31

  • Geek_bc7572

    2025-07-30 11:11:45

    没有人和我一样卡在google api key这一步吗,在给的链接页面上捣鼓了半天,没看懂怎么申请 api key的,点到了clude的页面,还要填什么信用卡的
    作者回复

    https://github.com/huangjia2019/a2a-in-action/issues - 看下悟空的排坑指南?

    2025-07-30 18:32:28

  • 拉可里啦

    2025-07-13 17:46:52

    TypeError: 'NoneType' object is not iterable
    INFO: 127.0.0.1:45507 - "POST /__ui__ HTTP/1.1" 200 OK
    Failed to list conversations: HTTP Error 502: Server error '502 Bad Gateway' for url 'http://localhost:12000/conversation/list'
    For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502
    Failed to list tasks HTTP Error 502: Server error '502 Bad Gateway' for url 'http://localhost:12000/task/list'
    For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502
    Failed to update state: 'NoneType' object is not iterable
    Traceback (most recent call last):
    File "D:\work\workspace\a2a-in-action\demo\ui\state\host_agent_service.py", line 142, in UpdateAppState
    for task in await GetTasks():
    ^^^^^^^^^^^^^^^^
    TypeError: 'NoneType' object is not iterable
    INFO: 127.0.0.1:45507 - "POST /__ui__ HTTP/1.1" 200 OK
    Failed to list conversations: HTTP Error 502: Server error '502 Bad Gateway' for url 'http://localhost:12000/conversation/list'
    For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502
    Failed to list tasks HTTP Error 502: Server error '502 Bad Gateway' for url 'http://localhost:12000/task/list'
    For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502
    Failed to update state: 'NoneType' object is not iterable
    Traceback (most recent call last):
    File "D:\work\workspace\a2a-in-action\demo\ui\state\host_agent_service.py", line 142, in UpdateAppState
    for task in await GetTasks():
    ^^^^^^^^^^^^^^^^
  • Geek_84eabd

    2025-07-13 16:41:50

    Failed to list conversations: HTTP Error 502: Server error '502 Bad Gateway' for url 'http://localhost:12000/conversation/list'
    For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502
    Failed to list conversations: HTTP Error 502: Server error '502 Bad Gateway' for url 'http://localhost:12000/conversation/list'
    For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502
    Failed to list tasks HTTP Error 502: Server error '502 Bad Gateway' for url 'http://localhost:12000/task/list'
    For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502
    Failed to update state: 'NoneType' object is not iterable
    Traceback (most recent call last):
    File "C:\Users\lyy\Desktop\llm-agent\a2a-in-action-master\demo\ui\state\host_agent_service.py", line 142, in UpdateAppState
    for task in await GetTasks():
    ^^^^^^^^^^^^^^^^
    TypeError: 'NoneType' object is not iterable,咖哥,我也出现了这个问题,不知道怎么解决
    作者回复

    很多同学都遇到了NoneType Error。哪位同学可以帮忙Debug一下,看看到底是什么情况下,什么地方出错了。

    2025-07-15 13:45:50

  • 黯言

    2025-07-04 12:21:52

    补充一点:公用的vpn代理依然可能遇到“Your location is not supported by google-generativeai at the moment. ”
    可以搭个自己的vpn或者买台海外虚拟机跑agents
    作者回复

    好,谢!

    2025-07-17 20:24:10

  • LVEli

    2025-07-02 16:24:36

    请问老师,正常启动后,页面一片空白。后台日志显示如下:
    INFO: Will watch for changes in these directories: ['D:\\13.Aigc_workspace\\a2a-in-action-master\\demo\\ui']
    INFO: Uvicorn running on http://0.0.0.0:12000 (Press CTRL+C to quit)
    WARNING: --reload-include and --reload-exclude have no effect unless watchfiles is installed.
    INFO: Started reloader process [6992] using StatReload
    INFO: Started server process [27908]
    INFO: Waiting for application startup.
    INFO: Application startup complete.
    INFO: 127.0.0.1:63396 - "GET / HTTP/1.1" 200 OK
    INFO: 127.0.0.1:63396 - "GET /styles.css HTTP/1.1" 304 Not Modified
    INFO: 127.0.0.1:63396 - "GET /zone.js/bundles/zone.umd.js HTTP/1.1" 304 Not Modified
    INFO: 127.0.0.1:63397 - "GET /prod_bundle.js HTTP/1.1" 304 Not Modified
    INFO: 127.0.0.1:63397 - "POST /__ui__ HTTP/1.1" 200 OK
    INFO: 127.0.0.1:63397 - "GET /__web-components-module__/components/async_poller.js HTTP/1.1" 304 Not Modified
    作者回复

    1. 重启
    2. 等待
    3. 换一台电脑试试
    大模型都指示下面的排查手段
    可能的原因和解决方案
    1. JavaScript执行错误
    打开浏览器开发者工具(F12),查看Console选项卡是否有JavaScript错误
    检查Network选项卡,确认所有资源都正常加载
    2. 前端构建问题
    检查 prod_bundle.js 文件是否正确生成
    尝试重新构建前端资源:
    bash# 如果是npm项目
    npm run build
    # 或者
    npm run dev

    2025-07-02 23:17:12

  • YSL

    2025-07-01 17:07:32

    遇到了内容安全策略(CSP)错误。
    需要再 demo/main.py 第 59 行,增加:dangerously_disable_trusted_types=True,
    完整代码:

    security_policy = me.SecurityPolicy(
    allowed_script_srcs=[
    'https://cdn.jsdelivr.net',
    ],
    dangerously_disable_trusted_types=True, # 新增修复代码
    )

    错误:
    ⚠️ Content Security Policy Error ⚠️
    ━━━━━━━━━━━━━━━━━━
    Directive: trusted-types
    Blocked URL: trusted-types-policy
    App path: /

    ℹ️ If this is coming from your web component,
    update your security policy like this:

    @me.page(
    security_policy=me.SecurityPolicy(
    dangerously_disable_trusted_types=True
    )
    )

    For more info:
    https://mesop-dev.github.io/mesop/web-components/troubleshooting/
    作者回复

    感谢同学提供信息!

    2025-07-02 23:17:41

  • Y

    2025-06-27 17:39:27

    申请google cloud免费试用,还需要填信用卡啥的。。。不用google cloud的话,有其他替代方案吗
    作者回复

    当然也是可以的,但是同学就需要把所有相关的大模型和工具换掉。因为A2A是Google推出的,还是申请一个Google API Key比较好。是否需要google cloud,我们文章中好像没说要用到。

    2025-06-28 12:59:14

  • whyseu

    2025-06-25 22:45:07

    前端UI中的event list和task list,event和task有啥区别?
    作者回复

    非常好的问题。

    Event是系统中发生的实时事件记录,记录了各个Agent在执行过程中的活动;Task是Agent执行的任务,有明确的状态和生命周期。Event关注"发生了什么";Task关注"从头到尾做了什么"。Event List是一个活动日志,而Task List是一个任务管理器。

    用户请求 → Task创建(Task List显示) → Task执行 → Task状态更新 → Event生成(Event List显示)

    跟具体来说:
    Task状态变化是,submitted → working → completed,每次状态变化都会生成对应的Event
    Task输出更新,产生新的artifact(如文本、图片等),立即生成包含该artifact的Event。Task List显示具体任务的状态和结果。
    Event记录,并通过Event List显示哪个Agent在什么时间做了什么。

    触发关系:Task的任何变化都会触发Event的生成
    包含关系:Event包含了Task的执行信息(执行者、内容、时间)
    显示关系:Event List提供活动日志视图,Task List提供任务管理视图
    数据关系:Event是Task执行过程的"快照"记录

    这种设计使得系统既能跟踪具体的任务执行状态,也就是Task,又能记录完整的活动历史,也就是Event。

    不知这样说是否准确,希望大家研读UI代码之后进行进一步的讨论。

    2025-06-26 10:10:46

  • YX

    2025-06-22 10:50:01

    google.genai.errors.ClientError: 400 FAILED_PRECONDITION. {'error': {'code': 400, 'message': 'User location is not supported for the API use.', 'status': 'FAILED_PRECONDITION'}}

    老师,这个对国内用户感觉不是很友好,能替换模型,用其他模型实现a2a吗?
    作者回复

    可以啊,同学可否自己手动替换成DeepSeek。回头我有空时候Repo里面加DeepSeek版本。A2A 是 Google推出的,示例里面大量的Google生态,可以理解。

    2025-06-23 11:40:48

  • Geek_aaf8c9

    2025-06-21 22:03:56

    启动加载页面报错了
    [2025-06-21 22:00:44,107] ERROR in app: Exception on /.well-known/appspecific/com.chrome.devtools.json [GET]
    Traceback (most recent call last):
    File "C:\Soft\workplace\a2a-in-action\demo\ui\.venv\Lib\site-packages\flask\app.py", line 1511, in wsgi_app
    response = self.full_dispatch_request()
    File "C:\Soft\workplace\a2a-in-action\demo\ui\.venv\Lib\site-packages\flask\app.py", line 919, in full_dispatch_request
    rv = self.handle_user_exception(e)
    File "C:\Soft\workplace\a2a-in-action\demo\ui\.venv\Lib\site-packages\flask\app.py", line 917, in full_dispatch_request
    rv = self.dispatch_request()
    File "C:\Soft\workplace\a2a-in-action\demo\ui\.venv\Lib\site-packages\flask\app.py", line 902, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]

    File "C:\Soft\workplace\a2a-in-action\demo\ui\.venv\Lib\site-packages\mesop\server\static_file_serving.py", line 141, in serve_file
    return send_file_compressed(
    get_path(path),
    disable_gzip_cache=disable_gzip_cache,
    )
    File "C:\Soft\workplace\a2a-in-action\demo\ui\.venv\Lib\site-packages\mesop\server\static_file_serving.py", line 345, in send_file_compressed
    response = send_file(path)
    File "C:\Soft\workplace\a2a-in-action\demo\ui\.venv\Lib\site-packages\flask\helpers.py", line 511, in send_file
    return werkzeug.utils.send_file( # type: ignore[return-value]
    ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    **_prepare_send_file_kwargs(
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<9 lines>...
    )
    ^
    )
    ^
    File "C:\Soft\workplace\a2a-in-action\demo\ui\.venv\Lib\site-packages\werkzeug\utils.py", line 428, in send_file
    stat = os.stat(path)
    FileNotFoundError: [WinError 3] 系统找不到指定的路径。: 'C:\\Soft\\workplace\\a2a-in-action\\demo\\ui\\.venv\\Lib\\site-packages
    Failed to update state: 'NoneType' object is not iterable
    作者回复

    这个DevTools错误是Mesop框架的问题,不是你的应用代码问题,可以暂时忽略。主要需要解决的是后端服务的502错误。你看看你的后端是否正常启动了,API Key是否有了。

    2025-06-23 12:20:20

  • Geek_aaf8c9

    2025-06-21 22:01:49

    启动加载页面就报错了
    作者回复

    具体错误是什么呢?可否
    1. 把错误发给Cursor或LLM分析一下
    2. 看看https://github.com/huangjia2019/a2a-in-action/issues/1这个链接。

    2025-06-22 23:11:17

  • Geek_de7f58

    2025-06-21 11:30:34

    能不用Google API key及Google的大模型,使用ollama模型吗
    作者回复

    当然可以了!同学要不要手动试一试。
    替换位置就是,在CurrencyAgent(LangGraph)、CrewAI Agent 等这些具体的Agent的位置,把相应的Agent实现框架里面LLM的实现替换掉就可以了。直接和LLM对话,或者在Cursor里面直接提需求,基本上两三轮就能搞定。

    2025-06-23 11:29:23

  • chun1123

    2025-06-20 08:47:55

    老师帮忙看下这个报错

    http error Server error '502 Bad Gateway' for url 'http://0.0.0.0:12000/task/list'
    For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502
    Failed to list tasks HTTP Error 502: Server error '502 Bad Gateway' for url 'http://0.0.0.0:12000/task/list'
    For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502
    Failed to update state: 'NoneType' object is not iterable
    Traceback (most recent call last):
    File "D:\pycharmProjects\a2a-samples\demo\ui\state\host_agent_service.py", line 154, in UpdateAppState
    for task in await GetTasks():
    ^^^^^^^^^^^^^^^^
    TypeError: 'NoneType' object is not iterable
    http error Server error '502 Bad Gateway' for url 'http://0.0.0.0:12000/conversation/list'
    作者回复

    哦,这个错应该是你后端服务没有启动成功,或者运行失败了。你看看你是否有相关的API Key。就是那个LangGraph智能体的LLM API Key。看看后端运行日志。实在没有Key,换个LLM。

    2025-06-23 11:39:14

  • aloha66

    2025-06-16 23:10:54

    在运行发送第一句话的时候报了这个错AttributeError: 'NoneType' object has no attribute 'state'。好像跟这里有关target=lambda: asyncio.run(self.manager.process_message(message)),希望老师解答一下
    作者回复

    我这边复现了一下流程,没有遇到这个问题。有没有进一步的错误上下文信息?Python版本和当前.venv的所有版本是啥?正如另一个同学留言中所建议的,这个问题可能直接问问Cursor比较好,因为Cursor可以自己观察你的程序代码,以及所安装的相关库的情况,直接找到问题。

    2025-06-17 20:33:07