A2A协议
什么是A2A协议?
A2A(Agent-to-Agent)协议是一种让智能代理(Agent)之间进行通信的标准方式。你可以把它想象成两个Agent之间的交流方式,让它们能够互相理解和协作。
协议:不同系统,不同个体之间能够有效沟通和协作的一套规则和标准。
为什么需要A2A协议?
你可能会问:这跟我自己写个脚本,手写提示词调几次大模型 API,最后把结果拼起来返回,有什么区别?
如果是写一次性脚本,确实没区别。但 A2A 的关键在于连接性 ------它能让你的 Agent 直接暴露给外部使用,从"写一个工具给自己用 "转变为"开发一个 Agent 供生态使用"。
这就好比你自己写个工具函数,和发布一个标准的三方包的区别:
以前你得把代码复制给别人,或者写一堆文档告诉别人怎么调你的接口;现在,遵循 A2A 协议,你的 Agent 就像发布到中央仓库的包一样,任何 Agent 都能自动发现、下载并调用它 (你需要知道对方的 URL(Endpoint) 。拿到 URL 后,请求这个地址,Agent 会返回一个标准的 Agent Card(名片)),无需额外适配。
Prompt 是给 Agent 一个"聪明的大脑",让它知道"该怎么做";
A2A 协议是给 Agent 一套"通用的语言和社交礼仪",让它知道"该怎么与人合作"。
A2A协议的核心概念
1. Agent Card(代理名片)
就像人的名片一样,告诉别人"我是谁,我能做什么"。
2. Task(任务)
代表一个具体的工作单元,比如"查询北京天气"
3. TaskStatus(任务状态)
任务执行过程中会有不同状态:
submitted:已提交working:正在处理(流式输出)completed:已完成failed:失败
4. EventQueue(事件队列)
初始化 -> 干活 -> 发Artifact(结果) -> 发Status(完结) 这是A2A协议的关键机制,代理通过事件队列不断向外发送状态和结果:
- 先推送Task(我接到活了)
- 再推送WORKING状态(我正在干...)
- 推送Artifact(这是我干出来的成果/半成品)
- 最后推送final=True的COMPLETED(我干完了)
5. JSON-RPC
一种特定格式的JSON传输协议,用于代理间的标准化通信。JSON-RPC本质上就是把RESTful的"动词(GET/POST)+路径(/api/weather)"压缩成了"method: getWeather"一个字段。
最小可运行代码

