1. 从零开始理解A2A协议
A2A(Agent-to-Agent)协议是近年来兴起的一种智能体间通信标准,它定义了不同智能体之间如何发现彼此、交换信息以及协同工作。作为一名长期从事智能系统开发的工程师,我发现A2A协议最吸引人的地方在于它的简洁性和扩展性——就像HTTP协议之于Web开发一样,A2A为智能体生态提供了基础通信框架。
在这个教程中,我们将通过构建一个最简单的"回显"服务器来理解A2A的核心概念。这个服务器会接收任何请求,然后固定返回"Hello World"字符串。虽然功能简单,但它包含了A2A智能体的所有关键组件:
- 智能体卡片(Agent Card):智能体的"身份证"
- 智能体技能(Agent Skills):智能体能做什么
- 执行器(Executor):如何处理请求
- 通信协议:如何与客户端交互
2. 环境准备与SDK安装
2.1 Python环境配置
A2A Python SDK要求Python 3.10或更高版本。我推荐使用pyenv或conda来管理Python环境,这样可以避免系统Python环境被污染。以下是我的常用设置方式:
# 使用pyenv创建专用环境 pyenv install 3.10.6 pyenv virtualenv 3.10.6 a2a-tutorial pyenv activate a2a-tutorial提示:如果你在Windows系统上,可以使用WSL2来获得更好的开发体验。我在Windows 11 + WSL2 Ubuntu 22.04环境下测试通过。
2.2 安装A2A SDK
安装A2A SDK非常简单,只需要一个pip命令:
pip install a2a-sdk我测试时使用的是0.3.16版本,你可以通过以下命令确认安装成功:
pip show a2a-sdk如果一切正常,你应该能看到类似这样的输出:
Name: a2a-sdk Version: 0.3.16 Summary: Python SDK for A2A protocol ...3. 定义智能体能力
3.1 智能体技能(Agent Skills)
智能体技能是A2A协议中的核心概念之一,它定义了智能体能够执行的具体操作。在我们的Hello World示例中,我们只需要定义一个最简单的技能:
from a2a.types import AgentSkill skill = AgentSkill( id='hello_world', name='Returns hello world', description='just returns hello world', tags=['hello world'], examples=['hi', 'hello world'], )这个技能定义包含几个关键部分:
id: 技能的唯一标识符,在智能体内部必须是唯一的name: 人类可读的技能名称description: 技能的详细描述tags: 用于分类和搜索的关键词examples: 使用示例,帮助客户端理解如何调用这个技能
实际开发中,我建议为每个技能编写详细的description和examples,这能大大提升智能体的可用性。我曾经在一个项目中因为description写得太简略,导致其他开发者误用技能,花了大量时间排查问题。
3.2 智能体卡片(Agent Card)
智能体卡片相当于智能体的"身份证",它告诉外界这个智能体是谁、能做什么、如何交互。我们的Hello World智能体卡片定义如下:
from a2a.types import AgentCard, AgentCapabilities public_agent_card = AgentCard( name='Hello World Agent', description='Just a hello world agent', url='http://localhost:9999/', version='1.0.0', default_input_modes=['text'], default_output_modes=['text'], capabilities=AgentCapabilities(streaming=True), skills=[skill], supports_authenticated_extended_card=True, )智能体卡片的关键字段包括:
url: 智能体的访问地址default_input_modes: 默认支持的输入类型(如text, audio等)capabilities: 声明智能体支持的高级功能(如流式传输)skills: 该智能体提供的技能列表
一个实用的技巧是提供扩展卡片(Extended Card),为经过认证的用户提供额外功能:
extended_skill = AgentSkill( id='super_hello_world', name='Returns a SUPER Hello World', description='A more enthusiastic greeting, only for authenticated users.', tags=['hello world', 'super', 'extended'], examples=['super hi', 'give me a super hello'], ) specific_extended_agent_card = public_agent_card.model_copy( update={ 'name': 'Hello World Agent - Extended Edition', 'description': 'The full-featured hello world agent for authenticated users.', 'version': '1.0.1', 'skills': [skill, extended_skill], } )这种设计模式在实际项目中非常有用,可以实现功能分级,基础功能对所有人开放,高级功能需要认证才能使用。
4. 实现智能体逻辑
4.1 创建执行器(Executor)
执行器是智能体的"大脑",负责处理请求并生成响应。我们需要继承AgentExecutor类并实现两个关键方法:
from a2a.server.agent_execution import AgentExecutor, RequestContext from a2a.server.events import EventQueue from a2a.utils import new_agent_text_message class HelloWorldAgent: """实际的业务逻辑封装""" async def invoke(self) -> str: return 'Hello World' class HelloWorldAgentExecutor(AgentExecutor): """A2A协议执行器实现""" def __init__(self): self.agent = HelloWorldAgent() async def execute(self, context: RequestContext, event_queue: EventQueue) -> None: result = await self.agent.invoke() await event_queue.enqueue_event(new_agent_text_message(result)) async def cancel(self, context: RequestContext, event_queue: EventQueue) -> None: raise Exception('cancel not supported')这里有几个关键点需要注意:
execute方法是异步的,因为智能体操作可能需要时间- 我们使用
event_queue来发送响应,而不是直接返回 new_agent_text_message工具函数帮助创建符合A2A协议的响应消息
在实际项目中,我建议在
execute方法中添加详细的日志记录,这对调试和监控非常有帮助。我曾经因为缺少日志,花了三天时间排查一个偶发的执行问题。
4.2 理解请求上下文
RequestContext参数包含了当前请求的所有相关信息,在实际项目中常用的属性包括:
request_message: 用户发送的消息内容task_id: 当前任务的唯一标识符user_info: 用户身份信息(如果启用了认证)
虽然我们的Hello World示例没有使用这些信息,但在实际开发中,它们非常关键。例如,你可以根据user_info实现个性化响应。
5. 启动A2A服务器
5.1 服务器配置
现在我们把所有部分组合起来,创建一个完整的A2A服务器:
import uvicorn from a2a.server.apps import A2AStarletteApplication from a2a.server.request_handlers import DefaultRequestHandler from a2a.server.tasks import InMemoryTaskStore request_handler = DefaultRequestHandler( agent_executor=HelloWorldAgentExecutor(), task_store=InMemoryTaskStore(), ) server = A2AStarletteApplication( agent_card=public_agent_card, http_handler=request_handler, extended_agent_card=specific_extended_agent_card, ) uvicorn.run(server.build(), host='0.0.0.0', port=9999)关键组件说明:
DefaultRequestHandler: 处理A2A协议的RPC调用InMemoryTaskStore: 在内存中管理任务状态(生产环境可能需要持久化存储)A2AStarletteApplication: 基于Starlette框架的A2A服务器实现
5.2 运行服务器
将上述代码保存为server.py,然后运行:
python server.py你应该能看到类似输出:
INFO: Started server process [12345] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:9999 (Press CTRL+C to quit)生产环境建议使用Gunicorn+Uvicorn的组合来获得更好的性能。我曾经用这种配置处理过每秒上千次的A2A请求。
6. 与智能体交互
6.1 创建测试客户端
让我们创建一个客户端来测试我们的智能体:
import asyncio import logging from uuid import uuid4 import httpx from a2a.client import A2ACardResolver, A2AClient from a2a.types import MessageSendParams, SendMessageRequest, SendStreamingMessageRequest async def test_agent(): base_url = 'http://localhost:9999' async with httpx.AsyncClient() as client: # 获取智能体卡片 resolver = A2ACardResolver(client, base_url) card = await resolver.get_agent_card() # 初始化A2A客户端 a2a_client = A2AClient(client, card) # 准备请求数据 message_data = { 'message': { 'role': 'user', 'parts': [{'kind': 'text', 'text': 'hi'}], 'messageId': uuid4().hex, } } # 发送普通请求 request = SendMessageRequest( id=str(uuid4()), params=MessageSendParams(**message_data) ) response = await a2a_client.send_message(request) print("普通响应:", response.result.message.parts[0].text) # 发送流式请求 stream_request = SendStreamingMessageRequest( id=str(uuid4()), params=MessageSendParams(**message_data) ) async for chunk in a2a_client.send_message_streaming(stream_request): print("流式响应:", chunk.result.message.parts[0].text) asyncio.run(test_agent())6.2 理解客户端交互
客户端与智能体的交互遵循以下流程:
- 通过
/.well-known/agent-card.json获取智能体卡片 - 从卡片中了解智能体的能力和端点
- 构造符合A2A协议的请求
- 发送请求并处理响应
在我们的示例中,无论是普通请求还是流式请求,智能体都会返回"Hello World"。
实际项目中,流式请求通常用于处理需要较长时间的任务,比如大语言模型的生成。我建议在实现流式响应时添加心跳机制,防止连接超时。
7. 进阶话题与最佳实践
7.1 错误处理与重试机制
在实际使用A2A协议时,健壮的错误处理非常重要。以下是我总结的几个关键点:
客户端重试策略:
- 对瞬时错误(如网络超时)实现指数退避重试
- 对4xx错误(如无效请求)不要重试
- 记录失败请求以便后续分析
服务端错误响应:
- 使用标准的A2A错误代码
- 在错误消息中包含足够的信息用于调试
- 避免暴露内部实现细节
# 客户端重试示例 async def send_with_retry(client, request, max_retries=3): for attempt in range(max_retries): try: return await client.send_message(request) except httpx.NetworkError as e: if attempt == max_retries - 1: raise await asyncio.sleep(2 ** attempt)7.2 性能优化技巧
经过多个A2A项目的实践,我总结了以下性能优化经验:
连接池管理:
- 重用HTTP客户端实例
- 合理设置连接池大小
- 监控连接使用情况
异步处理:
- 使用async/await避免阻塞
- 对CPU密集型任务考虑使用线程池
- 使用内存缓存减少重复计算
监控指标:
- 记录请求处理时间
- 监控错误率
- 跟踪队列长度和系统负载
# 监控装饰器示例 def monitor_a2a(endpoint): def decorator(func): @wraps(func) async def wrapper(*args, **kwargs): start = time.monotonic() try: result = await func(*args, **kwargs) record_metrics(endpoint, time.monotonic() - start, True) return result except Exception as e: record_metrics(endpoint, time.monotonic() - start, False) raise return wrapper return decorator # 在处理器方法上使用 @monitor_a2a("hello_world") async def execute(self, context, event_queue): ...7.3 安全实践
A2A智能体的安全性不容忽视,以下是我推荐的安全措施:
认证与授权:
- 使用OAuth2或API密钥进行认证
- 实现基于角色的访问控制
- 定期轮换密钥
输入验证:
- 验证所有输入数据的格式
- 限制输入大小和复杂度
- 对特殊字符进行转义
传输安全:
- 强制使用HTTPS
- 启用HSTS
- 使用最新的TLS版本
# 输入验证示例 def validate_message(message: dict) -> bool: if not isinstance(message.get('parts'), list): return False for part in message['parts']: if part['kind'] == 'text' and len(part['text']) > 1000: return False return True8. 项目扩展思路
虽然我们的Hello World示例很简单,但它包含了A2A智能体的所有核心组件。你可以基于此进行多种扩展:
添加真实技能:
- 集成外部API(如天气查询)
- 连接数据库获取信息
- 调用机器学习模型
实现多轮对话:
- 维护对话状态
- 支持上下文跟踪
- 处理用户反馈
构建智能体网络:
- 多个智能体协同工作
- 智能体间互相调用
- 实现技能组合
# 多技能智能体示例 class MultiSkillAgent: async def get_weather(self, location): # 调用天气API return f"Weather in {location}: Sunny" async def get_time(self): return f"Current time: {datetime.now()}" class AdvancedExecutor(AgentExecutor): async def execute(self, context, event_queue): message = context.request_message.parts[0].text if "weather" in message: result = await self.agent.get_weather("Beijing") else: result = await self.agent.get_time() await event_queue.enqueue_event(new_agent_text_message(result))通过这个简单的Hello World项目,我们完整走过了A2A智能体的开发流程。虽然功能简单,但它展示了A2A协议的核心概念和开发模式。在实际项目中,你可以基于这个框架构建各种复杂的智能体应用。