企业多智能体协作的工程边界:MCP 工具接入与 A2A 任务编排实践

简介: 本文探讨多智能体系统可靠协作的关键——通过MCP(代理到能力)规范工具调用,A2A(代理到代理)接口统一任务契约,解决参数混乱、重复执行、状态不可知等工程痛点,推动智能体从Demo走向可运维的生产系统。(239字)

单个大模型应用通常只需要处理一条请求链路:接收输入、调用模型、返回结果。当系统进一步拆分为规划代理、检索代理、执行代理和审核代理时,问题就从“模型能不能回答”变成了“多个代理能不能可靠地协作”。

常见故障包括:工具参数没有统一格式,代理之间传递了无法解析的自然语言;执行代理重复提交订单或重复发送通知;一个代理失败后,上游无法判断任务是否已经执行;模型供应商更换后,调用代码、重试策略和审计字段全部散落在业务逻辑中。

MCP 和 A2A 可以分别解决两个方向的问题:MCP 更适合描述代理如何发现并调用工具、资源和提示模板;A2A 风格的协作接口更适合描述代理之间如何提交任务、查询状态和交换结果。它们不是完整的业务系统,也不能替代身份认证、权限管理、消息队列和审计平台。工程落地时,必须把协议层放在明确的边界内。

本文选择这一方向,是因为当前智能体开发正在从单轮问答转向工具调用和多代理分工。下面以“客服工单处理”为例,构建一个最小但可扩展的协作流程:分类代理判断工单类型,知识代理提供参考,执行代理创建内部任务,审核节点决定是否允许高风险操作。

两类协议的职责

MCP:代理到能力

可以把 MCP 看成一个能力适配层。服务端向客户端暴露工具、资源或提示模板,客户端根据定义调用它们。一个工具至少需要具备名称、用途说明和参数模式。参数模式最好采用 JSON Schema 或等价的结构化描述,以便在调用前进行校验。

MCP 的关键价值不是“让模型自动执行一切”,而是把外部能力从提示词中分离出来。例如,查询工单、读取知识库和创建待办任务都应当是独立工具。每个工具可以拥有不同的权限、超时和审计策略,模型只能选择已经被授予的能力。

A2A 风格接口:代理到代理

代理之间的协作应当像调用一个远程服务,而不是把一段自然语言直接塞进另一个代理的上下文。一个可执行的任务消息通常需要包含:任务标识、发起方、目标代理、输入数据、幂等键、截止时间和当前状态。

任务状态建议至少区分 submittedrunningsucceededfailedcancelled。状态变化应当由服务端记录,而不是由模型自行声称“已经完成”。对于长任务,调用方应先获得任务编号,再通过查询接口或事件订阅获取结果。

两者结合后的边界可以概括为:编排器通过代理协作接口分派任务,代理内部通过 MCP 调用具体能力。这样,代理协作协议负责任务生命周期,工具协议负责能力执行,业务系统负责最终一致性和权限约束。

先定义任务契约

不要从提示词开始,而应先定义任务输入和输出。下面是一个简化的工单分类任务契约:

{
   
  "task_id": "task-20260809-0001",
  "task_type": "ticket.classify",
  "source_agent": "orchestrator",
  "target_agent": "classifier",
  "idempotency_key": "ticket-7842-classify-v1",
  "deadline": "2026-08-09T12:00:00Z",
  "input": {
   
    "ticket_id": "7842",
    "subject": "无法登录管理后台",
    "content": "昨天开始持续返回 403"
  }
}

输出也要结构化,并明确置信度和需要人工介入的条件:

{
   
  "task_id": "task-20260809-0001",
  "status": "succeeded",
  "result": {
   
    "category": "access_control",
    "priority": "high",
    "confidence": 0.86,
    "requires_human_review": true,
    "reason_codes": ["permission_denied", "admin_scope"]
  },
  "usage": {
   
    "model": "provider-model-id",
    "request_id": "req-example"
  }
}

这里的模型名称只是协议字段示例,不代表任何服务的固定名称。生产系统应把模型标识、请求编号和提示版本写入审计记录,但不要把模型输出当成权限判定的唯一依据。

实现一个可恢复的编排器

下面使用 Python 标准库演示一个任务提交客户端。示例只负责提交和轮询,不假定某个供应商的具体接口;实际使用时应依据目标代理的公开文档调整路径、认证头和响应字段。

import os
import time
import uuid
import requests

AGENT_URL = os.environ["CLASSIFIER_AGENT_URL"]
AGENT_TOKEN = os.environ["CLASSIFIER_AGENT_TOKEN"]


def submit_task(ticket_id: str, subject: str, content: str) -> str:
    task_id = f"task-{uuid.uuid4()}"
    payload = {
   
        "task_id": task_id,
        "task_type": "ticket.classify",
        "source_agent": "orchestrator",
        "target_agent": "classifier",
        "idempotency_key": f"{ticket_id}-classify-v1",
        "input": {
   
            "ticket_id": ticket_id,
            "subject": subject,
            "content": content,
        },
    }
    response = requests.post(
        f"{AGENT_URL}/tasks",
        json=payload,
        headers={
   "Authorization": f"Bearer {AGENT_TOKEN}"},
        timeout=10,
    )
    response.raise_for_status()
    return response.json()["task_id"]


