多Agent协作入门:基于A2A协议的Agent通信(中)

大家好,我是Edison。

上一篇,我们了解了A2A协议的基本概念,还通过A2A组件实现了一个Hello World的Demo,有了一个快速的感性认识。这一篇,我们来了解下A2A协议的三大角色、四大对象 以及 工作流程,有了这些基础的认知后会对我们全面认识A2A有所帮助。

A2A协议的三大角色

A2A 即 Agent-to-Agent,它定义了三个关键的角色,它们各司其职+互相配合,支撑多个Agent的运行。

那么,都是哪几个角色呢?下面告诉你:

角色1:用户(User)

即终端用户(可能是人类 或 服务),需要使用Agent来完成某个任务。

角色2:客户端(Client)

一个代表用户向 远程Agent 发送请求的实体,它发送的请求是严格按照A2A协议的。它的表现形式可以是一个应用程序、服务 或 一个Agent。

例如,我们在上一篇的Demo中开发的一个控制台应用程序通过引用A2A包来向远端的Agent发送请求。

角色3:远程Agent(Remote Agent)

一个执行实际任务的Agent(部署在某个远端Server上),对于客户端来说是"黑盒"一样的存在,仅仅通过Agent Card声明自己提供的接口或技能,但内部实现细节或工作机制是不透明的,即一个"黑盒"。

例如,我们在上一篇的Demo中开发的一个WebAPI项目EchoAgent,提供了一个ProcessMessage的技能 以及 声明了一个AgentCard公开了一些元数据。

A2A的四大对象

A2A中定义了一套完整的对象体系,其中最核心的就是下面这四个核心对象:

第一个对象:Agent Card (又称Agent名片)

每个A2A的远程Agent都需要发布一个JSON格式的名片,被称为"Agent Card",用于描述这个Agent具有哪些技能 及其 认证机制,便于Client可以获得这些信息并选择合适的Agent来完成任务。

其实,它就和我们在做后端服务开发中的服务注册和发现的机制差不多,只不过这个注册的信息被标准化了,下面我们可以看看一个典型的Agent Card的JSON格式:

复制代码
{
  "name": "Google Maps Agent",
  "description": "Plan routes, remember places, and generate directions",
  "url": "https://maps-agent.google.com",
  "provider": {
    "organization": "Google",
    "url": "https://google.com"
  },
  "version": "1.0.0",
  "authentication": {
    "schemes": "OAuth2"
  },
  "defaultInputModes": ["text/plain"],
  "defaultOutputModes": ["text/plain", "application/html"],
  "capabilities": {
    "streaming": true,
    "pushNotifications": false
  },
  "skills": [
    {
      "id": "route-planner",
      "name": "Route planning",
      "description": "Helps plan routing between two locations",
      "tags": ["maps", "routing", "navigation"],
      "examples": [
        "plan my route from Sunnyvale to Mountain View",
        "what's the commute time from Sunnyvale to San Francisco at 9AM"
      ],
      "outputModes": ["application/html", "video/mp4"]
    }
  ]
}

这个JSON数据简要描述了一个名为"Google Maps Agent"的Agent定义。这个Agent的主要功能是规划路线、记住地点和生成导航指示。这个应用由Google提供,版本号是1.0.0,采用OAuth2身份验证。它支持文本和HTML格式的输入和输出,具有流媒体功能,但不支持推送通知。它的一个核心技能是"route-planner",可以帮助用户规划两个地点之间的路线,并输出HTML和视频格式的内容。

在A2A .NET SDK中,AgentCard的定义如下:

复制代码
public class AgentCard
{
    public string Name { get; set; }                    // 代理名称

    public string Description { get; set; }            // 代理描述

    public string Url { get; set; }                     // 代理 URL

    public AgentProvider? Provider { get; set; }        // 提供商信息

    public string Version { get; set; }                 // 版本信息

    public AgentCapabilities Capabilities { get; set; } // 代理能力

    public List<AgentSkill> Skills { get; set; }        // 代理技能

    public List<string> DefaultInputModes { get; set; } // 默认输入模式

