人工智能智能体开发领域日益扩展,充斥着各种缩写:MCP、A2A、UCP、AP2、A2UI 和 AG-UI,仅举几例。如果你曾看着这份协议列表,感觉自己面对着一堵竞争标准之墙,你并不孤单。为了帮助你理解它们的价值,我们将演示每种协议的作用,让你免于为智能体所接触的每一个工具、API 和前端组件编写和维护自定义集成代码。
我们将通过使用智能体开发工具包(ADK)为一家餐厅构建一个多步骤供应链智能体,将这些协议付诸实践。这个场景非常适合作为测试案例,因为订购批发食材需要检查库存数据库、与远程供应商智能体通信、执行安全交易以及渲染交互式仪表板。
我们将从一个会凭空产生模型幻觉的裸大语言模型开始,然后逐一添加协议,直到它能够检查真实库存、获取专家报价、下订单、授权付款,并渲染交互式、流式传输的仪表板。
1. 模型上下文协议(MCP)
让我们看看构建智能体时遇到的第一个障碍:将其连接到你的系统和数据。如果你的厨房管理智能体需要检查库存或给供应商发邮件,你通常必须为该特定 API 编写自定义集成代码。如果一个服务有十几个端点,你就需要为该服务编写和维护十几个自定义工具。
模型上下文协议(MCP)通过为数百个服务器提供单一的标准连接模式,消除了这种繁琐工作。服务器公布其工具,你的智能体自动发现它们。并且,由于 MCP 服务器由构建这些系统的团队维护,你的智能体始终能获得最新的工具定义,而你无需编写或更新任何集成代码。
ADK 通过 McpToolset 为此提供了一流支持。我们的厨房管理智能体现在无需从头编写大量 API 请求,而是可以使用数据库 MCP 工具箱从真实的 PostgreSQL 数据库中读取数据,通过 Notion MCP 查找食谱,并使用 Mailgun MCP 通过电子邮件联系供应商采取行动。
from google.adk.agents import Agent
from google.adk.tools.mcp_tool import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams
from google.adk.tools.toolbox_toolset import ToolboxToolset
from mcp import StdioServerParameters
# 1. Inventory database - MCP Toolbox for Databases (PostgreSQL, SQLite, BigQuery, etc.)
inventory_tools = ToolboxToolset(server_url=TOOLBOX_URL)
# 2. Kitchen SOPs and recipes - Notion MCP (read menus, ingredient lists, supplier contacts)
notion_tools = McpToolset(connection_params=StdioConnectionParams(
server_params=StdioServerParameters(
command="npx", args=["-y", "@notionhq/notion-mcp-server"],
env={"NOTION_TOKEN": NOTION_TOKEN}),
timeout=30))
# 3. Email suppliers about orders - Mailgun MCP (send confirmations, track delivery)
mailgun_tools = McpToolset(connection_params=StdioConnectionParams(
server_params=StdioServerParameters(
command="npx", args=["-y", "@mailgun/mcp-server"],
env={"MAILGUN_API_KEY": MAILGUN_API_KEY}),
timeout=30))
kitchen_agent = Agent(
model="gemini-3-flash-preview",
name="kitchen_manager",
instruction="You manage a restaurant kitchen. Check inventory, look up recipes, email suppliers.",
tools=[inventory_tools, notion_tools, mailgun_tools],
) 您可以浏览 ADK 中 MCP 集成的完整生态系统,查看有哪些可用的集成。
2. 智能体间协议(A2A)
在 MCP 处理数据访问之后,下一个挑战是专业知识。您的厨房管理员可以检查库存,但它不知道今天的批发价格、供应商质量等级或配送时间窗口。这些信息存在于不同的远程智能体中,这些智能体可能由不同团队构建、基于不同框架、运行在不同服务器上。在某些情况下,原始数据可能永远不会通过 API 暴露,但可以通过智能体接口暴露。如果没有标准协议,您就必须为每个远程智能体编写和维护自定义集成代码,并且每次远程智能体发生变化时都需要重新部署。
智能体间协议(A2A)标准化了智能体之间发现和通信的方式。每个 A2A 智能体在一个众所周知的 URL(`/.well-known/agent-card.json`)上发布一张智能体卡片,描述其名称、能力和端点。完整规范请参阅 A2A 协议文档。
我们的厨房管理员智能体会获取这些卡片,以了解每个远程智能体的功能,然后在运行时将查询路由到正确的智能体。添加一个新的远程智能体只需添加一个新的 URL,无需手动修改代码或重新部署。
ADK 的 `RemoteA2aAgent` 每次轮询路由到一个远程智能体。当查询涉及多个远程智能体时,例如同时检查价格、质量和配送信息,您可以直接使用 `a2a-sdk`,这也是我们在此处采用的方法。
# An A2A agent serves an Agent Card at /.well-known/agent-card.json:
# {
# "name": "pricing_agent",
# "description": "Checks today's wholesale market prices for food items.",
# "skills": [{"id": "pricing", "name": "Price Check",
# "description": "Check current wholesale market prices"}],
# "url": "http://pricing-agent:8001/",
# "version": "1.0.0"
# }
# EXPOSE: Turn any ADK agent into an A2A service
from google.adk.a2a.utils.agent_to_a2a import to_a2a
app = to_a2a(pricing_agent, port=8001)
# DISCOVER: Resolve the Agent Card and create a client - just a URL
from a2a.client.client_factory import ClientFactory
client = await ClientFactory.connect("http://pricing-agent:8001")
card = await client.get_card()
print(f"{card.name} - {card.description}")
# -> "pricing_agent - Checks today's wholesale market prices for food items."
# CALL: Send a message via the A2A protocol
from a2a.client.helpers import create_text_message_object
msg = create_text_message_object(content="What's today's wholesale price for salmon?")
async for response in client.send_message(msg):
... # response is a Task (with artifacts) or a direct Message 尝试 A2A 示例,查看实际的发现和通信模式。
3. 通用商务协议(UCP)
您的智能体现在可以发现供应商并获取报价。但当需要实际下单时,每个供应商都有不同的 API。如果您的智能体需要从五家批发分销商采购原料,您就需要集成五种不同的结账流程。
通用商务协议(UCP)通过强类型的请求与响应模式,将购物生命周期标准化为模块化能力,这些模式在任何底层传输协议上保持一致。你的智能体无需为每个供应商构建定制集成,而是通过统一模式与之交互。无论连接是通过 REST、模型上下文协议(MCP)、智能体间协议(A2A)还是用于浏览器端流程的嵌入式协议(EP)建立,这一点都同样适用。
我们的厨房管理智能体能够使用与 A2A 中相同的知名 URL 模式(`/.well-known/ucp`)发现供应商的商品目录,然后构建一个类型化的结账请求并完成订单。由于 UCP 也支持标准 REST API,因此它可以与你项目已使用的任何 HTTP 客户端配合工作,无需专有 SDK。
import httpx, uuid
from ucp_sdk.models.discovery.profile_schema import UcpDiscoveryProfile
from ucp_sdk.models.schemas.shopping.checkout_create_req import CheckoutCreateRequest
from ucp_sdk.models.schemas.shopping.types.line_item_create_req import LineItemCreateRequest
from ucp_sdk.models.schemas.shopping.types.item_create_req import ItemCreateRequest
from ucp_sdk.models.schemas.shopping.payment_create_req import PaymentCreateRequest
# DISCOVER: Parse the supplier's UCP profile
async with httpx.AsyncClient() as c:
profile = UcpDiscoveryProfile.model_validate(
(await c.get("http://example-wholesale:8182/.well-known/ucp")).json())
# ORDER: Build a typed checkout request
checkout_req = CheckoutCreateRequest(
currency="USD",
line_items=[
LineItemCreateRequest(quantity=10, item=ItemCreateRequest(id="salmon")),
LineItemCreateRequest(quantity=3, item=ItemCreateRequest(id="olive_oil")),
],
payment=PaymentCreateRequest(),
)
# SEND: Create checkout + complete (with required UCP headers)
# UCP-Agent header should point to your agent's capability profile
headers = {"UCP-Agent": 'profile="https://kitchen.example/agent"',
"Idempotency-Key": str(uuid.uuid4()), "Request-Id": str(uuid.uuid4())}
async with httpx.AsyncClient() as c:
checkout = (await c.post("http://example-wholesale:8182/checkout-sessions",
json=checkout_req.model_dump(mode="json", by_alias=True, exclude_none=True),
headers=headers)).json()
headers["Idempotency-Key"] = str(uuid.uuid4()) # New Idempotency-Key per operation
order = (await c.post(
f"http://example-wholesale:8182/checkout-sessions/{checkout['id']}/complete",
headers=headers)).json() UCP 示例代码库包含一个基于 ADK 构建的 AI 购物助手,它将 UCP 与 A2A 相结合,实现端到端的购物工作流。
4. 智能体支付协议(AP2)
在上一节中,我们的厨房管理智能体获得了向供应商下单的能力。但谁授权了这笔支出?没有记录显示设置了哪些限额、哪些商家获得批准,或者授权何时到期。
智能体支付协议(AP2)通过类型化的授权指令(mandates)补充了这一缺失的层级,这些指令提供不可否认的意图证明,并对每笔交易强制执行可配置的防护措施。UCP 处理你订购什么以及向谁订购,而 AP2 则处理谁批准了购买并提供审计追踪。两者协同工作:AP2 作为扩展接入 UCP,在结账流程中增加加密授权证明。
与不受控制的交易不同,你可以为智能体配置需要遵循的防护措施。你定义一个 IntentMandate(意图授权指令)来指定允许的商家,并设置自动批准的消费限额。然后智能体会生成一个绑定到特定购物车和金额的 PaymentMandate(支付授权指令)。如果订单超出限额,该授权指令将保持未签名状态,直到管理人员明确批准。PaymentReceipt(支付收据)则完成审计追踪的闭环。
以下代码片段使用了官方仓库中的真实 AP2 类型,展示了从意图、经过签名授权到收据的完整授权流程。
from ap2.types.mandate import IntentMandate, PaymentMandate, PaymentMandateContents
from ap2.types.payment_request import PaymentCurrencyAmount, PaymentItem, PaymentResponse
from ap2.types.payment_receipt import PaymentReceipt, Success
# The restaurant owner configures guardrails
intent = IntentMandate(
natural_language_description="10 lbs salmon, 3 bottles olive oil",
merchants=["Example Wholesale"], # ONLY these suppliers
requires_refundability=True, # must be refundable
user_cart_confirmation_required=False, # auto-approve under limit
intent_expiry="2026-02-23T20:00:00Z", # expires in 1 hour
)
# Agent creates a PaymentMandate binding payment to the intent
mandate = PaymentMandate(payment_mandate_contents=PaymentMandateContents(
payment_mandate_id="abc123",
payment_details_id="order-001",
payment_details_total=PaymentItem(
label="10 lbs salmon + 3 bottles olive oil",
amount=PaymentCurrencyAmount(currency="USD", value=294.00)),
payment_response=PaymentResponse(request_id="order-001", method_name="CARD"),
merchant_agent="Example Wholesale",
))
# Manager signs (simulated - real AP2 uses JWT/biometric on secure device)
mandate.user_authorization = "signed_hash_abc123"
# PaymentReceipt closes the audit trail
receipt = PaymentReceipt(
payment_mandate_id="abc123", payment_id="PAY-001",
amount=PaymentCurrencyAmount(currency="USD", value=294.00),
payment_status=Success(merchant_confirmation_id="ORD-A1B2C3"),
)
# IntentMandate -> PaymentMandate (signed) -> PaymentReceipt
# Full audit trail: what was intended, authorized, and paid AP2 目前为 v0.1 版本,其类型以独立包的形式提供,并未内置于 ADK 核心中。欢迎在 AP2 仓库中探索该协议及参考实现。
5. 智能体与用户界面协议(A2UI)
至此,我们的厨房管理员可以检查库存、获取报价、下单并授权付款。但所有结果都以纯文本形式返回,而有时文本是不够的。当你的智能体需要展示库存仪表盘、订单表单或供应商对比时,通常需要为每个需求单独构建一个前端组件。每一个新的界面需求都意味着需要编写和维护更多的前端代码。
智能体与用户界面协议(A2UI)通过让智能体从一个固定组件目录中动态组合新颖布局来解决此问题。它使用一种声明式 JSON 格式,仅由 18 种安全的组件原语构成,例如行、列和文本字段。
A2UI 将界面结构与底层数据分离。智能体发送一个扁平的组件列表,各组件通过 ID 相互引用,随后附带一个独立的数据负载。客户端上的渲染器使用 Lit、Flutter 或 Angular 等框架将此 JSON 转换为原生界面。
# This is what the agent sends. A renderer (Lit, Flutter, Angular) turns it into native UI.
a2ui_messages = [
# 1. Create a rendering surface
{"beginRendering": {"surfaceId": "default", "root": "card"}},
# 2. Send the component tree (flat list, ID references - not nested)
{"surfaceUpdate": {"surfaceId": "default", "components": [
{"id": "card", "component": {"Card": {"child": "col"}}},
{"id": "col", "component": {"Column": {"children": {"explicitList": ["title", "price", "buy"]}}}},
{"id": "title", "component": {"Text": {"usageHint": "h3", "text": {"path": "name"}}}},
{"id": "price", "component": {"Text": {"text": {"path": "price"}}}},
{"id": "buy", "component": {"Button": {"child": "btn-label", "action": {"name": "purchase",
"context": [{"key": "item", "value": {"path": "name"}}]}}}},
{"id": "btn-label", "component": {"Text": {"text": {"literalString": "Buy Now"}}}},
]}},
# 3. Send the data (separate from structure - update data without resending components)
{"dataModelUpdate": {"surfaceId": "default", "contents": [
{"key": "name", "valueString": "Fresh Atlantic Salmon"},
{"key": "price", "valueString": "$24.00/lb"},
]}},
] 现在,智能体可以根据请求,使用相同的 18 种原语组合出完全不同的界面。以下示例中,对同一个智能体的三个提示词分别生成了一个库存清单、一个订单表单和一个供应商对比,所有内容均由 CheckBox、TextField、DateTimeInput 和 Card 等组件构建,无需额外的前端代码。
在开发过程中,ADK 的 Web 界面(adk web)可以原生渲染 A2UI 组件,因此你无需构建自定义渲染器即可测试智能体的界面输出。
欢迎探索 A2UI 示例以获取更多组件模式,或尝试使用 A2UI Widget Builder 以交互方式组合布局。
6. 智能体与用户交互协议(AG-UI)
传统的 REST API 会返回一个响应,然后任务就结束了。智能体则不同。它们会增量式地流式输出文本,在响应过程中调用工具,有时还会暂停以等待人工输入。这使得将智能体连接到前端比标准的 API 调用更为复杂。
你可以自己处理这个问题。ADK 提供了一个原生的 `/run_sse` 端点,可以直接流式传输事件,并且只需几十行前端代码就能解析流并渲染工具调用。但这些解析代码是样板代码,而且每当事件格式发生变化时,它就会失效。
智能体-用户交互协议(AG-UI)消除了这些样板代码。它充当了一个中间件,将原始的框架事件转换为标准化的 SSE 流。你的前端监听诸如 `TEXT_MESSAGE_CONTENT` 或 `TOOL_CALL_START` 这类类型化事件,而无需关心是哪个智能体框架产生了它们。
要将我们的厨房管理智能体变成一个 AG-UI 流式端点,我们使用 `ag_ui_adk` 包对其进行封装,并将其挂载到一个 FastAPI 应用上:
from ag_ui_adk import ADKAgent, add_adk_fastapi_endpoint
from fastapi import FastAPI
# Wrap the agent, create the app, mount the endpoint
ag_ui_agent = ADKAgent(adk_agent=kitchen_mgr, app_name="kitchen", user_id="chef")
app = FastAPI()
add_adk_fastapi_endpoint(app, ag_ui_agent, path="/")
# Run with: uvicorn module:app
# The SSE stream emits typed events:
# RUN_STARTED
# TOOL_CALL_START toolCallName="check_inventory"
# TOOL_CALL_RESULT content="3 lbs in stock, REORDER NEEDED"
# TOOL_CALL_END
# TEXT_MESSAGE_CONTENT delta="Based on "
# TEXT_MESSAGE_CONTENT delta="current inventory..."
# RUN_FINISHED 探索 AG-UI 示例,查看更多实际应用中的流式传输模式。
整合所有功能:智能体在行动
在集成了所有六种协议之后,我们最初那个简陋的大语言模型已经变成了一个相当强大的智能体,它可以检查真实库存、发现供应商、下订单、授权付款,并流式传输交互式仪表盘。以下是当用户发送一个调用智能体全部功能的请求时会发生的情况:
“检查我们的三文鱼库存,获取今天的批发价和品质等级,如果库存不足,就从 Example Wholesale 订购 10 磅并授权付款。”
智能体使用不同的协议处理请求的每个阶段:
第一阶段:收集信息
- 首先,检查库存情况。MCP 查询库存数据库中的三文鱼信息(`check_inventory`)。
- 库存不足。当前行情价是多少?A2A 查询远程的定价和品质智能体(`ask_agent`)。
第二阶段:完成交易
- 价格看起来合适,下单。UCP 向 Example Wholesale 发送结账请求(`place_order`)。
- 但谁来批准这笔订单?AP2 在配置好的护栏范围内,通过支付授权指令来保障订单安全(`authorize_payment`)。
第三阶段:呈现结果
- 现在向用户展示发生了什么。A2UI 根据结果组合出交互式组件。
- 将所有内容实时流式传输到前端。AG-UI 实时传递工具调用和文本响应。
六种协议,各自解决不同的问题,全部通过一个智能体协同工作。
使用这些协议的技巧
了解每种协议解决的问题:MCP 将智能体连接到工具和数据。A2A 将智能体连接到其他智能体。UCP 标准化商业流程。AP2 处理支付授权。A2UI 定义要渲染的内容。AG-UI 定义如何流式传输。理解这些边界能让你的架构保持清晰。
按需添加协议:你不需要在第一天就把所有六种协议都集成到你的智能体中。大多数智能体从 MCP 开始,用于数据访问。随着你的需求增长(多智能体通信、商业、支付、丰富 UI、流式传输),引入能解决特定问题的协议。
不要从零开始:在使用某个协议进行构建之前,先检查是否有 ADK 集成、官方 SDK 和示例代码。这些协议发展很快,官方工具处理了你不想自己重新实现的细节。
尽早采用标准:这些协议仍在成熟过程中,但它们建立的模式(通过知名 URL 进行发现、类型化的请求/响应模式、标准事件流)能让你的智能体与日益增长的工具、服务和其他智能体生态系统兼容。
现在就开始
本文中的所有代码示例都使用了 ADK。设置你的第一个智能体,将其连接到 MCP 服务器,然后从那里开始添加协议。浏览 ADK 集成,查看哪些工具和服务已经可用。本指南中提供了指向每种协议文档和示例的链接。
我们迫不及待地想看到你的成果。
- AI
- 云
- 公告
- 最佳实践
- 探索
- 影响力
- 学习