在前面三篇文章中,我们已经了解了A2A协议的基本概念、核心组件以及它与MCP的协同关系。今天,我们将进入实战环节,带领大家从零开始搭建一个A2A兼容的智能体。本篇文章将集中在环境配置和基础组件构建上,手把手带你入门A2A开发。
准备工作:搭建开发环境
开始开发A2A智能体前,我们需要准备好开发环境。这个过程并不复杂,只需遵循以下几个步骤:
1. 安装Python
A2A SDK使用Python开发,因此首先确保您的系统已安装Python 3.8或更高版本:
# 检查Python版本
python --version
如果需要安装或升级Python,可以访问Python官网下载最新版本。
2. 创建虚拟环境
为了避免依赖冲突,建议为A2A项目创建独立的虚拟环境:
# 创建项目目录
mkdir my-a2a-agent
cd my-a2a-agent
# 创建虚拟环境
python -m venv venv
# 激活虚拟环境
# Windows
venv\Scripts\activate
# macOS/Linux
source venv/bin/activate
3. 安装A2A SDK
激活虚拟环境后,使用pip安装A2A SDK:
# 确保pip是最新版本
pip install --upgrade pip
# 安装A2A SDK和其他工具
pip install a2a-sdk pytest black
# 保存依赖
pip freeze > requirements.txt
4. 创建项目结构
一个典型的A2A项目结构如下:
my-a2a-agent/
├── README.md
├── requirements.txt
├── main.py # 入口文件
├── agent/
│ ├── __init__.py
│ ├── card.py # Agent Card定义
│ ├── executor.py # Agent执行器
│ └── skills/ # Agent技能目录
│ ├── __init__.py
│ └── hello.py # 示例技能
└── tests/ # 测试目录
├── __init__.py
└── test_skills.py
让我们创建这个结构:
mkdir -p agent/skills tests
touch README.md main.py
touch agent/__init__.py agent/card.py agent/executor.py
touch agent/skills/__init__.py agent/skills/hello.py
touch tests/__init__.py tests/test_skills.py
第一步:定义基础技能
作为入门示例,我们将创建一个简单的"Hello World"智能体,它能够问候用户并进行简单的计算。
编辑agent/skills/hello.py:
from typing import Dict, List, Any, Optional
from a2a.types import AgentSkill
# 定义问候技能
def greet(name: str, language: str = "en") -> str:
"""
向用户发送问候
Args:
name: 用户名
language: 语言代码(默认英语)
Returns:
个性化问候语
"""
greetings = {
"en": f"Hello, {name}! Welcome to A2A!",
"zh": f"你好,{name}!欢迎使用A2A!",
"es": f"¡Hola, {name}! ¡Bienvenido a A2A!",
"fr": f"Bonjour, {name}! Bienvenue à A2A!"
}
return greetings.get(language, greetings["en"])
# 定义计算技能
def calculate(operation: str, a: float, b: float) -> Dict[str, Any]:
"""
执行基本数学运算
Args:
operation: 运算类型(add、subtract、multiply、divide)
a: 第一个数字
b: 第二个数字
Returns:
包含运算结果的字典
"""
result = None
if operation == "add":
result = a + b
elif operation == "subtract":
result = a - b
elif operation == "multiply":
result = a * b
elif operation == "divide":
if b == 0:
return {
"error": "除数不能为零",
"success": False
}
result = a / b
else:
return {
"error": f"不支持的运算: {operation}",
"success": False
}
return {
"operation": operation,
"a": a,
"b": b,
"result": result,
"success": True
}
# 注册A2A技能
greet_skill = AgentSkill(
id="greet",
name="问候用户",
description="向用户发送个性化问候",
function=greet,
examples=["向张三发送中文问候", "用英语问候李四"]
)
calculate_skill = AgentSkill(
id="calculate",
name="基础计算器",
description="执行基本数学运算",
function=calculate,
examples=["计算 5 加 3", "将 10 除以 2"]
)
# 导出技能列表
available_skills = [greet_skill, calculate_skill]
这里我们定义了两个基本技能:
greet:根据指定的语言向用户发送问候语calculate:执行四则运算,并返回结构化结果
每个技能都有详细的文档字符串,解释其参数和返回值,这是良好实践的一部分。
第二步:创建Agent Card
接下来,我们需要为智能体创建一个"名片",向外部声明其身份和能力。
编辑agent/card.py:
from a2a.types import (
AgentCard,
AgentCapabilities,
AgentAuthentication,
AgentSkill
)
from agent.skills.hello import available_skills
def create_agent_card(
base_url: str = "http://localhost:8000",
name: str = "hello-world-agent",
version: str = "1.0.0"
) -> AgentCard:
"""
创建Agent Card
Args:
base_url: 智能体服务的基础URL
name: 智能体名称
version: 智能体版本
Returns:
配置好的AgentCard对象
"""
# 定义智能体能力
capabilities = AgentCapabilities(
streaming=True,
pushNotifications=False,
stateTransitionHistory=True
)
# 定义认证需求(这里设置为不需要认证,仅用于演示)
authentication = AgentAuthentication(
schemes=[] # 空列表表示不需要认证
)
# 创建Agent Card
card = AgentCard(
name=name,
description="一个入门级A2A智能体示例,提供问候和计算功能",
url=base_url,
version=version,
capabilities=capabilities,
authentication=authentication,
defaultInputModes=["text/plain"],
defaultOutputModes=["text/plain", "application/json"],
skills=available_skills
)
return card
Agent Card定义了智能体的核心属性:
- 基本信息(名称、描述、版本)
- 服务URL
- 技术能力(如是否支持流式响应)
- 认证需求
- 默认输入/输出格式
- 提供的技能列表
创建标准化的Agent Card是智能体被发现和使用的关键。
第三步:实现Agent执行器
Agent执行器是智能体的"大脑",负责接收请求、执行相应技能并返回结果。
编辑agent/executor.py:
from typing import Dict, Any, Optional, List
from a2a.types import Task, TaskStatus, Message, TextPart, DataPart
from agent.skills.hello import greet, calculate
class HelloWorldAgentExecutor:
"""Hello World智能体执行器"""
def __init__(self):
"""初始化执行器"""
self.skills = {
"greet": self._execute_greet,
"calculate": self._execute_calculate
}
async def execute_task(self, task: Task) -> Task:
"""
执行任务
Args:
task: 输入任务对象
Returns:
更新后的任务对象
"""
# 获取用户消息
user_message = task.message
if not user_message or user_message.role != "user":
task.status = TaskStatus.FAILED
task.message = Message(
role="agent",
parts=[TextPart(text="无效的用户消息")]
)
return task
# 分析用户意图(简化版)
intent = self._analyze_intent(user_message)
# 根据意图执行相应技能
if intent["skill"] in self.skills:
result = await self.skills[intent["skill"]](intent["params"])
# 创建响应消息
if isinstance(result, str):
response_part = TextPart(text=result)
else:
response_part = DataPart(data=result)
# 更新任务
task.status = TaskStatus.COMPLETED
task.message = Message(
role="agent",
parts=[response_part]
)
else:
# 未识别的技能
task.status = TaskStatus.FAILED
task.message = Message(
role="agent",
parts=[TextPart(text=f"未找到技能: {intent['skill']}")]
)
return task
def _analyze_intent(self, message: Message) -> Dict[str, Any]:
"""
简化的意图分析
实际应用中,这里可能会调用LLM或其他复杂的NLP服务
本示例中,我们假设消息中直接包含了技能名称和参数
格式:{"skill": "技能名称", "params": {...参数...}}
"""
if len(message.parts) == 0:
return {"skill": "unknown", "params": {}}
# 尝试从消息中提取JSON数据
for part in message.parts:
if part.type == "data":
data = part.data
if isinstance(data, dict) and "skill" in data:
return data
# 简单文本处理(仅示例用)
text = ""
for part in message.parts:
if part.type == "text":
text = part.text
break
if "问候" in text or "hello" in text.lower() or "greet" in text.lower():
# 简单解析:"问候张三"或"用中文问候张三"
parts = text.split()
name = parts[-1] if len(parts) > 1 else "Guest"
language = "zh" if "中文" in text else "en"
return {"skill": "greet", "params": {"name": name, "language": language}}
if any(op in text for op in ["计算", "加", "减", "乘", "除", "calculate"]):
# 非常简化的解析,实际应用中应使用更复杂的NLP
operation = "add" # 默认加法
a, b = 0, 0
if "加" in text or "+" in text:
operation = "add"
elif "减" in text or "-" in text:
operation = "subtract"
elif "乘" in text or "*" in text:
operation = "multiply"
elif "除" in text or "/" in text:
operation = "divide"
# 非常简化的数字提取
import re
numbers = re.findall(r'\d+', text)
if len(numbers) >= 2:
a = float(numbers[0])
b = float(numbers[1])
return {"skill": "calculate", "params": {"operation": operation, "a": a, "b": b}}
# 默认响应
return {"skill": "greet", "params": {"name": "Guest"}}
async def _execute_greet(self, params: Dict[str, Any]) -> str:
"""执行问候技能"""
name = params.get("name", "Guest")
language = params.get("language", "en")
return greet(name, language)
async def _execute_calculate(self, params: Dict[str, Any]) -> Dict[str, Any]:
"""执行计算技能"""
operation = params.get("operation", "add")
a = params.get("a", 0)
b = params.get("b", 0)
return calculate(operation, a, b)
这个执行器包含三个主要组件:
- 意图分析:解析用户请求,确定需要使用哪个技能以及相应的参数
- 技能执行:调用相应的技能函数,处理参数和结果
- 响应生成:根据技能执行结果,生成格式化的响应
在实际应用中,意图分析部分可能会更加复杂,通常会借助大型语言模型(LLM)来理解用户意图。
第四步:创建入口文件
最后,我们需要创建一个入口文件,将所有组件连接起来并启动服务器。
编辑main.py:
import asyncio
import uvicorn
from a2a.server.apps import A2AStarletteApplication
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.tasks import InMemoryTaskStore
from agent.card import create_agent_card
from agent.executor import HelloWorldAgentExecutor
# 配置参数
HOST = "127.0.0.1"
PORT = 8000
BASE_URL = f"http://{HOST}:{PORT}"
async def main():
"""主函数"""
print(f"启动 Hello World A2A 智能体 ({BASE_URL})...")
# 创建Agent Card
agent_card = create_agent_card(base_url=BASE_URL)
print(f"已创建Agent Card: {agent_card.name} (v{agent_card.version})")
# 创建Agent执行器
executor = HelloWorldAgentExecutor()
print(f"已初始化执行器,支持技能: {', '.join(executor.skills.keys())}")
# 创建任务存储
task_store = InMemoryTaskStore()
# 创建请求处理器
request_handler = DefaultRequestHandler(
task_executor=executor.execute_task,
task_store=task_store,
agent_card=agent_card
)
# 创建A2A应用
app = A2AStarletteApplication(
request_handler=request_handler,
agent_card=agent_card
)
# 启动服务器
config = uvicorn.Config(
app=app,
host=HOST,
port=PORT,
log_level="info"
)
server = uvicorn.Server(config)
await server.serve()
if __name__ == "__main__":
# 运行主函数
asyncio.run(main())
入口文件完成了以下工作:
- 创建Agent Card
- 初始化Agent执行器
- 设置内存任务存储
- 配置请求处理器
- 创建A2A服务器应用
- 启动HTTP服务器
运行你的第一个A2A智能体
完成上述所有步骤后,就可以运行智能体了:
# 确保虚拟环境已激活
python main.py
如果一切正常,你应该会看到类似下面的输出:
启动 Hello World A2A 智能体 (http://127.0.0.1:8000)...
已创建Agent Card: hello-world-agent (v1.0.0)
已初始化执行器,支持技能: greet, calculate
INFO: Started server process [12345]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
现在,你的A2A智能体已经在本地运行了!它提供以下端点:
/.well-known/agent.json:Agent Card,描述智能体的能力/tasks/send:发送同步任务请求/tasks/sendSubscribe:发送支持流式处理的任务请求/tasks/get:获取任务状态
验证你的Agent Card
你可以通过浏览器访问 http://127.0.0.1:8000/.well-known/agent.json 来查看你的Agent Card。它应该显示一个包含智能体能力和技能信息的JSON对象。
小结与展望
恭喜!你已经成功从零开始创建了一个A2A兼容的智能体,它包含了标准的Agent Card、执行器和基本技能。虽然这个示例相对简单,但它包含了A2A协议的核心组件,可以作为你构建更复杂智能体的基础。
在下一篇文章《上手A2A实战(下):启动服务并与你的智能体"聊聊天"》中,我们将探讨如何:
- 通过API与智能体进行交互
- 实现流式响应和多轮对话
- 调试和优化智能体性能
- 将智能体部署到生产环境
通过这两篇实战文章,你将掌握构建A2A兼容智能体的全套技能,为探索更高级的智能体协作场景打下坚实基础。