    public List<string> DefaultOutputModes { get; set; }// 默认输出模式
}

在上一篇的Demo中,我们在定义EchoAgent时,就实现了一个GetAgentCard方法,并将其注册到服务发现中最终被Client探索发现时就会以JSON格式输出给到Client:

复制代码
public class EchoAgent
{
    public void Attach(ITaskManager taskManager)
    {
        taskManager.OnMessageReceived = ProcessMessageAsync;
        taskManager.OnAgentCardQuery = GetAgentCardAsync;
    }
    private Task<Message> ProcessMessageAsync(MessageSendParams messageSendParams, CancellationToken cancellationToken)
    {
        ......
    }
    private Task<AgentCard> GetAgentCardAsync(string agentUrl, CancellationToken cancellationToken)
    {
        return Task.FromResult(new AgentCard
        {
            Name = "Echo Agent",
            Description = "Echoes messages back to the user",
            Url = agentUrl,
            Version = "1.0.0",
            DefaultInputModes = ["text"],
            DefaultOutputModes = ["text"],
            Capabilities = new AgentCapabilities { Streaming = true }
        });
    }
}

与此同时,在Client中也可以主动进行服务发现,例如上一篇Demo中的Client示例代码:

复制代码
// Discover agent and create client
var cardResolver = new A2ACardResolver(new Uri("https://localhost:7243/"));
var agentCard = await cardResolver.GetAgentCardAsync();
var client = new A2AClient(new Uri(agentCard.Url));

第二个对象:Task (任务)

Task 是 Client 和 远程Agent 之间协作的一个概念,很好理解,一个Task代表一个需要完成的任务,每个Task都有一个唯一的ID号,它通常包含了任务状态、历史记录 和 执行结果 等信息。

Task的主要具体状态有:submitted, working, completed, canceled, failed 等,下图展示了Task的状态机转换流。

在A2A .NET SDK中,AgentTask的定义如下:

复制代码
public class AgentTask : A2AResponse
{
    public string Id { get; set; }                      // 任务 ID
    public string? ContextId { get; set; }              // 上下文 ID
    public AgentTaskStatus Status { get; set; }         // 任务状态
    public List<Artifact>? Artifacts { get; set; }      // 任务产出物
    public List<Message>? History { get; set; }         // 消息历史
    public Dictionary<string, JsonElement>? Metadata { get; set; } // 元数据
}

第三个对象:Artifact(工件 或 成果)

Artifact 和我们在DevOps CI/CD流水线中的Artifact(即工件)的概念类似,它是 远程Agent执行完某个任务后生成输出的结果(即远程Agent返回的结果通过一个Artifact对象输出给Client),每个任务的结果可能都不一样。

一个Artifact可以包含多个部分(parts),每个部分(part)可以是:文本、文档、图像 等,涉及纯文本、文件 和 结构化数据。

第四个对象:Message(消息)

Message 也很好理解,它就是 Client 和 远程Agent 之间通信的 一个消息对象,它通常包含了 指令 和 状态更新 等内容。

同样的,一个Message对象也可以包含多个parts,用于传递如 文本、文件 或 结构化 等不同类型的内容。每个Message都有发送方设置的一个唯一的messageId,且通过一些关键词如"user"(代表Client发送的)或"agent"(代表服务端发送的)来区分角色。

在A2A .NET SDK中,Message的定义如下:

复制代码
public class Message : A2AResponse
{
    public MessageRole Role { get; set; }               // 消息角色 (User/Agent)
    public List<Part> Parts { get; set; }               // 消息部分
    public string? MessageId { get; set; }              // 消息 ID
    public string? TaskId { get; set; }                 // 关联任务 ID
    public string? ContextId { get; set; }              // 上下文 ID
    public Dictionary<string, JsonElement>? Metadata { get; set; } // 元数据
}

A2A协议的工作流程

这里我们来通过一个简单的例子看看A2A协议的 请求-响应 工作流程是怎么样的。

例如,有这样一个场景"招聘XX岗位候选人搜寻":