后端(main.py)- 天气助手代理
python
# main.py
"""
最简单的 A2A Agent 后端示例
"""
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.apps import A2AStarletteApplication
from a2a.server.events import EventQueue
from a2a.server.agent_execution import AgentExecutor, RequestContext
from a2a.server.tasks import InMemoryTaskStore
from a2a.types import AgentCard, AgentSkill
from a2a.types import (
AgentCapabilities,
AgentCard,
AgentInterface,
AgentSkill,
)
import uvicorn
from agent_executor import WeatherAgentExecutor
def main():
# 1. 声明技能
skill = AgentSkill(
id='check_weather',
name='查询天气',
description='根据用户提供的城市名称,查询该城市的实时天气情况',
tags=['天气', '查天气', '气温'],
# examples=['北京今天天气怎么样?', '帮我查一下上海的天气', '广州冷不冷']
)
# 2. 定义能力(你的硬件配置,全用默认的就行)
capabilities = AgentCapabilities(streaming=False)
# 3. Agent 卡片信息
agent_card = AgentCard(
name='天气助手',
version='1.0.0',
description='一个能够根据城市名称查询实时天气的智能代理',
capabilities=capabilities,
preferred_transport='JSONRPC', # default='JSONRPC', examples=['JSONRPC', 'GRPC', 'HTTP+JSON']
url='http://localhost:8000',
defaultInputModes=["text"], # 必需字段
defaultOutputModes=["text"],
skills=[skill],
)
# 4. 创建执行器和事件队列
executor = WeatherAgentExecutor()
request_handler = DefaultRequestHandler(agent_executor=executor,task_store=InMemoryTaskStore())
# 5. 创建应用
app = A2AStarletteApplication(agent_card=agent_card, http_handler=request_handler)
# 6. 启动应用
print("🚀 A2A Agent 启动在 http://localhost:8000")
uvicorn.run(app.build(), host="0.0.0.0", port=8000)
if __name__ == "__main__":
main()
执行器(agent_executor.py)- 实际工作逻辑
这是 A2A 的精髓,初始化 -> 干活 -> 发Artifact -> 发Status
python
# agent_executor.py
from a2a.server.agent_execution import AgentExecutor, RequestContext
from a2a.server.events import EventQueue
from a2a.utils import new_task, new_text_artifact
from a2a.types import TaskArtifactUpdateEvent, TaskStatusUpdateEvent, TaskStatus, TaskState
class WeatherAgentExecutor(AgentExecutor):
async def execute(self, context: RequestContext, event_queue: EventQueue):
# 1. 初始化任务(应对并发:多用户同时来,各拿各的 task_id)
task = context.current_task or new_task(context.message)
await event_queue.enqueue_event(task)
# 2. 获取用户发来的文本
query = context.message.parts[0].root.text
# ================= 核心业务区 =================
# 实际工作中,这里可能是调用大模型、查外部 API 等
result_text = f"问题:{query}\n答案:北京今天晴天,气温 25°C。"
# ==============================================
# 3. 发送结果文本(把最终答案放进包裹里)
await event_queue.enqueue_event(
TaskArtifactUpdateEvent(
task_id=task.id,
context_id=task.context_id,
artifact=new_text_artifact(name='response', text=result_text),
)
)
# 4. 标记任务完成(告诉客户端:包裹发完了,结束吧)
await event_queue.enqueue_event(
TaskStatusUpdateEvent(
task_id=task.id,
context_id=task.context_id,
status=TaskStatus(state=TaskState.completed),
final=True # 👈 非常关键,代表这次交互彻底结束
)
)
前端(test.py)- 客户端调用
python
# test.py
"""
测试 A2A Agent
"""
import httpx
import asyncio
import json
from uuid import uuid4
from a2a.client import A2ACardResolver
from a2a.client.client import ClientConfig
from a2a.client.client_factory import ClientFactory
from a2a.types import (
Message,
Part,
Role,
)
from a2a.utils.constants import AGENT_CARD_WELL_KNOWN_PATH
async def main():
base_url = "http://localhost:8000"
# 打通一个电话线路,不用的时候自动断开,httpx相当于requests的升级版,支持异步
async with httpx.AsyncClient() as httpx_client:
# 初始化 A2ACardResolver,用来接收和解析 Agent Card(名片)
resolver = A2ACardResolver(
httpx_client=httpx_client,
base_url=base_url,
)
_public_card = (await resolver.get_agent_card())
# print(f'_public_card: {json.dumps(_public_card.dict(), indent=2, ensure_ascii=False)}') # 名片信息
# 封装好的客户端,用于发请求
client_factory = ClientFactory(config=ClientConfig(streaming=False))
client = client_factory.create(_public_card)
# 组建消息
parts = [Part(text='我要查看北京的天气')]
message = Message(
role=Role.user,
parts=parts,
message_id=uuid4().hex,
)
# request = SendMessageRequest(id=uuid4().hex, params=MessageSendParams(message=message))
# 发送消息,接收响应
response = client.send_message(message)
async for task, update in response:
# print(json.dumps(task.model_dump(), indent=2, ensure_ascii=False)) # 完整json
if task and task.artifacts:
for artifact in task.artifacts:
for part in artifact.parts:
# 直接打印纯文本
print("Agent 回复:", part.root.text)
if __name__ == "__main__":
asyncio.run(main())
A2A vs MCP协议
- A2A协议:Agent与Agent之间的交流方式
- MCP协议:Agent与Tool(工具)之间的交流方式
gRPC vs HTTP + JSON-RPC
- HTTP + JSON-RPC :传的是明文 JSON。优点 是人眼能直接看懂,前后端对接极其方便,不用依赖任何特殊工具;缺点是数据体积大,解析相对较慢。
- gRPC :传的是 Protobuf(二进制格式)。优点 是体积小 3-10 倍,解析速度快几倍到几十倍,性能拉满;缺点是肉眼看着全是乱码,调试极其痛苦,必须用专门的工具才能解码。
总结
前端拿着你的 Endpoint (URL) 找到你,获取你的 Agent Card(名片,功能),通过 JSON-RPC 给你发了一个 Task。你开始干活,通过 EventQueue 不断往外扔状态和产出物,最后扔出一个带 final=True 的完成状态,结束这次与Agent的交流。