def wait_for_result(task_id: str, max_wait: int = 60) -> dict:
    end_at = time.monotonic() + max_wait
    while time.monotonic() < end_at:
        response = requests.get(
            f"{AGENT_URL}/tasks/{task_id}",
            headers={
   "Authorization": f"Bearer {AGENT_TOKEN}"},
            timeout=10,
        )
        response.raise_for_status()
        data = response.json()
        if data.get("status") in {
   "succeeded", "failed", "cancelled"}:
            return data
        time.sleep(2)
    raise TimeoutError(f"task {task_id} did not finish before deadline")

这段代码仍然需要补充三项生产能力:持久化任务状态、处理网络重试,以及在超时后进入补偿流程。轮询只是最容易理解的实现;如果基础设施支持消息队列或事件回调,应让状态事件成为主要通知方式,同时保留查询接口作为兜底。

在代理内部接入工具

工具服务器应把每个动作拆开,并在服务端再次校验参数。例如,查询工单可以是只读工具,创建内部任务则是写操作。写操作应当要求业务服务验证操作者身份、租户归属、资源状态和幂等键。

一个工具定义可以采用如下形式:

{
   
  "name": "create_internal_task",
  "description": "为指定工单创建一个内部跟进任务",
  "inputSchema": {
   
    "type": "object",
    "required": ["ticket_id", "owner", "summary", "idempotency_key"],
    "properties": {
   
      "ticket_id": {
   "type": "string"},
      "owner": {
   "type": "string"},
      "summary": {
   "type": "string", "maxLength": 500},
      "idempotency_key": {
   "type": "string"}
    },
    "additionalProperties": false
  }
}

模型可以提出工具调用,但不能绕过工具服务器的校验。对于删除数据、修改权限、发起付款等高风险动作,建议增加人工审批或双人确认。审批结果应写入任务状态,不能仅放在对话上下文中。

如果代理需要调用模型 API,应将模型客户端封装在独立适配层中,并通过环境变量读取密钥。例如,在目标服务文档明确声明兼容相应接口格式的前提下,可以将 MODEL_BASE_URL 指向企业允许使用的模型接入服务;HaerAPI 可作为需要评估的模型 API 接入选项之一,具体兼容范围和数据处理方式应以其当前文档为准。

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["MODEL_API_KEY"],
    base_url=os.environ["MODEL_BASE_URL"],
)

response = client.chat.completions.create(
    model=os.environ["MODEL_NAME"],
    messages=[
        {
   "role": "system", "content": "只输出符合约定 JSON Schema 的分类结果。"},
        {
   "role": "user", "content": "请分类这条工单:无法登录管理后台,持续返回 403"},
    ],
    temperature=0,
)
print(response.choices[0].message.content)

可靠性与安全控制

幂等

所有有副作用的工具调用都应携带幂等键。服务端在数据库中建立唯一约束,首次请求创建业务记录,重复请求返回原结果。不能只依靠模型“记住自己已经调用过”。

超时与重试

连接超时、读取超时、业务失败和未知状态应分别处理。对于未知状态,直接重试写操作可能造成重复执行,正确做法是先用幂等键查询;只有确认请求未被接受时,才允许重新提交。重试次数、退避时间和最终失败状态都应可配置并可观测。

权限

代理身份、用户身份和工具权限需要分开。代理拥有调用某个工具的资格,不等于它可以访问所有租户数据。工具服务器应根据租户、资源和操作类型进行服务端鉴权,并限制返回内容,避免把整张数据库表交给模型。

上下文与数据泄露

代理之间只传递完成任务所需的字段。原始邮件、身份证号、访问令牌和内部系统响应不应默认进入下一个代理的提示词。日志应对敏感字段脱敏,并记录调用者、工具名、参数摘要、结果状态、耗时和关联任务号。

常见问题

MCP 和 A2A 能否互相替代?

通常不能。MCP 侧重代理与工具、资源之间的能力调用,A2A 风格接口侧重代理之间的任务协作。项目可以只使用其中一种,但如果同时存在多代理和外部工具,分层会更容易管理。

为什么不直接让一个模型调用所有工具?

小型原型可以这样做,但工具数量、权限范围和失败路径增加后,单代理上下文会变得复杂。拆分代理不是越多越好,应依据权限边界、独立伸缩需求和故障隔离需求决定。每增加一个代理,也会增加网络、状态和调试成本。

模型输出 JSON 就足够可靠吗?

不够。必须使用 JSON 解析器、Schema 校验和业务规则校验。即使结构合法,也要检查资源是否存在、状态是否允许变更、数值是否在业务范围内。校验失败时,应返回可诊断的错误并设置重试或人工复核状态。

怎样判断系统是否真的可观测?

一次完整任务应能通过关联 ID串起代理调用、模型请求、工具执行和最终业务结果。至少记录成功率、失败类型、重试次数、等待时间、人工介入次数和未完成任务数量。不要只统计模型请求次数,因为那无法反映业务任务是否完成。

