返回顶部
热门问答 更多热门问答
技术文章 更多技术文章

详解A2A(Agent2Agent)协议

[复制链接]
链载Ai 显示全部楼层 发表于 9 小时前 |阅读模式 打印 上一主题 下一主题

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;display: table;padding-right: 0.2em;padding-left: 0.2em;color: rgb(255, 255, 255);background: rgb(15, 76, 129);">什么是 A2A 协议

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.1em;color: rgb(63, 63, 63);">A2A(Agent2Agent)协议 是由 Google Cloud 推出的一个开放协议,旨在促进不同 AI 代理之间的互操作性。其主要目标是允许这些代理在动态的、多代理的生态系统中进行有效的通信和协作,无论它们是由不同的供应商构建的还是使用不同的技术框架。

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;padding-left: 8px;color: rgb(63, 63, 63);">A2A 的设计原则总结

ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.1em;color: rgb(63, 63, 63);">A2A(Agent2Agent)协议的设计原则旨在提升代理之间的协作能力,确保灵活性、安全性和与现有系统的兼容性。以下是这些原则的综合总结:

    ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;color: rgb(63, 63, 63);" class="list-paddingleft-2">
  1. ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-indent: -1em;display: block;margin: 0.2em 8px;">

    1.ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: inherit;color: rgb(15, 76, 129);">拥抱代理能力

    ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;" class="list-paddingleft-1">
  • ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-indent: -1em;display: block;margin: 0.2em 8px;">

    • 允许代理在其自然、非结构化的模式下进行协作,无需共享内存、工具或上下文,从而实现真实的多代理场景。

  • ingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-indent: -1em;display: block;margin: 0.2em 8px;">

    2.基于现有标准构建

    • • 协议建立在广泛接受的技术标准之上,如 HTTP、SSE 和 JSON-RPC,便于与企业现有的 IT 堆栈集成。

  • 3.默认安全

    • • 设计支持企业级身份验证和授权,确保只有经过授权的用户和系统可以访问代理,增强了系统的安全性。

  • 4.支持长时间运行的任务

    • • 灵活支持从快速任务到复杂研究的多种场景,能够在任务执行过程中提供实时反馈、通知和状态更新。

  • 5.模态无关

    • • 支持多种交互形式,包括文本、音频和视频流、form 、 iframe 等,增强了代理的交互能力和适应性。

    整体看下来,协议在开放性、安全性、灵活性上考虑得比较多。这些点都是 MCP 有所不足的。和 MCP 的对比我们放在最后。先说正题——详解A2A

    A2A 的参与者

    A2A 协议有三个参与者:

    • • 用户(User):使用代理系统完成任务的用户(人类或服务)

    • • 客户端(Client):代表用户向不透明代理(服务、代理、应用程序)请求操作的实体。

    • • 服务端(Server):不透明(黑盒)的远程代理,即 A2A 服务器。

    参考如下的图

    通过上面的图,我们可以清晰地看到三个参与者的位置,对比之前 MCP 参与者,缺少一个 Host 的参与者。这个是设计思路上的不同,是要开放实现,还是规范一个机制,在 A2A 的实现中,安全等因素,已经通过别的方式实现,但确实User 如何发现需要的 Agent,是一个遗留的问题。

    A2A 核心概念

    AgentCard

    AgentCard 是一个 JSON 文件,描述了 Agent 提供了什么样的功能,官方建议托管在https:// base url /.well-known/agent.json
    这样就可以直接通过 HTTP GET 获取 AgentCard,得到有关 Agent 的描述。

    一个自然的引申是:需要注册表,无论是公开的、还是隐私的。这样方便查找 Agent 。

    但另一个方面,注册表也可以是去中心化的。我们想象这样一个场景:每一个网站都有一个https:// base url /.well-known/agent.json,描述了自己可以做什么,然后在一个 P2P 的网络中,不断的广播自己的 AgentCard ——甚至这些 AgentCard,可以放在 IPFS 、或者以太坊上,这样 Agent 的协作关系,就构成了一个自组织的 Agent 网络。

    回到 A2A,一个 AgentCard 的定义如下:

    //AnAgentCardconveyskeyinformation:
    //-Overalldetails(version,name,description,uses)
    //-Skills:Asetofcapabilitiestheagentcanperform
    //-Defaultmodalities/contenttypessupportedbytheagent.
    //-Authenticationrequirements
    interfaceAgentCard{
    //Humanreadablenameoftheagent.
    //(e.g."RecipeAgent")
    name:string;
    //Ahuman-readabledescriptionoftheagent.Usedtoassistusersand
    //otheragentsinunderstandingwhattheagentcando.
    //(e.g."Agentthathelpsuserswithrecipesandcooking.")
    description:string;
    //AURLtotheaddresstheagentishostedat.
    url:string;
    //Theserviceprovideroftheagent
    provider?:{
    organization:string;
    url:string;
    };
    //Theversionoftheagent-formatisuptotheprovider.(e.g."1.0.0")
    version:string;
    //AURLtodocumentationfortheagent.
    documentationUrl?:string;
    //Optionalcapabilitiessupportedbytheagent.
    capabilities:{
    streaming?:boolean;//trueiftheagentsupportsSSE
    pushNotifications?:boolean;//trueiftheagentcannotifyupdatestoclient
    stateTransitionHistory?:boolean;//trueiftheagentexposesstatuschangehistoryfortasks
    };
    //Authenticationrequirementsfortheagent.
    //IntendedtomatchOpenAPIauthenticationstructure.
    authentication:{
    schemes:string[];//e.g.Basic,Bearer
    credentials?:string;//credentialsaclientshoulduseforprivatecards
    };
    //Thesetofinteractionmodesthattheagent
    //supportsacrossallskills.Thiscanbeoverriddenper-skill.
    defaultInputModes:string[];//supportedmimetypesforinput
    defaultOutputModes:string[];//supportedmimetypesforoutput
    //Skillsareaunitofcapabilitythatanagentcanperform.
    skills:{
    id:string;//uniqueidentifierfortheagent'sskill
    name:string;//humanreadablenameoftheskill
    //descriptionoftheskill-willbeusedbytheclientorahuman
    //asahinttounderstandwhattheskilldoes.
    description:string;
    //Setoftagwordsdescribingclassesofcapabilitiesforthisspecific
    //skill(e.g."cooking","customersupport","billing")
    tags:string[];
    //Thesetofexamplescenariosthattheskillcanperform.
    //Willbeusedbytheclientasahinttounderstandhowtheskillcanbe
    //used.(e.g."Ineedarecipeforbread")
    examples?:string[];//examplepromptsfortasks
    //Thesetofinteractionmodesthattheskillsupports
    //(ifdifferentthanthedefault)
    inputModes?:string[];//supportedmimetypesforinput
    outputModes?:string[];//supportedmimetypesforoutput
    }[];
    }

    内容很长,但是比较简单,我们用下图来表示:

    完整的定义可以参考这里:https://github.com/sing1ee/a2a-agent-coder/blob/main/src/schema.ts

    Task(任务)

    任务是一个有状态的实体,允许客户端与远程代理协作以达成特定的结果并生成相应的输出。在任务内,客户端与远程代理之间会交换消息,远程代理则生成工件作为结果(代理即是 Agent)。

    任务始终由客户端创建,而其状态则由远程代理决定。如果客户端需要,多个任务可以归属于同一个会话(通过可选的 sessionId 表示)。在创建任务时,客户端可以设置这个可选的 sessionId。

    代理收到请求之后,可以采取以下几种行动:

    • • 立即满足请求

    • • 安排稍后执行的工作

    • • 拒绝请求

    • • 协商不同的执行方式

    • • 向客户端索要更多信息

    • • 委派给其他代理或系统

    即使在完成目标后,客户端仍然可以请求更多信息或在同一任务的上下文中进行更改。例如,客户端可以请求:“画一只兔子的图片”,代理回应:“<图片>”,随后客户端又可以要求:“把它画成红色”。

    任务不仅用于传递工件(结果)和消息(思考、指令等),还维护着任务的状态及其可选的历史记录,包括状态变化和消息记录。

    这些特性非常重要,尤其是同一个任务的上下文,可以进行多轮的对话,这些状态,还有历史记录,都有保存,这个非常匹配现在以 Chat 形式为主的AI 交互。

    任务的定义如下:

    interfaceTask{
    id:string;//uniqueidentifierforthetask
    sessionId:string;//client-generatedidforthesessionholdingthetask.
    status:TaskStatus;//currentstatusofthetask
    history?:Message[];
    artifacts?:Artifact[];//collectionofartifactscreatedbytheagent.
    metadata?:Record<string,any>;//extensionmetadata
    }
    //TaskStateandaccompanyingmessage.
    interfaceTaskStatus{
    state:TaskState;
    message?:Message;//additionalstatusupdatesforclient
    timestamp?:string;//ISOdatetimevalue
    }
    //sentbyserverduringsendSubscribeorsubscriberequests
    interfaceTaskStatusUpdateEvent{
    id:string;
    status:TaskStatus;
    final:boolean;//indicatestheendoftheeventstream
    metadata?:Record<string,any>;
    }
    //sentbyserverduringsendSubscribeorsubscriberequests
    interfaceTaskArtifactUpdateEvent{
    id:string;
    artifact:Artifact;
    metadata?:Record<string,any>;
    }
    //Sentbytheclienttotheagenttocreate,continue,orrestartatask.
    interfaceTaskSendParams{
    id:string;
    sessionId?:string;//servercreatesanewsessionIdfornewtasksifnotset
    message:Message;
    historyLength?:number;//numberofrecentmessagestoberetrieved
    //wheretheservershouldsendnotificationswhendisconnected.
    pushNotification?ushNotificationConfig;
    metadata?:Record<string,any>;//extensionmetadata
    }
    typeTaskState=
    |"submitted"
    |"working"
    |"input-required"
    |"completed"
    |"canceled"
    |"failed"
    |"unknown";

    Artifact(工件)

    工件是代理作为任务最终结果生成的输出。工件具有不可变性,可以被命名,并且可以包含多个部分。通过流式响应,可以将新部分附加到现有的工件中。

    一个任务可以生成多个工件。例如,当执行“创建一个网页”时,可能会产生单独的 HTML 工件和图像工件。

    不得不说 A2A 出现的时机很准确,现在 AI 的一些主要的应用的形式,在协议定义上都包括了。Artifact就是很火的一个形式。

    具体的定义:

    interfaceArtifact{
    name?:string;
    description?:string;
    partsart[];
    metadata?:Record<string,any>;
    index:number;
    append?:boolean;
    lastChunk?:boolean;
    }

    Message(消息)

    消息是包含任何非工件内容的实体。这些内容可以包括代理的思考、用户的上下文、指令、错误信息、状态更新或元数据。

    所有来自客户端的内容均以消息的形式发送。代理通过消息来传达状态或提供指令,而生成的结果则以工件的形式发送。

    消息可以包含多个Part(片段),以表示不同类型的内容。例如,一个用户请求可能包括用户的文本描述以及多个用于上下文的文件。

    定义如下:

    interfaceMessage{
    role:"user"|"agent";
    partsart[];
    metadata?:Record<string,any>;
    }

    Part(片段)

    Part是客户端与远程代理之间作为消息或工件一部分交换的完整内容。每个Part都有其独特的内容类型和元数据。

    以下是不同类型部分的接口定义:

    文本部分(TextPart)

    interfaceTextPart{
    type:"text";
    text:string;
    }

    文件部分(FilePart)

    interfaceFilePart{
    type:"file";
    file:{
    name?:string;
    mimeType?:string;
    //可能的内容
    //oneof{
    bytes?:string;//base64编码的内容
    uri?:string;
    //}
    };
    }

    数据部分(DataPart)

    interfaceDataPart{
    type:"data";
    data:Record<string,any>;
    }

    综合类型

    typePart=(TextPart|FilePart|DataPart)&{
    metadata:Record<string,any>;
    };

    更多的消息的细节,参考链接:https://a2aprotocol.ai/blog/a2a-sample-methods-and-json-responses

    通信机制与异步支持

    A2A 支持以下的通信机制:

    • • A2A 支持安全的推送通知机制,允许代理在不连接的情况下向客户端发送更新。

    • • 客户端和服务器可以使用标准请求/响应模式,也可以通过 SSE 进行流式更新。

    在推送通知时,代理需要验证通知服务的身份,并使用受信任的凭证进行身份验证,以确保通知的安全性。
    基于以上的通信机制,A2A 支持客户端在处理长时间运行的任务时进行轮询,代理也可以通过 SSE 向客户端推送状态更新。

    这里,最重要的是异步的支持,client 可以通过类似注册一个 webhook,异步的获取长时间运行任务的结果——就是PushNotification 相关的实现。目前大家在使用 LLMs API 的时候,都会遇到一个问题,就是输出太慢了,而且输出的过程中,并不能做别的事情。如果有了异步的回调,或者轮询、重新订阅,那么就可以在 client 的开发上,更加灵活,可以给用户带来更好的体验。

    以下是推送的定义:

    interfacePushNotificationConfig{
    url:string;
    token?:string;//tokenuniquetothistask/session
    authentication?:{
    schemes:string[];
    credentials?:string;
    };
    }
    interfaceTaskPushNotificationConfig{
    id:string;//taskid
    pushNotificationConfigushNotificationConfig;
    }

    错误处理(Error Handling)

    错误消息格式

    以下是服务器在处理客户端请求时遇到错误时响应客户端的ErrorMessage格式:

    interfaceErrorMessage{
    code:number;
    message:string;
    data?:any;
    }

    标准 JSON-RPC 错误代码

    以下为服务器在错误场景中可以响应的标准 JSON-RPC 错误代码:

    错误代码信息描述
    -32700JSON parse error无效的 JSON 被发送
    -32600Invalid Request请求负载验证错误
    -32601Method not found非法方法
    -32602Invalid params无效的方法参数
    -32603Internal error内部 JSON-RPC 错误
    -32000 to -32099Server error保留供实现特定错误代码使用
    -32001Task not found找不到提供的 ID 的任务
    -32002Task cannot be canceled无法由远程代理取消任务
    -32003Push notifications not supported推送通知由代理不支持
    -32004Unsupported operation操作不支持
    -32005Incompatible content types客户端与代理之间的内容类型不兼容

    动手实践

    我把官方的 ts 的示例进行了修改,支持了 OpenRouter,主要是改动了兼容 OpenAI 的 API 形式。代码在这里:https://github.com/sing1ee/a2a-agent-coder

    我是在 Mac 环境下进行的,打开你最爱的终端:

    1. 1. 安装 Bun

    brewinstalloven-sh/bun/bun#针对macOS和Linux
    1. 2. 克隆仓库

    gitclonegit@github.com:sing1ee/a2a-agent-coder.git
    1. 3. 安装依赖

    cda2a-agent-coder
    buni
    1. 4. 配置环境变量
      参考***.env.example创建一个.env***文件,内容如下:

    OPENAI_API_KEY=sk-or-v1-xxxxxxx
    OPENAI_BASE_URL=https://openrouter.ai/api/v1
    OPENAI_MODEL=anthropic/claude-3.5-haiku

    我用的是 OpenRouter,支付方便,模型众多。大家尝试的话,可以注册一个 OpenRouter,即使没有充值,可以有每天 50 次免费模型的额度,例如deepseek/deepseek-chat-v3-0324:free
    让环境变量生效

    export$(cat.env|xargs)
    1. 5. 运行 A2A Server

    bunrunagents:coder
    1. 6. 再打开一个新的终端,运行 A2A Client,这里不需要配置 env

    bunruna2a:cli

    以下是我之前运行的结果:

    bunruna2a:cli

    #result
    $bunxtsxsrc/cli.ts
    A2ATerminalClient
    AgentURL:http://localhost:41241
    Attemptingtofetchagentcardfrom:http://localhost:41241/.well-known/agent.json
    ✓AgentCardFound:
    Name:CoderAgent
    Description:Anagentthatgeneratescodebasedonnaturallanguageinstructionsandstreamsfileoutputs.
    Version:0.0.1
    StartingTaskID:a1a608b3-3015-4404-a83f-6ccc05083761
    Entermessages,oruse'/new'tostartanewtask.
    CoderAgent>You:implementbinarysearch
    Sending...

    CoderAgent[4:28:00PM]:⏳Status:working
    Part1:?Text:Generatingcode...

    CoderAgent[4:28:02PM]:⏳Status:working
    Part1:?File:Name:src/algorithms/binary_search.py,Source:"""
    ImplementationofthebinarysearchalgorithminPython.
    """

    defbinary_search(arr,target):
    """
    Performsabinarysearchonasortedarraytofindtheindexofatargetvalue.

    Args:
    arr(list):Asortedlistofelements.
    target:Thevaluetosearchforinthearray.

    Returns:
    int:Theindexofthetargetvalueiffound,otherwise-1.
    """
    low=0
    high=len(arr)-1

    whilelow<=high:
    mid=(low+high)//2#Integerdivisiontofindthemiddleindex

    ifarr[mid]==target:
    returnmid#Targetfoundatindexmid
    elifarr[mid]<target:
    low=mid+1#Targetisintherighthalf
    else:
    high=mid-1#Targetisinthelefthalf

    return-1#Targetnotfoundinthearray


    CoderAgent[4:28:02PM]:✅Status:completed
    SSEstreamfinishedformethodtasks/sendSubscribe.
    ---Endofresponseforthisinput---
    CoderAgent>You:
    Exitingterminalclient.Goodbye!

    运行过程的流程图如下:

    目前非程序员用户想体验,还需要耐心等待,也可以借助 Cursor 等试一试。

    A2A 与 MCP 比较

    这个问题,很多人关心,我大概做了一个总结:

    特性A2AMCP
    主要用途代理间通信和协作为模型提供工具和上下文,连接外部资源
    核心架构客户端-服务器(代理-代理)客户端-主机-服务器(应用-LLM-外部资源)
    标准接口JSON 规范、代理卡、任务、消息、工件JSON-RPC 2.0、资源、工具、记忆、提示
    关键特性多模态、动态协作、安全性、任务管理、能力发现模块化、安全边界、可重用连接器、SDK、工具发现
    通信协议HTTP, JSON-RPC, SSEJSON-RPC 2.0 over stdio, HTTP with SSE
    性能重点异步通信,处理负载高效上下文管理、并行处理、缓存以提高吞吐量
    采用与社区初期行业支持良好,新兴生态系统行业广泛采用,社区快速增长

    同时,我也在做一些思考,

    • • 我们要如何区分 Agent 和 Tools?真的有绝对的边界么?

    • • 目前从技术上看,A2A 适应的场景更多,包括了 MCP 的场景

    • • 如果未来 Agent 很多,以及 MCP server 很多,会构成一个什么样的网络呢?前者更倾向于去中心化的,后者更倾向于中心化的。前者更倾向于分散自治,后者是集中的管理。

    都在思考中,需要更多的实践。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

链载AI是专业的生成式人工智能教程平台。提供Stable Diffusion、Midjourney AI绘画教程,Suno AI音乐生成指南,以及Runway、Pika等AI视频制作与动画生成实战案例。从提示词编写到参数调整,手把手助您从入门到精通。
  • 官方手机版

  • 微信公众号

  • 商务合作

  • Powered by Discuz! X3.5 | Copyright © 2025-2025. | 链载Ai
  • 桂ICP备2024021734号 | 营业执照 | |广西笔趣文化传媒有限公司|| QQ