Step1 ,用户在统一界面下向Client(假设它也是一个Agent)发送一个请求消息"请帮我寻找一个XX岗位的候选人"。

Step2 ,Client将用户的请求消息进行封装,并根据岗位需求依次调用一些远程Agent如 简历检索Agent、技能筛选Agent 等等。

例如,下面的请求示例展示了Client在检索了5位候选人简历之后通过A2A协议向远端技能筛选Agent发送的任务请求:

复制代码
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tasks/send",
  "params": {
    "id": "de38c76d-d54c-436c-8b9f-4c2703648d64",
    "message": {
      "role": "user",
      "parts": [
        {
          "type": "text",
          "text": "请分析下面5位候选人是否符合岗位需求,并推荐最佳面试人选。"
        }
      ]
    },
    "metadata": {}
  }
}

Step3 ,各个远端Agent执行各自的任务,并返回给Client对应的Artifact对象结果(如候选人名单等),然后再由Client进行汇总和展示。

复制代码
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "id": "de38c76d-d54c-436c-8b9f-4c2703648d64",
    "sessionId": "c295ea44-7543-4f78-b524-7a38915ad6e4",
    "status": {
      "state": "completed"
    },
    "artifacts": [
      {
        "name": "result",
        "parts": [
          {
            "type": "text",
            "text": "第三位候选人最符合你的需求!建议安排面试。"
          }
        ]
      }
    ],
    "metadata": {}
  }
}

Step4 ,后续Client可以陆续调用其他远端Agent如 面试安排Agent、背景调查Agent等,完成端到端的自动化招聘流程。

那么,该场景的整个工作流程便如下图所示:

除此之外,实际应用案例中通常是A2A与MCP两个协议一起使用,形成更广的应用范围。

例如,下图展示了一个汽车维修店的场景,店长智能体 和 机械师智能体 通过A2A协议完成任务移交(hand-off),店长可以处理常见问题,但机械师可以解决技术难题。机械师智能体再通过MCP协议完成内部工具使用 完成具体任务,还可以通过A2A协议和零件供应商Agent完成外部协作

由此可见,其实在企业客服 或 售后中心 等场景中,A2A协议可以被广泛应用于多Agent协作。

小结

本文介绍了A2A的三个主要角色(User、Client 和 Remote Agent)以及 四个核心对象(Agent Card、Task、Artifact 和 Message),并通过简单的例子介绍了A2A协议的典型工作流程,相信对于你加深了解A2A协议会有帮助。

下一篇,我们将以一个旅行规划的应用场景,结合LLM大模型来实现一个A2A协议的案例,它会涉及一个Client 和 三个Remote Agent,是一个拿来练手的好案例。

参考资料

sing1ee:《2025年完整指南:A2A协议 - AI智能体协作的新标准

黄佳:《MCP & A2A前沿实战

圣杰:《.NET+AI | Semantic Kernel入门到精通


作者:爱迪生

出处:https://edisontalk.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

相关推荐
嘟嘟MD11 小时前
程序员副业 | 2025年9月复盘
后端·aigc
墨风如雪13 小时前
就它了!Claude Sonnet 4.5:AI编程与智能体的新王牌
aigc
墨风如雪13 小时前
AI视频革命奇点:Sora 2的数字幻境
aigc
Mintopia17 小时前
小样本学习在 WebAI 场景中的技术应用与局限
前端·人工智能·aigc
AI大模型19 小时前
斩获59.4K星!一款本地部署的开源私人知识库工具!
程序员·llm·agent
大模型教程19 小时前
GitHub 上 6 万人收藏!RAG 引擎让知识库活起来
程序员·llm·agent
Lululaurel2 天前
提示工程深度解析:驾驭大语言模型的艺术与科学
人工智能·ai·aigc·提示词
win4r2 天前
程序员福利!GitHub最火的Spec Kit项目深度解析:只需7条命令就能实现规格驱动开发,告别繁琐的PRD文档,让规范直接生成代码!支持Claude Cod
aigc·claude·vibecoding