总结

多智能体系统的核心难点不在于增加更多代理,而在于定义清晰的协作契约和失败语义。用 MCP 约束工具发现与调用,用 A2A 风格任务接口管理代理间的生命周期,再配合幂等、鉴权、审批、状态持久化和可观测日志,才能把演示性质的智能体流程推进到可维护的工程系统。

落地时建议从一个低风险、可回放的任务开始:先固定输入输出 Schema,再实现只读工具,随后加入写操作和人工审批,最后根据真实失败类型设计重试与补偿。模型和接入服务只是链路中的一个可替换组件,协议、权限和业务状态才是系统长期稳定性的基础。

相关文章
|
5天前
|
存储 弹性计算 缓存
阿里云服务器租赁费用:新版租赁收费标准及活动报价参考
本文更新了2026年阿里云全系列云服务器租赁活动报价,所有特惠资源均可前往阿里云活动中心选购,整体覆盖从个人入门到企业级高性能场景的全梯度需求。其中轻量应用服务器主打极致性价比,2核2G峰值200M带宽配置每日10点、15点限时抢购价仅38元/年,2核4G配置379元/年起;高性价比的经济型e实例、通用算力型u2i实例覆盖2核4G至4核32G全档位,适配开发测试与中小型企业业务;搭载英特尔至强6处理器的第九代c9i企业级实例算力较上代提升20%,支撑高并发生产环境,不同实例规格价差清晰,用户可根据自身业务负载与预算灵活选型。
1572 112
|
12天前
|
云安全 人工智能 运维
阿里云联动百位企业安全专家,共识Agent防御最佳实践
当Agent成为新员工,你的安全边界在哪里?
1939 8
阿里云联动百位企业安全专家,共识Agent防御最佳实践
|
6天前
|
人工智能 程序员 API
Codex 接入 DeepSeek-V4-Flash:还能补上识图,提供两套方案
Codex 接入 DeepSeek-V4-Flash 怎么配?本文覆盖 CLI 与桌面端,再用 qwen3-vl-flash 补识图,两套方案可直接照做
|
6天前
|
编解码 人工智能 安全
2核4G/4核8G/8核16G阿里云服务器如何选择实例?经济型e、通用算力型u2i与计算型c9i选哪个?
本文介绍了阿里云2核4G、4核8G、8核16G三档主流配置下经济型e、通用算力型u2i和计算型c9i三种实例的最新活动价格与适用场景。同配置下三者价差显著,以2核4G为例,经济型e低至599.93元/年,计算型c9i则高达1742.08元/年。文章详细解析了各实例的性能定位:经济型e适合轻负载入门场景,u2i兼顾稳定算力与性价比,c9i凭借第9代至强处理器与芯片级安全能力支撑高性能业务。同时提示用户可叠加满减优惠券享受折上折,建议根据业务负载与预算综合决策。
526 112
|
18天前
|
人工智能 前端开发 Linux
Codex 桌面版安装 + CC Switch 接入第三方 API 完整教程(2026 最新)
2026最新教程:手把手教你安装Codex桌面版,通过CC Switch v3.17.0一键接入Fenno等国产API(兼容OpenAI Responses格式),跳过账号登录,完整启用代码审查、多步任务与上下文感知功能。零基础友好,全程图文实操。(239字)
2559 4
|
10天前
|
存储 人工智能 关系型数据库
阿里云AI产品与云产品最新组合套餐:Token Plan、AI coding及云服务器和建站等组合优惠价
阿里云推出全新“算力+模型+应用”一站式云与AI组合套餐活动,覆盖从个人开发者到中大型企业的全场景需求。核心亮点为分三档定价的Token Plan订阅服务,支持Qwen3.8-Max-Preview大模型调用,错峰时段最低可享0.2折优惠。活动同步推出AI Coding、智能体部署、云电脑托管、0代码建站等十余类场景化组合,搭配99元/年的普惠云服务器、88元/年的入门数据库等经典特惠产品,还为企业提供1V1定制化AI转型方案,大幅降低了不同用户群体拥抱AI的技术门槛与采购成本。
720 111
|
20天前
|
人工智能 JSON 安全
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
阿里云AI安全产品联动防御Fastjson攻击
2634 13
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
|
6天前
|
人工智能 JSON Shell
2026AI漫剧本地全开源方案(附各个软件模型链接),8G显卡也能流畅运行
这是一套完全本地化部署的AI漫剧生成技术链路:涵盖LLM剧本分镜生成、FLUX文生图(IP-Adapter人脸锁定)、StoryDiffusion时序连贯控制、LTX-2.3唇形同步视频生成,及ComfyUI全流程调度。零云端费用,仅耗硬件算力,单集2–4小时可产出竖屏短视频,适配抖音/B站分发。
|
7天前
Qoder 一周年 × Qwen3.8-Max 正式上线,多重好礼限时领
8月3日,Qwen3.8-Max 正式上线Qoder,迎来Qoder一周年。新老用户可领800次免费调用,下单再赠2000次;夜间(22:00–08:00)调用5折;邀请好友双方得积分与调用额度。
446 1

热门文章

最新文章