如果你还在为AI Agent开发感到困惑,觉得多智能体协作、MCP协议、A2A架构这些概念听起来高大上但实际操作无从下手,那么这篇文章就是为你准备的。2026年已经到来,AI Agent技术正在从单兵作战向多智能体协作演进,但很多开发者仍然停留在“对话式AI”的认知层面,无法构建真正具备专业分工的智能体系统。
本文将通过一个完整的餐厅预订系统实战案例,带你从零构建一个包含菜单查询代理和预订代理的多智能体系统。你将学会如何让不同专业能力的AI Agent通过MCP协议访问工具和数据,通过A2A协议进行智能体间通信,并最终部署到生产环境。最重要的是,本文提供的代码完全兼容DeepSeek模型,让你可以用更经济的成本实现相同的功能。
1. 为什么单智能体已经不够用了?
在传统的AI应用开发中,我们通常构建一个“全能型”智能体来处理所有任务。比如一个餐厅助手,既要能查询菜单,又要能处理预订,还要回答各种咨询问题。这种架构在简单场景下还能应付,但随着业务复杂度增加,问题就暴露出来了:
单智能体的局限性:
- 功能臃肿:一个智能体需要掌握所有领域的知识,模型容易产生混淆
- 更新困难:修改预订逻辑可能影响菜单查询功能,风险集中
- 资源浪费:简单的菜单查询也要动用复杂的预订处理能力
- 扩展性差:新增功能需要重新训练或大幅调整现有智能体
多智能体的优势:
- 专业分工:每个智能体专注特定领域,表现更专业
- 独立部署:不同智能体可以有不同的更新周期和部署策略
- 资源优化:根据任务复杂度分配合适的智能体
- 易于扩展:新增功能只需添加新的专业智能体
在实际项目中,我们采用的多智能体架构是这样的:一个“餐厅礼宾代理”作为总协调员,负责理解用户意图并将任务分发给专业的“菜单查询代理”(通过MCP协议)和“预订代理”(通过A2A协议)。
2. 核心概念解析:MCP vs A2A vs 传统技能
2.1 MCP(Model Context Protocol):智能体与工具的桥梁
MCP的核心作用是让AI智能体能够安全、标准化地使用外部工具和数据源。可以把MCP理解为智能体的“手和眼睛”——它让智能体能够操作工具、获取信息。
# MCP工具示例:菜单查询工具 class MenuQueryTool: def search_by_category(self, category: str) -> List[MenuItem]: """根据分类查询菜单""" pass def search_by_description(self, description: str) -> List[MenuItem]: """语义搜索菜单项""" pass2.2 A2A(Agent-to-Agent):智能体间的协作协议
A2A协议解决了不同智能体之间如何发现彼此、如何通信、如何协作的问题。与MCP主要连接工具不同,A2A连接的是其他智能体。
关键区别:
- MCP工具:无状态,单一功能,执行完即结束
- A2A代理:有状态,具备推理能力,支持多轮对话
2.3 智能体卡片(Agent Card):智能体的“名片”
每个通过A2A协议暴露的智能体都需要一个标准化的描述文件,这就是智能体卡片。它包含智能体的功能描述、技能列表、输入输出格式等信息。
{ "agent_name": "Reservation Agent", "description": "处理餐厅预订创建、查询和取消", "skills": [ { "id": "manage_reservations", "name": "餐厅预订管理", "examples": [ "预订4人周五晚上7点的座位", "查询电话号码555-0101的预订" ] } ] }3. 环境准备与项目结构
3.1 开发环境要求
- Python版本:3.9或更高版本
- 包管理:uv(快速Python包管理器)
- AI框架:Google ADK(Agent Development Kit)
- 模型支持:Gemini系列或DeepSeek(本文兼容)
3.2 项目目录结构
adk-a2a-agent-runtime-starter/ ├── reservation_agent/ # 预订代理 │ ├── agent.py # 代理核心逻辑 │ ├── a2a_config.py # A2A配置和智能体卡片 │ └── executor.py # A2A执行器 ├── restaurant_agent/ # 餐厅总代理 │ └── agent.py # 集成了预订代理的餐厅代理 ├── tools.yaml # MCP工具箱配置 ├── scripts/ # 部署和测试脚本 └── .env # 环境配置3.3 初始环境设置
# 克隆项目代码 git clone https://github.com/alphinside/adk-a2a-agent-runtime-starter.git cd adk-a2a-agent-runtime-starter # 使用uv安装依赖(uv比pip快10倍以上) uv sync # 环境配置 cp .env.example .env # 编辑.env文件,配置项目ID和区域4. 构建专业预订代理
4.1 预订代理的核心功能设计
我们的预订代理需要处理三种核心操作:
- 创建预订:收集用户信息并创建新的预订记录
- 查询预订:根据电话号码查询现有预订
- 取消预订:取消已存在的预订
# reservation_agent/agent.py import os from google.adk.agents import LlmAgent from google.adk.tools import ToolContext # 使用应用级状态前缀,确保预订数据在所有会话间持久化 STATE_PREFIX = "app:reservation:" def create_reservation( phone_number: str, name: str, party_size: int, date: str, time: str, tool_context: ToolContext, ) -> dict: """创建新的餐厅预订""" reservation = { "name": name, "party_size": party_size, "date": date, "time": time, "status": "confirmed", } # 使用电话号码作为唯一标识符存储预订 tool_context.state[f"{STATE_PREFIX}{phone_number}"] = reservation return { "status": "confirmed", "message": f"Reservation created for {name}, party of {party_size} on {date} at {time}", } def check_reservation(phone_number: str, tool_context: ToolContext) -> dict: """根据电话号码查询预订""" reservation = tool_context.state.get(f"{STATE_PREFIX}{phone_number}") if reservation: return {"found": True, "reservation": reservation} return {"found": False, "message": f"No reservation found for {phone_number}"} def cancel_reservation(phone_number: str, tool_context: ToolContext) -> dict: """取消现有预订""" key = f"{STATE_PREFIX}{phone_number}" reservation = tool_context.state.get(key) if not reservation: return {"success": False, "message": f"No reservation found for {phone_number}"} reservation["status"] = "cancelled" tool_context.state[key] = reservation return {"success": True, "message": "Reservation cancelled"} # 创建主要的LLM代理 root_agent = LlmAgent( name="reservation_agent", model="gemini-3.5-flash", # 可替换为DeepSeek模型 instruction="""你是Foodie Finds餐厅的友好预订助手。 帮助食客创建、查询和取消餐桌预订。 创建预订时需要收集以下信息: - 预订姓名 - 电话号码(作为预订ID) - 人数 - 日期 - 时间 在创建前始终确认详细信息。 查询或取消时,如果未提供电话号码请询问。 保持简洁专业。""", tools=[create_reservation, check_reservation, cancel_reservation], )4.2 状态管理的设计考量
在AI Agent开发中,状态管理是一个关键问题。我们采用了以下几种策略:
- 会话状态:在同一对话中保持上下文
- 应用状态:跨会话持久化数据(如预订记录)
- 临时状态:单次请求的临时数据
对于预订数据,我们使用应用级状态确保即使对话结束,预订信息仍然保留。这种设计比使用数据库更轻量,适合中小型应用。
5. 配置A2A协议支持
5.1 创建智能体卡片
智能体卡片是其他智能体发现和理解我们预订代理功能的途径。
# reservation_agent/a2a_config.py from a2a.types import AgentSkill from vertexai.preview.reasoning_engines.templates.a2a import create_agent_card reservation_skill = AgentSkill( id="manage_reservations", name="餐厅预订管理", description="为Foodie Finds餐厅创建、查询和取消餐桌预订", tags=["reservations", "restaurant", "booking"], examples=[ "预订4人周五晚上7点的座位", "查询电话号码555-0101的预订", "取消我的预订,电话号码555-0101" ], input_modes=["text/plain"], output_modes=["text/plain"], ) agent_card = create_agent_card( agent_name="预订代理", description="处理餐厅餐桌预订——为Foodie Finds餐厅创建、查询和取消预订", skills=[reservation_skill], )5.2 实现A2A执行器
执行器是A2A协议与ADK代理之间的桥梁,负责处理传入的A2A请求并通过我们的代理执行。
# reservation_agent/executor.py import os import vertexai from a2a.server.agent_execution import AgentExecutor, RequestContext from google.adk.runners import Runner from google.adk.sessions import InMemorySessionService, VertexAiSessionService class ReservationAgentExecutor(AgentExecutor): """连接A2A协议和ADK预订代理的桥梁""" def __init__(self) -> None: self.agent = None self.runner = None def _init_agent(self): if self.agent is not None: return from reservation_agent.agent import root_agent as reservation_agent self.agent = reservation_agent # 根据环境选择会话服务 engine_id = os.environ.get("GOOGLE_CLOUD_AGENT_ENGINE_ID") if engine_id: # 生产环境:使用持久化会话服务 project = os.environ.get("GOOGLE_CLOUD_PROJECT") location = os.environ.get("GOOGLE_CLOUD_LOCATION", "us-central1") vertexai.init(project=project, location=location) session_service = VertexAiSessionService( project=project, location=location, agent_engine_id=engine_id ) app_name = engine_id else: # 本地开发:使用内存会话服务 session_service = InMemorySessionService() app_name = self.agent.name self.runner = Runner( app_name=app_name, agent=self.agent, session_service=session_service, # 其他服务配置... )这种设计的关键优势在于环境自适应——在本地开发时使用轻量级的内存存储,部署到生产环境时自动切换为持久化存储。
6. 本地测试与验证
6.1 完整的本地测试流程
在部署之前,我们需要确保A2A代理在本地正常工作。以下是完整的测试脚本:
# scripts/test_a2a_agent_local.py import asyncio import os from vertexai.preview.reasoning_engines import A2aAgent from reservation_agent.a2a_config import agent_card from reservation_agent.executor import ReservationAgentExecutor async def main(): # 创建本地A2A代理 a2a_agent = A2aAgent( agent_card=agent_card, agent_executor_builder=ReservationAgentExecutor ) a2a_agent.set_up() # 测试1:获取智能体卡片 print("=== 测试智能体卡片 ===") card_response = await a2a_agent.handle_authenticated_agent_card() print(f"代理名称: {card_response.get('name')}") print(f"技能列表: {[s.get('name') for s in card_response.get('skills', [])]}") # 测试2:创建预订 print("\n=== 测试创建预订 ===") message_data = { "message": { "messageId": "test-001", "content": [{"text": "预订2人周六晚上6点的座位,姓名:Bob,电话:555-0202"}], "role": "ROLE_USER", }, } response = await a2a_agent.on_message_send(**message_data) task_id = response["task"]["id"] print(f"任务ID: {task_id}") # 等待任务完成并获取结果 result = await wait_for_task_completion(a2a_agent, task_id) print(f"结果: {result}") if __name__ == "__main__": asyncio.run(main())6.2 测试结果验证
运行测试脚本后,你应该看到类似以下的输出:
=== 测试智能体卡片 === 代理名称: 预订代理 技能列表: ['餐厅预订管理'] === 测试创建预订 === 任务ID: f7f7004d-cfea-49c2-b57d-5bca9959e193 结果: 您的预订已确认:Bob,2人,周六晚上6点,电话555-0202这个测试验证了:
- A2A代理能够正确暴露其功能描述
- 代理能够处理预订请求并返回正确结果
- 整个A2A协议流程正常工作
7. 部署到Agent运行时环境
7.1 部署脚本实现
将代理部署到生产环境需要处理依赖管理、环境配置和部署流程。
# scripts/deploy_a2a_agent_runtime.py import os from pathlib import Path import vertexai from vertexai.preview.reasoning_engines import A2aAgent from reservation_agent.a2a_config import agent_card from reservation_agent.executor import ReservationAgentExecutor def deploy_reservation_agent(): """部署预订代理到Agent运行时""" # 环境配置 project_id = os.environ["GOOGLE_CLOUD_PROJECT"] region = os.environ["REGION"] staging_bucket = os.environ.get("STAGING_BUCKET") vertexai.init(project=project_id, location=region, staging_bucket=staging_bucket) # 创建A2A代理实例 a2a_agent = A2aAgent( agent_card=agent_card, agent_executor_builder=ReservationAgentExecutor, ) print("开始部署预订代理到Agent运行时...") print("预计需要3-5分钟...") # 执行部署 client = vertexai.Client(project=project_id, location=region) remote_agent = client.agent_engines.create( agent=a2a_agent, config={ "display_name": agent_card.name, "description": agent_card.description, "requirements": [ "google-cloud-aiplatform[agent_engines,adk]==1.149.0", "a2a-sdk==0.3.26", "google-adk==1.29.0", ], "extra_packages": ["./reservation_agent"], }, ) print(f"部署完成!资源名称: {remote_agent.api_resource.name}") return remote_agent.api_resource.name7.2 部署后的验证
部署完成后,我们需要验证代理在生产环境的正常运行:
# scripts/test_deployed_agent.py import asyncio import vertexai from dotenv import load_dotenv load_dotenv() async def test_deployed_agent(): """测试已部署的代理""" project_id = os.environ["GOOGLE_CLOUD_PROJECT"] region = os.environ["REGION"] resource_name = os.environ["RESERVATION_AGENT_RESOURCE_NAME"] vertexai.init(project=project_id, location=region) client = vertexai.Client(project=project_id, location=region) # 获取已部署的代理 agent = client.agent_engines.get(name=resource_name) # 测试智能体卡片 card = await agent.handle_authenticated_agent_card() print(f"已部署代理: {card.name}") print(f"访问URL: {card.url}") # 测试预订功能 response = await agent.on_message_send( messageId="prod-test-001", role="user", parts=[{"kind": "text", "text": "预订3人周日下午12点的座位"}] ) print("生产环境测试通过!") if __name__ == "__main__": asyncio.run(test_deployed_agent())8. 集成多智能体系统
8.1 升级餐厅主代理
现在我们需要将预订代理集成到餐厅主代理中,实现真正的多智能体协作。
# restaurant_agent/agent.py import os import httpx from google.adk.agents import LlmAgent from google.adk.agents.remote_a2a_agent import RemoteA2aAgent from google.auth import default from toolbox_adk import ToolboxToolset class GoogleCloudAuth(httpx.Auth): """Google Cloud身份验证处理器""" def __init__(self): self.credentials, _ = default( scopes=["https://www.googleapis.com/auth/cloud-platform"] ) def auth_flow(self, request): if not self.credentials.valid: self.credentials.refresh(httpx.Request("POST", "https://oauth2.googleapis.com/token")) request.headers["Authorization"] = f"Bearer {self.credentials.token}" yield request # 配置工具和代理 TOOLBOX_URL = os.environ.get("TOOLBOX_URL", "http://127.0.0.1:5000") RESERVATION_AGENT_CARD_URL = os.environ.get("RESERVATION_AGENT_CARD_URL", "") toolbox = ToolboxToolset(TOOLBOX_URL) # 创建远程A2A代理实例 reservation_remote_agent = RemoteA2aAgent( name="reservation_agent", description="处理餐厅餐桌预订——创建、查询和取消预订", agent_card=RESERVATION_AGENT_CARD_URL, httpx_client=httpx.AsyncClient(auth=GoogleCloudAuth(), timeout=60), ) # 主代理:协调菜单查询和预订功能 root_agent = LlmAgent( name="restaurant_agent", model="gemini-3.5-flash", instruction="""你是Foodie Finds餐厅的知识渊博的礼宾员。 你的工作: - 帮助食客按分类或菜系浏览菜单 - 提供菜品的完整详细信息,包括成分、价格和饮食信息 - 根据食客渴望的描述推荐菜品 - 当用户想要预订、查询或取消餐桌时,委托给reservation_agent 当食客按名称或菜系询问特定菜品时,使用get-item-details工具。 当食客要求特定分类或菜系类型时,使用search-menu工具。 当食客描述他们想要的食物类型时,使用search-menu-by-description工具进行语义搜索。 对于预订请求(预订、查询或取消餐桌),委托给reservation_agent。 保持对话性、知识渊博且简洁。""", tools=[toolbox], sub_agents=[reservation_remote_agent], )8.2 多智能体协作流程
这个集成实现了以下协作流程:
- 用户请求分析:主代理首先分析用户意图
- 任务路由:如果是菜单相关请求,路由到MCP工具箱;如果是预订相关请求,路由到A2A预订代理
- 结果整合:主代理将子代理的结果整合后返回给用户
9. 完整系统测试与验证
9.1 端到端测试场景
我们需要测试整个多智能体系统的各种使用场景:
# scripts/test_full_system.py import asyncio import requests async def test_full_system(): """测试完整的多智能体系统""" agent_url = os.environ.get("AGENT_URL", "http://localhost:8080") test_scenarios = [ { "name": "菜单查询测试", "message": "你们有哪些意大利菜?", "expected_keywords": ["pasta", "pizza", "意大利"] }, { "name": "预订创建测试", "message": "我想预订周五晚上7点4个人的座位,姓名Eve,电话555-0505", "expected_keywords": ["确认", "预订", "Eve"] }, { "name": "预订查询测试", "message": "查询电话555-0505的预订", "expected_keywords": ["预订", "Eve", "周五"] } ] for scenario in test_scenarios: print(f"\n=== {scenario['name']} ===") # 发送请求到代理 response = requests.post( f"{agent_url}/api/chat", json={"message": scenario["message"]} ) if response.status_code == 200: result = response.json() print(f"响应: {result['response']}") # 验证响应包含预期关键词 for keyword in scenario["expected_keywords"]: if keyword in result['response']: print(f"✓ 包含预期关键词: {keyword}") else: print(f"✗ 缺少预期关键词: {keyword}") else: print(f"请求失败: {response.status_code}")9.2 性能与稳定性考量
在生产环境中,我们还需要考虑:
- 错误处理:网络超时、代理不可用等情况
- 重试机制:临时故障的自动恢复
- 限流控制:防止单个用户过度使用资源
- 监控告警:实时监控系统健康状态
10. 生产环境最佳实践
10.1 安全配置
# 生产环境安全配置示例 security: # API密钥管理 api_keys: rotation_period: 90 days emergency_rotation: enabled # 访问控制 access_control: ip_whitelist: ["10.0.0.0/8"] rate_limiting: 100 requests/minute # 数据保护 data_protection: encryption: enabled retention_period: 30 days10.2 监控与日志
建立完整的可观测性体系:
# 监控配置示例 from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider # 设置分布式追踪 tracer_provider = TracerProvider() trace.set_tracer_provider(tracer_provider) # 关键指标监控 monitoring_metrics = [ "agent_response_time", "a2a_request_success_rate", "concurrent_users", "error_rate_by_agent" ]10.3 成本优化策略
特别是使用DeepSeek等成本较低的模型时:
- 缓存策略:对常见查询结果进行缓存
- 请求批处理:合并多个小请求
- 模型选择:根据任务复杂度选择合适的模型规格
- 自动扩缩:根据负载动态调整资源
11. 常见问题与解决方案
11.1 部署问题排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 部署超时 | 网络问题或依赖下载慢 | 检查网络连接,使用国内镜像源 |
| 依赖冲突 | 版本不兼容 | 使用uv管理依赖,确保版本一致 |
| 权限错误 | 服务账号权限不足 | 配置正确的IAM角色 |
11.2 运行时问题
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| A2A调用失败 | 身份验证令牌过期 | 实现自动令牌刷新机制 |
| 响应缓慢 | 模型推理时间过长 | 优化提示词,启用流式响应 |
| 状态丢失 | 会话配置错误 | 检查会话服务配置 |
11.3 模型兼容性问题
由于我们设计时考虑了多模型兼容性,从Gemini切换到DeepSeek只需要修改配置:
# 修改模型配置 # 从Gemini切换到DeepSeek model_config = { "gemini": "gemini-3.5-flash", "deepseek": "deepseek-chat" # 根据实际模型名称调整 } # 在agent初始化时选择模型 selected_model = model_config[os.environ.get("MODEL_PROVIDER", "deepseek")]12. 扩展与进阶方向
12.1 添加新的专业智能体
基于这个架构,你可以轻松添加新的智能体:
- 支付处理代理:处理订单支付和退款
- 推荐代理:基于用户历史提供个性化推荐
- 客服代理:处理投诉和复杂咨询
12.2 性能优化建议
- 异步处理:对耗时操作使用异步模式
- 连接池:重用数据库和API连接
- 预加载:提前加载常用数据到内存
- 压缩传输:对大量数据使用压缩算法
12.3 企业级特性
对于大型企业应用,可以考虑:
- 多租户支持:隔离不同客户的数据和配置
- 审计日志:记录所有操作用于合规审查
- 备份恢复:定期备份智能体状态和配置
- 蓝绿部署:实现零停机更新
通过本文的实战指南,你应该已经掌握了构建生产级多智能体系统的核心技能。从单智能体到多智能体协作的转变,不仅仅是技术架构的升级,更是开发思维的转变。这种架构为构建复杂、可扩展的AI应用提供了坚实的基础。
记住,最好的学习方式是实践。建议你按照本文的步骤亲手实现这个系统,然后在基础上进行扩展和优化。随着经验的积累,你将能够设计出更加复杂和强大的多智能体解决方案。