客服系统里,一个用户要改发票。编排 Agent 把任务发给账单 Agent,账单 Agent 通过 MCP 调发票系统。Demo 能跑,上线后问题集中在四件事:工具谁注册、权限谁批、审计怎么查、两个 Agent 互相调用超时怎么办。下面按这四件事拆。
MCP 和 A2A 分别解决什么
MCP 由 Anthropic 在 2024 年开源,当前常用规范版本是 2025-06-18。它把 tools、resources、prompts 暴露给模型或 Agent,走 JSON-RPC 2.0。本地常用 stdio,远程用 Streamable HTTP 或 SSE。适合接数据库、文件、SaaS API。
A2A 由 Google 在 2025 年发起,后进入 Linux Foundation。它让 Agent 通过 Agent Card 发现彼此,用 Task 管理长任务,支持流式响应和推送通知。适合跨团队、跨进程、跨厂商的 Agent 协作。
两者互补。Agent 对外协作走 A2A,对内取数走 MCP。
| 维度 | MCP | A2A |
|---|---|---|
| 定位 | Agent/LLM 与工具、数据、提示的接口 | Agent 与 Agent 的任务协作 |
| 核心对象 | tools、resources、prompts、roots、sampling、elicitation | Agent Card、Task、Message、Part、Artifact |
| 传输 | stdio、Streamable HTTP、SSE;JSON-RPC 2.0 | HTTP(S)、SSE、JSON-RPC;Agent Card |
| 状态 | 单次请求为主,远程可流式 | 长任务有状态,可查询、取消、推送 |
| 权限 | OAuth 2.1、资源指示器、scope | Agent Card 声明安全方案,OAuth2、mTLS、API Key |
| 典型坑 | 工具描述模糊、参数缺 schema、stdio 难多租户 | 信任未验证的 Agent Card、重复任务、取消语义不清 |
工具注册:先定 manifest,再谈接入
不要允许 Agent 运行时动态注册工具。生产环境走审批。
每个工具至少登记这些字段:
- tool_id:
crm.contact.search,不要用search。 - mcp_server 和版本:
crm-mcp@1.4.0。 - JSON Schema:参数、返回、错误码。
- scopes:
crm.contact.read。 - risk:low、medium、high。
- data_class:public、internal、PII、PCI。
- rate_limit:例如 20 QPS/租户。
- owner 和 oncall。
- health_endpoint。
- audit_required:true 或 false。
- 提交 manifest 和 schema。
- 安全评审 data_class 和 scopes。
- staging 跑契约测试,覆盖正常、缺参、越权、超时。
- 生产灰度 5%,看错误率和 P95。
- 异常自动下线,保留旧版本回滚。
search 会让模型在 CRM、工单、订单之间乱选。写清 crm.contact.search 和边界,才能降低误调用。
权限:别把全量 token 塞给 Agent
编排 Agent 拿用户身份,专家 Agent 拿工作负载身份,MCP 网关换短期 token。每个工具调用做一次策略判断。
策略四要素:subject、action、resource、context。可以用 OPA/Rego 或 Cedar。高风险工具,例如 invoice.reissue、refund.create,要求人工审批或二次确认。
权限点放在 MCP 网关和工具服务两层。只在编排层卡,专家 Agent 或直连 MCP 的客户端能绕过。
| 角色 | 能做什么 | 不能做什么 |
|---|---|---|
| 用户 | 发起请求 | 直接调 MCP |
| 编排 Agent | 拆任务、调 A2A | 拿长期数据库密码 |
| 专家 Agent | 处理领域任务、申请 scope | 越权访问其他租户 |
| MCP 网关 | 校验 token、脱敏、审计 | 信任客户端传的 user_id |
| 工具服务 | 最终鉴权、幂等执行 | 假设网关已经鉴权 |
审计:记到能回答“谁在什么时候让哪个 Agent 调了什么”
每次调用记录:
- trace_id、a2a.task_id、mcp.request.id
- user_id、tenant_id、agent_id、tool_id、tool_version
- 参数哈希、脱敏参数、策略版本、策略结果
- 审批人、审批单号、耗时、成本、错误码
- 模型版本、prompt 版本、工具 schema 版本
多 Agent 编排演示:改发票
场景:用户要求“上个月发票抬头写错,重开”。
A2A Agent Card 示例:
{
"name": "billing-agent",
"url": "https://billing.svc.cluster.local/a2a",
"version": "1.0.0",
"capabilities": {"streaming": true, "pushNotifications": true},
"skills": [
{"id": "invoice.reissue", "name": "重开发票", "description": "处理发票抬头、税号、金额错误导致的重开"}
],
"securitySchemes": {
"oauth2": {
"type": "oauth2",
"flows": {
"clientCredentials": {
"tokenUrl": "https://auth.svc.cluster.local/token",
"scopes": {"invoice.reissue": "重开发票"}
}
}
}
}
}
MCP 调用示例:
{"jsonrpc":"2.0","id":7,"method":"tools/call","params":{"name":"invoice.reissue","arguments":{"invoice_id":"INV-2026-0001","reason":"title_error","idempotency_key":"req-8f3a"}}}
编排伪代码:
async def handle(user_msg, ctx):
task_id = new_task_id()
with tracer.start_as_current_span('orchestrate') as span:
span.set_attribute('a2a.task.id', task_id)
span.set_attribute('user.id', ctx.user_id)
result = await a2a.send(
agent='billing-agent',
method='tasks/send',
params={
'task': {
'id': task_id,
'message': {'role': 'user', 'parts': [{'type': 'text', 'text': user_msg}]}
},
'metadata': {'trace_id': trace_id(), 'tenant_id': ctx.tenant_id}
}
)
if result['status']['state'] == 'input-required':
return ask_user(result['status']['message'])
if result['status']['state'] == 'completed':
return result['artifacts'][0]['parts'][0]['text']
return '任务未完成,已转人工'
伪代码,SDK 方法名按你选用的 a2a-python 或自研客户端调整。关键点:A2A 任务用 task_id 贯穿;MCP 写操作带 idempotency_key;高风险工具在网关拦一次,在发票系统再拦一次。
可观测:Trace 要串起 A2A 和 MCP
用 OpenTelemetry。一次用户请求一个 trace,A2A task 一个 span,MCP tools/call 一个 span。
| 指标 | 用途 | 告警线示例 |
|---|---|---|
| MCP 工具错误率 | 工具或服务故障 | 5 分钟大于 2% |
| A2A 任务失败率 | Agent 协作故障 | 5 分钟大于 3% |
| P95 端到端延迟 | 用户等待 | 大于 15s |
| 越权拦截数 | 策略或攻击 | 突增 10 倍 |
| 每任务成本 | 预算 | 大于 0.5 元/任务,按实际预算改 |
评测:分开评工具选择、参数和执行结果
只看最终答案,会漏掉工具调用错误。拆成四层:
- 工具选择准确率:该调
invoice.get却调invoice.reissue,算错。 - 参数正确率:缺
tenant_id、金额格式错。 - 任务完成率:A2A 任务到 completed。
- 安全指标:越权拦截率、敏感数据泄露数、人工审批绕过数。
安全护栏:入口、工具、出口三层
- 入口:输入过滤,越狱检测,租户隔离。
- 工具:白名单、schema 校验、scope 校验、速率限制、沙箱、网络出口限制。
- 出口:输出脱敏、引用来源、高风险操作二次确认、人工审批。
部署拓扑和代码仓库
仓库结构:
mcp-a2a-enterprise/
agents/
orchestrator/
main.py
prompts/
billing-agent/
main.py
agent-card.json
crm-agent/
main.py
agent-card.json
mcp_servers/
invoice_server.py
ticket_server.py
manifests/
invoice.reissue.json
crm.contact.search.json
policy/
rego/
mcp_authz.rego
a2a_authz.rego
audit/
schema.sql
sink.py
deploy/
docker-compose.yml
k8s/
orchestrator.yaml
mcp-gateway.yaml
otel-collector.yaml
eval/
replay_set.jsonl
run_eval.py
把这个目录推到你的 Git 服务。官方规范:MCP 2025-06-18 见 https://modelcontextprotocol.io/specification/2025-06-18 ,MCP 仓库 https://github.com/modelcontextprotocol/modelcontextprotocol ,A2A 仓库 https://github.com/a2aproject/A2A 。A2A 已进入 Linux Foundation。链接可能随项目迁移变化,以官方仓库 README 为准。
视频参考:B站、腾讯视频、优酷、抖音搜“MCP 协议”或“A2A Agent2Agent”,优先看官方账号或开发者大会回放。免责声明:第三方视频的观点和代码版本可能过时,以本文引用的官方规范为准;本文不嵌入链接,避免失效和版权问题。
避坑清单
- 把 MCP 当 A2A 用。MCP 适合工具调用,长任务协作交给 A2A。
- 信任 Agent Card。Card 是发现信息,不是授权凭证。
- 工具描述写“查询客户”。模型会乱选。写清边界。
- 只在编排层做权限。专家 Agent 可能直连 MCP。双层校验。
- 审计只记请求。策略版本、审批人、参数哈希也要记。
- 写操作没有幂等键。重试会重复开票。task_id 加 idempotency_key。
- 多 Agent 没有预算和轮次上限。循环调用烧钱。设 max_turns、max_cost、timeout。
- 流式响应无背压。SSE 堆积拖垮网关。限并发和 token 速率。
- 评测只看最终答案。工具选择错、参数错会被掩盖。
- 忽略协议版本。MCP 和 A2A 都在演进。注册中心记录版本,灰度发布。